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

#log, setup_logger

Constructor Details

#initialize(ws, handler, thread_pool) ⇒ 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



85
86
87
88
89
90
# File 'lib/bixby-common/websocket/api_channel.rb', line 85

def close(event)
  if @connected then
    @connected = false
    @handler.new(nil).disconnect(self)
  end
end

#connected?Boolean

Handle channel events



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)



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)



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



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



95
96
97
98
99
100
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
# File 'lib/bixby-common/websocket/api_channel.rb', line 95

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
# File 'lib/bixby-common/websocket/api_channel.rb', line 78

def open(event)
  @connected = true
end