class Vici::Transport
The Transport
class implements to low level segmentation of packets to the underlying transport stream. Directly using this class is usually not required.
Constants
- CMD_REQUEST
- CMD_RESPONSE
- CMD_UNKNOWN
- EVENT
- EVENT_CONFIRM
- EVENT_REGISTER
- EVENT_UNKNOWN
- EVENT_UNREGISTER
Public Class Methods
Create a transport layer using a provided socket for communication.
# File lib/vici.rb, line 223 def initialize(socket) @socket = socket @events = {} end
Public Instance Methods
# File lib/vici.rb, line 282 def dispatch_event(name, message) @events[name].each do |handler| handler.call(name, message) end end
Read a packet from the transport socket. Returns the packet type, and if available in the packet a label and the contained message.
# File lib/vici.rb, line 260 def read len = recv_all(4).unpack("N")[0] encoding = recv_all(len) type = encoding.unpack("c")[0] len = 1 case type when CMD_REQUEST, EVENT_REGISTER, EVENT_UNREGISTER, EVENT label = encoding[2, encoding[1].unpack("c")[0]] len += label.length + 1 when CMD_RESPONSE, CMD_UNKNOWN, EVENT_CONFIRM, EVENT_UNKNOWN label = nil else raise TransportError, "invalid message: #{type}" end message = if encoding.length == len Message.new else Message.new(encoding[len..-1]) end [type, label, message] end
# File lib/vici.rb, line 288 def read_and_dispatch_event type, label, message = read raise TransportError, "unexpected message: #{type}" if type != EVENT dispatch_event(label, message) end
# File lib/vici.rb, line 295 def read_and_dispatch_events loop do type, label, message = read return type, label, message if type != EVENT dispatch_event(label, message) end end
Receive data from socket, until len bytes read
# File lib/vici.rb, line 230 def recv_all(len) encoding = "" while encoding.length < len data = @socket.recv(len - encoding.length) raise TransportError, "connection closed" if data.empty? encoding << data end encoding end
Register a handler method for the given event name
# File lib/vici.rb, line 322 def register(name, handler) write(EVENT_REGISTER, name, nil) type, _label, _message = read_and_dispatch_events case type when EVENT_CONFIRM if @events.key?(name) @events[name] += [handler] else @events[name] = [handler] end when EVENT_UNKNOWN raise EventUnknownError, name else raise EventError, "invalid response for #{name} register" end end
Send a command with a given name, and optionally a message. Returns the reply message on success.
# File lib/vici.rb, line 307 def request(name, message = nil) write(CMD_REQUEST, name, message) type, _label, message = read_and_dispatch_events case type when CMD_RESPONSE return message when CMD_UNKNOWN raise CommandUnknownError, name else raise CommandError, "invalid response for #{name}" end end
Send data to socket, until all bytes sent
# File lib/vici.rb, line 242 def send_all(encoding) len = 0 len += @socket.send(encoding[len..-1], 0) while len < encoding.length end
Unregister a handler method for the given event name
# File lib/vici.rb, line 341 def unregister(name, handler) write(EVENT_UNREGISTER, name, nil) type, _label, _message = read_and_dispatch_events case type when EVENT_CONFIRM @events[name] -= [handler] when EVENT_UNKNOWN raise EventUnknownError, name else raise EventError, "invalid response for #{name} unregister" end end
Write a packet prefixed by its length over the transport socket. Type specifies the message, the optional label and message get appended.
# File lib/vici.rb, line 250 def write(type, label, message) encoding = "" encoding << label.length << label if label encoding << message.encoding if message send_all([encoding.length + 1, type].pack("Nc") + encoding) end