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

new(socket) click to toggle source

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

dispatch_event(name, message) click to toggle source
# File lib/vici.rb, line 282
def dispatch_event(name, message)
  @events[name].each do |handler|
    handler.call(name, message)
  end
end
read() click to toggle source

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
read_and_dispatch_event() click to toggle source
# 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
read_and_dispatch_events() click to toggle source
# 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
recv_all(len) click to toggle source

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(name, handler) click to toggle source

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
request(name, message = nil) click to toggle source

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_all(encoding) click to toggle source

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(name, handler) click to toggle source

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(type, label, message) click to toggle source

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