Class: Nova::Starbound::Protocol::Packet

Inherits:
Object
  • Object
show all
Extended by:
PackedStruct
Defined in:
lib/nova/starbound/protocol/packet.rb

Overview

Handles serialization and deserialization of packets.

API:

  • public

Constant Summary collapse

Type =

A list of the types of packets in existance, and their packet_type codes.

API:

  • public

{
  :nul => 0x00,

  # handshake
  :protocol_version   => 0x01,
  :encryption_options => 0x02,
  :public_key         => 0x03,

  # other stuff
  :standard_error     => 0x04,
  :close              => 0x05,

  # content
  :echo               => 0x06,
  :password           => 0x07,
  :star_run           => 0x08
}.freeze
Structs =

Used internally to check the types of packets when unpacking.

API:

  • public

{
  :packet   => 0x00,
  :response => 0x01
}.freeze
CloseReasons =

For checking why the protocol was closed.

API:

  • public

{
  :none     => 0x00,
  :shutdown => 0x01
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(struct, data) ⇒ Packet

Initialize the packet.

Parameters:

  • the type of struct.

  • the packet data.

API:

  • public



162
163
164
165
# File 'lib/nova/starbound/protocol/packet.rb', line 162

def initialize(struct, data)
  @struct = struct
  @data = data
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Forwards requests on this packet of unkown methds to the data hash.

Returns:

API:

  • public



233
234
235
236
237
238
239
240
241
242
243
# File 'lib/nova/starbound/protocol/packet.rb', line 233

def method_missing(method, *args, &block)
  if @data.respond_to?(method)
    @data.public_send(method, *args, &block)
  elsif @data.key?(method)
    @data[method]
  elsif @data.key?(key = :"packet_#{method}")
    @data[key]
  else
    super
  end
end

Instance Attribute Details

#dataHash

The data in this packet.

Returns:

See Also:

  • []

API:

  • public



156
157
158
# File 'lib/nova/starbound/protocol/packet.rb', line 156

def data
  @data
end

#structSymbol (readonly)

The type of struct this packet is. See Structs.

Returns:

API:

  • public



150
151
152
# File 'lib/nova/starbound/protocol/packet.rb', line 150

def struct
  @struct
end

Class Method Details

.build(type, body, others = {}) ⇒ Packet

Builds a packet from a given body.

Parameters:

  • the type of packet it is. See Type.

  • the body of the packet.

  • (defaults to: {})

    the data to pass to the struct. See the packet struct definition to see what keys are allowed.

Returns:

  • the packet data.

API:

  • public



84
85
86
87
88
89
90
91
92
93
# File 'lib/nova/starbound/protocol/packet.rb', line 84

def self.build(type, body, others = {})
  packet_data = {
    :packet_type => Packet.types[type],
    :body        => body,
    :size        => body.bytesize
  }.merge(others)

  # Packet.struct[:packet].pack(packet_data)
  Packet.new(:packet, packet_data)
end

.build_response(type, body, packet_data = {}, others = {}) ⇒ Packet

Builds a response from a given body. Doesn’t increment the packet id, as a response doesn’t have a packet id.

Parameters:

  • the type of packet. See Type.

  • the body of the packet.

  • (defaults to: {})

    the packet data that this is a response to.

  • (defaults to: {})

    the data to pass to the struct. See the response struct definition to see what keys are allowed.

Options Hash (packet_data):

  • :packet_id (Numeric)

    the packet id this response is a response to.

  • :packet_type (Numeric)

    the packet type this response is a response to.

Returns:

  • the packet data.

API:

  • public



110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/nova/starbound/protocol/packet.rb', line 110

def self.build_response(type, body, packet_data = {}, others = {})
  response_data = {
    :packet_response_id   => packet_data[:packet_id] ||
      packet_data[:packet_response_id],
    :packet_response_type => packet_data[:packet_type],
    :packet_type          => Packet.types[type],
    :body                 => body,
    :size                 => body.bytesize
  }.merge(others)

  # Packet.struct[:response].pack(response_data)
  Packet.new(:response, response_data)
end

.from_socket(sock) ⇒ Packet

Unpacks a struct from a socket.

Parameters:

  • the socket to read from.

Returns:

Raises:

  • if it can’t determine the struct type.

API:

  • public



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/nova/starbound/protocol/packet.rb', line 130

def self.from_socket(sock)
  # we're gonna read one byte to see what type of packet it
  # is, a response or a regular packet.
  struct_type_num = sock.read(1)

  struct_type = Structs.key(
    struct_type_num.unpack("c").first)

  unless struct_type
    raise NoStructError,
      "Undefined struct type #{struct_type_num.inspect}"
  end

  data = Packet.struct[struct_type].unpack_from_socket(sock)
  Packet.new(struct_type, data)
end

.typesHash

Provides access to the Type constant.

Returns:

API:

  • public



73
74
75
# File 'lib/nova/starbound/protocol/packet.rb', line 73

def self.types
  Type
end

Instance Method Details

#body=(body) ⇒ void

This method returns an undefined value.

Sets the body and the size for this packet.

Parameters:

  • the new body.

API:

  • public



204
205
206
207
# File 'lib/nova/starbound/protocol/packet.rb', line 204

def body=(body)
  data[:body] = body
  data[:size] = body.bytesize
end

#expect(type) ⇒ Object

Checks this packet for the expected type.

Raises:

  • if the type doesn’t match.

API:

  • public



212
213
214
215
216
217
218
# File 'lib/nova/starbound/protocol/packet.rb', line 212

def expect(type)
  if self.type != type
    raise UnacceptablePacketError,
      "Expected packet to be of type #{type}, " +
      "got #{self.type} instead"
  end
end

#idNumeric

Forwards to the data key :packet_id, or if that doesn’t exist, :packet_response_id.

Returns:

API:

  • public



188
189
190
# File 'lib/nova/starbound/protocol/packet.rb', line 188

def id
  @data[:packet_id] || @data[:packet_response_id]
end

#initialize_copy(other) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Copies the data over to the new packet. This is used when #clone or #dup is copied on the instance.

API:

  • private



225
226
227
# File 'lib/nova/starbound/protocol/packet.rb', line 225

def initialize_copy(other)
  other.data = self.data.clone
end

#inspectString

Pretty inspect.

Returns:

API:

  • public



180
181
182
# File 'lib/nova/starbound/protocol/packet.rb', line 180

def inspect
  "#<#{self.class.name}:#{@struct}:#{@data}>"
end

#respond_to_missing?(method, include_all = false) ⇒ Boolean

Defined so ruby knows we’re doing #method_missing magic.

Parameters:

  • the method to check for.

  • (defaults to: false)

    whether or not to include private and protected methods.

Returns:

API:

  • public



251
252
253
# File 'lib/nova/starbound/protocol/packet.rb', line 251

def respond_to_missing?(method, include_all = false)
  @data.respond_to?(method, include_all) || @data.key?(method)
end

#to_sString Also known as: to_str

Turn this packet into a string.

Returns:

API:

  • public



170
171
172
173
# File 'lib/nova/starbound/protocol/packet.rb', line 170

def to_s
  @_cache ||= [Structs[@struct]].pack("c") +
    Packet.struct[@struct].pack(@data)
end

#typeSymbol, Numeric

The type of packet this is. Checks types before returning just the number.

Returns:

API:

  • public



196
197
198
# File 'lib/nova/starbound/protocol/packet.rb', line 196

def type
  Packet.types.key(@data[:packet_type]) || @data[:packet_type]
end