class Bixby::WebSocket::APIChannel

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.

Attributes

ws[R]

Public Class Methods

new(ws, handler, thread_pool) click to toggle source
# 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

Public Instance Methods

close(event) click to toggle source

Close

Can be fired either due to disconnection or failure to connect

# 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?() click to toggle source

Handle channel events

# File lib/bixby-common/websocket/api_channel.rb, line 73
def connected?
  @connected
end
execute(json_request) click to toggle source

Execute the given request (synchronously)

@param [JsonRequest] json_request

@return [JsonResponse] response

# 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) click to toggle source

Execute the given request (asynchronously)

@param [JsonRequest] json_request

@return [String] request id

# 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) click to toggle source

Fetch the response for the given request

@param [String] request id

@return [JsonResponse]

# 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) click to toggle source

Message

Fired whenever a message is received on the channel

# 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) click to toggle source

Open

# 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