Class: OpenC3::WebSocketApi

Inherits:
Object show all
Defined in:
lib/openc3/script/web_socket_api.rb

Overview

Base class - Do not use directly

Direct Known Subclasses

CmdTlmWebSocketApi, ScriptWebSocketApi

Constant Summary collapse

USER_AGENT =
'OpenC3 / v5 (ruby/openc3/lib/io/web_socket_api)'.freeze

Instance Method Summary collapse

Constructor Details

#initialize(url:, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope, &block) ⇒ WebSocketApi

Create the WebsocketApi object. If a block is given will automatically connect/disconnect



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/openc3/script/web_socket_api.rb', line 29

def initialize(url:, write_timeout: 10.0, read_timeout: 10.0, connect_timeout: 5.0, authentication: nil, scope: $openc3_scope, &block)
  @scope = scope
  @authentication = authentication.nil? ? generate_auth() : authentication
  @url = url
  @write_timeout = write_timeout
  @read_timeout = read_timeout
  @connect_timeout = connect_timeout
  @subscribed = false
  if block_given?
    begin
      connect()
      yield self
    ensure
      disconnect()
    end
  end
end

Instance Method Details

#connectObject

Connect to the websocket with authorization in query params



127
128
129
130
131
132
133
134
135
136
# File 'lib/openc3/script/web_socket_api.rb', line 127

def connect
  disconnect()
  final_url = @url + "?scope=#{@scope}&authorization=#{@authentication.token}"
  @stream = WebSocketClientStream.new(final_url, @write_timeout, @read_timeout, @connect_timeout)
  @stream.headers = {
    'Sec-WebSocket-Protocol' => 'actioncable-v1-json, actioncable-unsupported',
    'User-Agent' => USER_AGENT
  }
  @stream.connect
end

#connected?Boolean

Are we connected?

Returns:

  • (Boolean)


139
140
141
142
143
144
145
# File 'lib/openc3/script/web_socket_api.rb', line 139

def connected?
  if @stream
    @stream.connected?
  else
    false
  end
end

#disconnectObject

Disconnect from the websocket and attempt to send unsubscribe message



148
149
150
151
152
153
154
155
156
157
# File 'lib/openc3/script/web_socket_api.rb', line 148

def disconnect
  if connected?()
    begin
      unsubscribe()
    rescue
      # Oh well, we tried
    end
    @stream.disconnect
  end
end

#generate_authObject

Generate the appropriate token for OpenC3



162
163
164
165
166
167
168
169
170
171
172
# File 'lib/openc3/script/web_socket_api.rb', line 162

def generate_auth
  if ENV['OPENC3_API_TOKEN'].nil? and ENV['OPENC3_API_USER'].nil?
    if ENV['OPENC3_API_PASSWORD']
      return OpenC3Authentication.new()
    else
      raise "Environment Variables Not Set for Authentication"
    end
  else
    return OpenC3KeycloakAuthentication.new(ENV['OPENC3_KEYCLOAK_URL'])
  end
end

#read(ignore_protocol_messages: true, timeout: nil) ⇒ Object

Read the next message with json parsing, filtering, and timeout support



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/openc3/script/web_socket_api.rb', line 54

def read(ignore_protocol_messages: true, timeout: nil)
  start_time = Time.now
  while true
    message = read_message()
    if message
      json_hash = JSON.parse(message, allow_nan: true, create_additions: true)
      if ignore_protocol_messages
        type = json_hash['type']
        if type # ping, welcome, confirm_subscription, reject_subscription, disconnect
          if type == 'disconnect'
            if json_hash['reason'] == 'unauthorized'
              raise "Unauthorized"
            end
          end
          if type == 'reject_subscription'
            raise "Subscription Rejected"
          end
          if timeout
            end_time = Time.now
            if (start_time - end_time) > timeout
              raise Timeout::Error, "No Data Timeout"
            end
          end
          if defined? RunningScript and RunningScript.instance
            raise StopScript if RunningScript.instance.stop?
          end
          next
        end
      end
      return json_hash['message']
    end
    return message
  end
end

#read_messageObject

Read the next message without filtering / parsing



48
49
50
51
# File 'lib/openc3/script/web_socket_api.rb', line 48

def read_message
  subscribe()
  return @stream.read
end

#subscribeObject

Will subscribe to the channel based on @identifier



90
91
92
93
94
95
96
97
98
# File 'lib/openc3/script/web_socket_api.rb', line 90

def subscribe
  unless @subscribed
    json_hash = {}
    json_hash['command'] = 'subscribe'
    json_hash['identifier'] = JSON.generate(@identifier)
    @stream.write(JSON.generate(json_hash))
    @subscribed = true
  end
end

#unsubscribeObject

Will unsubscribe to the channel based on @identifier



101
102
103
104
105
106
107
108
109
# File 'lib/openc3/script/web_socket_api.rb', line 101

def unsubscribe
  if @subscribed
    json_hash = {}
    json_hash['command'] = 'unsubscribe'
    json_hash['identifier'] = JSON.generate(@identifier)
    @stream.write(JSON.generate(json_hash))
    @subscribed = false
  end
end

#write(data) ⇒ Object

General write to the websocket



121
122
123
124
# File 'lib/openc3/script/web_socket_api.rb', line 121

def write(data)
  subscribe()
  @stream.write(data)
end

#write_action(data_hash) ⇒ Object

Send an ActionCable command



112
113
114
115
116
117
118
# File 'lib/openc3/script/web_socket_api.rb', line 112

def write_action(data_hash)
  json_hash = {}
  json_hash['command'] = 'message'
  json_hash['identifier'] = JSON.generate(@identifier)
  json_hash['data'] = JSON.generate(data_hash)
  write(JSON.generate(json_hash))
end