Class: Rcon::Packet

Inherits:
Object
  • Object
show all
Defined in:
lib/rcon/packet.rb

Overview

Data structure representing packets sent to / received from RCON server.

Constant Summary collapse

REQUEST_PACKET_TYPE =

Types of packets that the server expects to receive.

The keys correspond with the Source RCON spec names, the values correspond with what the server expects to see in the type segment of a packet.

{
  SERVERDATA_AUTH: 3,
  SERVERDATA_EXECCOMMAND: 2
}.freeze
RESPONSE_PACKET_TYPE =

Types of packets that the client can expect to receive back from the server.

The keys correspond with the Source RCON spec names, the values correspond with what the client expects to see in the type segment of a packet.

{
  SERVERDATA_AUTH_RESPONSE: 2,
  SERVERDATA_RESPONSE_VALUE: 0
}.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id, type, body) ⇒ Packet

Instantiates a Rcon::Packet

Parameters:



70
71
72
73
74
# File 'lib/rcon/packet.rb', line 70

def initialize(id, type, body)
  @id = id
  @type = type
  @body = body
end

Instance Attribute Details

#bodyObject (readonly)

Returns the value of attribute body.



125
126
127
# File 'lib/rcon/packet.rb', line 125

def body
  @body
end

#idObject (readonly)

Returns the value of attribute id.



125
126
127
# File 'lib/rcon/packet.rb', line 125

def id
  @id
end

#typeObject (readonly)

Returns the value of attribute type.



125
126
127
# File 'lib/rcon/packet.rb', line 125

def type
  @type
end

Class Method Details

.read_from_socket_wrapper(socket_wrapper) ⇒ Packet

Read a packet from the given SocketWrapper.

Parameters:

Returns:

Raises:

  • if timeout occurs while waiting to read from socket



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rcon/packet.rb', line 43

def self.read_from_socket_wrapper(socket_wrapper)
  if socket_wrapper.ready_to_read?
    size = socket_wrapper.recv(INT_BYTE_SIZE)&.unpack(INTEGER_PACK_DIRECTIVE)&.first
    if size.nil?
      raise Error::ServerClosedSocketError
    end
    id_and_type_length = 2 * INT_BYTE_SIZE
    body_length = size - id_and_type_length - (2 * TRAILER_BYTE_SIZE) # ignore trailing nulls

    payload = socket_wrapper.recv(size)
    if payload.nil?
      raise Error::ServerClosedSocketError
    end
    id, type_int = payload[0...id_and_type_length].unpack("#{INTEGER_PACK_DIRECTIVE}*")
    body = payload[id_and_type_length..].unpack("#{STR_PACK_DIRECTIVE}#{body_length}").first
    type = RESPONSE_PACKET_TYPE.key(type_int) || raise(Error::InvalidResponsePacketTypeCodeError.new(type_int))

    new(id, RESPONSE_PACKET_TYPE.key(type_int), body)
  end
end

Instance Method Details

#==(other) ⇒ Boolean

Compares two objects to see if they are equal

Returns true if other is a Packet and attributes match self, false otherwise.

Parameters:

Returns:



81
82
83
# File 'lib/rcon/packet.rb', line 81

def ==(other)
  eql?(other)
end

#eql?(other) ⇒ Boolean

Compares two objects to see if they are equal Returns true if other is a Packet and attributes match self, false otherwise.

Parameters:

Returns:



90
91
92
93
94
95
96
# File 'lib/rcon/packet.rb', line 90

def eql?(other)
  if other.is_a?(Packet)
    id == other.id && type == other.type && body == other.body
  else
    false
  end
end

#to_sString

Converts the packet into an ASCII-encoded RCON Packet string for transmitting to the server.

Returns:



102
103
104
105
106
# File 'lib/rcon/packet.rb', line 102

def to_s
  [id, type_to_i, "#{body}#{TRAILER}", TRAILER].pack(PACKET_PACK_DIRECTIVE).then do |packet_str|
    "#{[packet_str.length].pack(INTEGER_PACK_DIRECTIVE)}#{packet_str}".force_encoding(ENCODING)
  end
end

#type_to_iInteger

Get the integer representation of the packet’s type, which is used in the string representation of the packet.

Returns:

Raises:

  • if the packet type is unknown / invalid.



113
114
115
116
117
118
119
120
121
122
123
# File 'lib/rcon/packet.rb', line 113

def type_to_i
  type_sym = type.to_sym
  case type_sym
  when ->(t) { REQUEST_PACKET_TYPE.keys.include?(t) }
    REQUEST_PACKET_TYPE[type_sym]
  when ->(t) { RESPONSE_PACKET_TYPE.keys.include?(t) }
    RESPONSE_PACKET_TYPE[type_sym]
  else
    raise Error::InvalidPacketTypeError.new(type)
  end
end