module Nova::Starbound::Protocol::Socket

Handles sending data on the socket.

Attributes

current_packet_id[R]

The current packet id.

@return [Numeric]

queue[R]

The queue that holds messages.

@return [Queue]

socket[RW]

The socket to write data to.

@return [#read, write]

Public Class Methods

new() click to toggle source

Initializes the socket.

# File lib/nova/starbound/protocol/socket.rb, line 105
def initialize
  @threaded = @options.fetch(:threaded, true)
  @run = true
  @queue = Queue.new
  @read  = []
  @current_packet_id = 0
end

Public Instance Methods

callbacks() click to toggle source

The callbacks that have been defined on this protocol.

@return [Hash<Symbol, Object>] the symbol is the type of

packet.
# File lib/nova/starbound/protocol/socket.rb, line 149
def callbacks
  @_callbacks ||= Hash.new { |h, k| h[k] = [] }
end
close() click to toggle source

Closes down the socket.

@return [void]

# File lib/nova/starbound/protocol/socket.rb, line 198
def close
  @run = false

  socket.close
end
loop() click to toggle source

Keep looping until we stop running. Reads packets continuously until we do stop.

@return [void]

# File lib/nova/starbound/protocol/socket.rb, line 170
def loop
  while run?
    read
  end
end
on(data, &block) click to toggle source

Stores callbacks for when packets arrive.

@param data [Hash<(Symbol, Symbol)>] should consist of only

one key-value pair, with the key being the struct that
represents the packet, and the type being the type of
packet.

@yieldparam packet [Packet] the packet.

# File lib/nova/starbound/protocol/socket.rb, line 137
def on(data, &block)
  struct = data.keys.first
  type   = data.values.first

  callbacks[type].push :struct => struct,
    :type => type, :block => block
end
read(read_check = true) click to toggle source

Waits for a packet and returns it. If it’s threaded, or if there’s data in the queue, it waits for a message in the queue and pops off the top one. If it’s not, it just reads from the socket.

@raise [RemoteClosedError] if it recieves a :close packet. @param read_check [Boolean] whether or not to check the read

list for the packet.

@return [Packet]

# File lib/nova/starbound/protocol/socket.rb, line 73
def read(read_check = true)
  pack = if @read.length > 0 && read_check
    @read.pop
  elsif threaded?
    queue.pop
  else
    wait_for_socket
  end

  if pack && pack.type == :close
    raise RemoteClosedError
  end

  pack
end
respond_to(packet, type, body, others = {}) click to toggle source

Sends out a response packet with the given type and body.

@param packet [Packet] the packet to respond to. @param type [Symbol] the packet tpye of this packet. See

{Packet::Type} for a list of packet types.

@param body [String] the body of this packet. @param others [Hash] the other data to pass to the packet. @return [Packet] the sent packet.

# File lib/nova/starbound/protocol/socket.rb, line 46
def respond_to(packet, type, body, others = {})
  write_packet Packet.build_response(type, body, packet,
    others)
end
response_to(packet) click to toggle source

Finds the response to the given packet.

@param packet [Packet] @return [nil, Packet] nil if it was told to stop running

before it could find a response.
# File lib/nova/starbound/protocol/socket.rb, line 181
def response_to(packet)
  response = nil

  while response.nil? && run?
    temp = read(false)

    if temp.struct == :response && temp.response_id == packet.id
      response = temp
    end
  end

  response
end
run?() click to toggle source

Whether or not this is actually running.

@return [Boolean]

# File lib/nova/starbound/protocol/socket.rb, line 100
def run?
  @run
end
run_callback(struct, type, *args) click to toggle source

Runs a callback. Automatically called by wait_for_socket.

@param struct [Symbol] the struct that the callback is for. @param type [Symbol] the type of callback this is for. @return [Array<Object>] all of the results from running the

callbacks.
# File lib/nova/starbound/protocol/socket.rb, line 159
def run_callback(struct, type, *args)
  callbacks[type].select { |c|
    c[:struct] == struct }.map do |c|
    c[:block].call(*args)
  end
end
send(packet_type, body, others = {}) click to toggle source

Sends out a regular packet with the given type and body.

@param packet_type [Symbol] the packet type of this packet.

See {Packet::Type} for a list of packet types.

@param body [String] the body of the packet. @param others [Hash] other data to pass to the packet. @return [Packet] the sent packet.

# File lib/nova/starbound/protocol/socket.rb, line 32
def send(packet_type, body, others = {})
  others = others.merge(:packet_id => current_packet_id)
  @current_packet_id += 1
  write_packet Packet.build(packet_type, body, others)
end
thread() click to toggle source

The thread that is filling the queue with packet data. If it doesn’t exist, it creates one, if this is threaded.

@return [nil, Thread] nil if this is not threaded, Thread

otherwise.
# File lib/nova/starbound/protocol/socket.rb, line 118
def thread
  return unless threaded?

  @_thread ||= Thread.start do
    while run?
      packet = wait_for_socket

      queue << packet
    end
  end
end
threaded?() click to toggle source

Returns whether or not this instance of the protocol uses threads to handle reading.

@return [Boolean]

# File lib/nova/starbound/protocol/socket.rb, line 93
def threaded?
  @threaded
end
write_packet(packet) click to toggle source

Writes the given packet to the socket, after handling the encryption of the packet.

@return [Packet] the sent packet.

# File lib/nova/starbound/protocol/socket.rb, line 55
def write_packet(packet)
  new_packet = encryption_provider.encrypt(packet)

  socket.write new_packet
  socket.flush

  new_packet
end

Private Instance Methods

wait_for_socket() click to toggle source

Blocks the thread until data is available, or this is signaled to stop running.

@return [nil, Packet] nil when it was told to stop running

before data was given, Packet otherwise.
# File lib/nova/starbound/protocol/socket.rb, line 211
def wait_for_socket
  packet = nil

  while packet.nil? && run?

    out = IO.select [socket], nil, nil, 0.1
    next unless out

    packet = encryption_provider.decrypt(
      Packet.from_socket(socket))

    run_callback packet.struct, packet.type, 
      packet, self unless state == :handshake
  end

  packet
end