Class: Bixby::WebSocket::APIChannel

Inherits:
APIChannel show all
Defined in:
lib/bixby-common/websocket/api_channel.rb

Overview

WebSocket API channel

Implements a simple request/response interface over a WebSocket channel. Requests can be sent in either direction, in a sync or async manner.

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Log

bin_regex, clean_ex, clean_ex_for_console, console_appender?, gems_regex, #log, ruby_regex, setup_logger

Constructor Details

#initialize(ws, handler, thread_pool) ⇒ APIChannel

Returns a new instance of APIChannel.



18
19
20
21
22
23
24
# File 'lib/bixby-common/websocket/api_channel.rb', line 18

def initialize(ws, handler, thread_pool)
  @ws = ws
  @handler = handler
  @responses = {}
  @connected = false
  @thread_pool = thread_pool
end

Instance Attribute Details

#wsObject (readonly)

Returns the value of attribute ws.



16
17
18
# File 'lib/bixby-common/websocket/api_channel.rb', line 16

def ws
  @ws
end

Instance Method Details

#close(event) ⇒ Object

Close

Can be fired either due to disconnection or failure to connect



88
89
90
91
92
93
94
95
96
# File 'lib/bixby-common/websocket/api_channel.rb', line 88

def close(event)
  if event && !event.target.kind_of?(Faye::WebSocket::Client) then
    logger.debug { "closed connection from #{event.target.env["REMOTE_ADDR"]} (code=#{event.code}; reason=\"#{event.reason}\")" }
  end
  if @connected then
    @connected = false
    @handler.new(nil).disconnect(self)
  end
end

#connected?Boolean

Handle channel events

Returns:

  • (Boolean)


73
74
75
# File 'lib/bixby-common/websocket/api_channel.rb', line 73

def connected?
  @connected
end

#execute(json_request) ⇒ JsonResponse

Execute the given request (synchronously)

Parameters:

Returns:



33
34
35
# File 'lib/bixby-common/websocket/api_channel.rb', line 33

def execute(json_request)
  fetch_response( execute_async(json_request) )
end

#execute_async(json_request, &block) ⇒ String

Execute the given request (asynchronously)

Parameters:

Returns:

  • (String)

    request id



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/bixby-common/websocket/api_channel.rb', line 42

def execute_async(json_request, &block)
  if json_request.kind_of? Request then
    id, request = json_request.id, json_request
  else
    request = Request.new(json_request)
    id = request.id
  end
  @responses[id] = AsyncResponse.new(id, &block)

  logger.debug { request.type == "connect" ? "execute_async: CONNECT [#{id}]" : "execute_async: RPC [#{id}]\n#{request.to_s}" }

  EM.next_tick {
    ws.send(request.to_wire)
  }
  id
end

#fetch_response(id) ⇒ JsonResponse

Fetch the response for the given request

Parameters:

  • request (String)

    id

Returns:



64
65
66
67
68
# File 'lib/bixby-common/websocket/api_channel.rb', line 64

def fetch_response(id)
  res = @responses[id].response
  @responses.delete(id)
  res
end

#message(event) ⇒ Object

Message

Fired whenever a message is received on the channel



101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/bixby-common/websocket/api_channel.rb', line 101

def message(event)
  req = Message.from_wire(event.data)

  if req.type == "rpc" then
    # Execute the requested method and return the result
    # Do it asynchronously so as not to hold up the EM-loop while the command is running
    @thread_pool.perform do
      json_req = req.json_request
      logger.debug { "RPC request\n#{json_req}" }
      json_response = @handler.new(req).handle(json_req)
      EM.next_tick { ws.send(Response.new(json_response, req.id).to_wire) }
    end

  elsif req.type == "rpc_result" then
    # Pass the result back to the caller
    res = req.json_response
    logger.debug { "RPC_RESULT for request id [#{req.id}]\n#{res}" }
    @responses[req.id].response = res

  elsif req.type == "connect" then
    # Agent request to CONNECT to the manager
    # will only be received by the server-end of the channel
    logger.debug { "CONNECT request #{req.id}"}
    ret = @handler.new(req).connect(req.json_request, self)
    if ret.kind_of? JsonResponse then
      ws.send(Response.new(ret, req.id).to_wire)
    else
      ws.send(Response.new(JsonResponse.new("success"), req.id).to_wire)
    end

  end
end

#open(event) ⇒ Object

Open



78
79
80
81
82
83
# File 'lib/bixby-common/websocket/api_channel.rb', line 78

def open(event)
  if event && !event.target.kind_of?(Faye::WebSocket::Client) then
    logger.debug { "opened connection from #{event.target.env["REMOTE_ADDR"]}" }
  end
  @connected = true
end