steam-condenser 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12,12 +12,12 @@ class TF2Stats < GameStats
12
12
  attr_reader :accumulated_points
13
13
 
14
14
  # Creates a TF2Stats object by calling the super constructor with the game
15
- # name "TF2"
15
+ # name "tf2"
16
16
  def initialize(steam_id)
17
- super steam_id, "TF2"
17
+ super steam_id, 'tf2'
18
18
 
19
19
  if public?
20
- @accumulated_points = @xml_data.elements["stats"].elements["accumulatedPoints"].text.to_i
20
+ @accumulated_points = @xml_data.elements['stats/accumulatedPoints'].text.to_i
21
21
  end
22
22
  end
23
23
 
@@ -28,8 +28,8 @@ class TF2Stats < GameStats
28
28
 
29
29
  if @class_stats.nil?
30
30
  @class_stats = Hash.new
31
- @xml_data.elements["stats"].elements.each("classData") do |class_data|
32
- @class_stats[class_data.elements["className"].text] = TF2Class.new class_data
31
+ @xml_data.elements.each('stats/classData') do |class_data|
32
+ @class_stats[class_data.elements['className'].text] = TF2Class.new(class_data)
33
33
  end
34
34
  end
35
35
 
@@ -1,20 +1,18 @@
1
1
  # This code is free software; you can redistribute it and/or modify it under the
2
2
  # terms of the new BSD License.
3
3
  #
4
- # Copyright (c) 2008, Sebastian Staudt
5
- #
6
- # $Id$
4
+ # Copyright (c) 2008-2009, Sebastian Staudt
7
5
 
8
6
  require "steam/packets/rcon/rcon_packet"
9
7
 
10
8
  class RCONExecResponse < RCONPacket
11
-
9
+
12
10
  def initialize(request_id, command_response)
13
11
  super request_id, RCONPacket::SERVERDATA_RESPONSE_VALUE, command_response
14
12
  end
15
-
13
+
16
14
  def get_response
17
- return @content_data.array
15
+ @content_data.array[0..-3]
18
16
  end
19
-
20
- end
17
+
18
+ end
@@ -2,27 +2,34 @@
2
2
  # terms of the new BSD License.
3
3
  #
4
4
  # Copyright (c) 2008, Sebastian Staudt
5
- #
6
- # $Id$
7
5
 
8
6
  require "steam/packets/steam_packet"
9
7
 
10
8
  # The S2A_RULES_Packet class represents the response to a A2S_RULES
11
9
  # request send to the server.
12
10
  class S2A_RULES_Packet < SteamPacket
13
-
11
+
14
12
  # Creates a S2A_RULES response object based on the data received.
15
13
  def initialize(content_data)
16
14
  if content_data == nil
17
15
  raise Exception.new("Wrong formatted A2A_RULES response packet.")
18
16
  end
19
-
17
+
20
18
  super SteamPacket::S2A_RULES_HEADER, content_data
21
-
22
- @rules_hash = Hash.new @content_data.get_short
23
19
 
24
- while @content_data.remaining > 0
25
- @rules_hash[@content_data.get_string] = @content_data.get_string
20
+ rules_count = @content_data.get_short
21
+
22
+ @rules_hash = {}
23
+
24
+ rules_count.times do
25
+ rule = @content_data.get_string
26
+ value = @content_data.get_string
27
+
28
+ # This is a workaround for servers sending corrupt replies
29
+ break if rule.empty? or value.empty?
30
+
31
+ @rules_hash[rule] = value
32
+ puts "#{rule} = #{value}"
26
33
  end
27
34
  end
28
35
 
@@ -142,13 +142,11 @@ class GameServer
142
142
  unless rcon_password.nil? or @player_hash.empty?
143
143
  rcon_auth(rcon_password)
144
144
  players = rcon_exec('status').split("\n")[7..-1]
145
- if is_a? GoldSrcServer
146
- players.pop
147
- end
145
+ players.pop if is_a? GoldSrcServer
148
146
 
149
147
  players.each do |player|
150
148
  player_data = split_player_status(player)
151
- @player_hash[player_data[1]].add_info(*player_data)
149
+ @player_hash[player_data[1]].add_info(*player_data) if @player_hash.key?(player_data[1])
152
150
  end
153
151
  end
154
152
  end
@@ -10,7 +10,7 @@ class GoldSrcServer < GameServer
10
10
 
11
11
  # Splits the player status obtained with +rcon status+
12
12
  def self.split_player_status(player_status)
13
- player_data = player_status.match(/#( \d|\d\d) +"(.*)" +(\d+) +(.*)/).to_a[1..-1]
13
+ player_data = player_status.match(/# *(\d+) +"(.*)" +(\d+) +(.*)/).to_a[1..-1]
14
14
  player_data[3] = player_data[3].split
15
15
  player_data.flatten!
16
16
  player_data[0] = player_data[2]
@@ -23,14 +23,14 @@ class GoldSrcServer < GameServer
23
23
  super port_number
24
24
  @socket = GoldSrcSocket.new ip_address, port_number, is_hltv
25
25
  end
26
-
26
+
27
27
  def rcon_auth(password)
28
28
  @rcon_password = password
29
29
  return true
30
30
  end
31
-
31
+
32
32
  def rcon_exec(command)
33
33
  return @socket.rcon_exec(@rcon_password, command).strip
34
34
  end
35
-
36
- end
35
+
36
+ end
@@ -15,35 +15,35 @@ class SourceServer < GameServer
15
15
 
16
16
  # Splits the player status obtained with +rcon status+
17
17
  def self.split_player_status(player_status)
18
- player_data = player_status.match(/#( \d|\d\d) +"(.*)" +(.*)/).to_a[1..-1]
18
+ player_data = player_status.match(/# *(\d+) +"(.*)" +(.*)/).to_a[1..-1]
19
19
  player_data[2] = player_data[2].split
20
20
  player_data.flatten
21
21
  end
22
-
22
+
23
23
  def initialize(ip_address, port_number = 27015)
24
24
  super port_number
25
25
  @rcon_socket = RCONSocket.new ip_address, port_number
26
26
  @socket = SourceSocket.new ip_address, port_number
27
27
  end
28
-
28
+
29
29
  def rcon_auth(password)
30
30
  @rcon_request_id = rand 2**16
31
-
31
+
32
32
  @rcon_socket.send RCONAuthRequest.new(@rcon_request_id, password)
33
33
  @rcon_socket.get_reply
34
34
  reply = @rcon_socket.get_reply
35
-
35
+
36
36
  if reply.request_id == -1
37
37
  raise RCONNoAuthException.new
38
38
  end
39
-
39
+
40
40
  return reply.get_request_id == @rcon_request_id
41
41
  end
42
-
42
+
43
43
  def rcon_exec(command)
44
44
  @rcon_socket.send RCONExecRequest.new(@rcon_request_id, command)
45
45
  response_packets = Array.new
46
-
46
+
47
47
  begin
48
48
  begin
49
49
  response_packet = @rcon_socket.get_reply
@@ -53,13 +53,13 @@ class SourceServer < GameServer
53
53
  rescue TimeoutException
54
54
  raise $! if response_packets.empty?
55
55
  end
56
-
56
+
57
57
  response = String.new
58
58
  response_packets.each do |packet|
59
59
  response << packet.get_response
60
60
  end
61
-
61
+
62
62
  return response.strip
63
63
  end
64
64
 
65
- end
65
+ end
@@ -1,38 +1,39 @@
1
1
  # This code is free software; you can redistribute it and/or modify it under the
2
2
  # terms of the new BSD License.
3
3
  #
4
- # Copyright (c) 2008, Sebastian Staudt
5
- #
6
- # $Id$
4
+ # Copyright (c) 2008-2009, Sebastian Staudt
7
5
 
8
- require "socket_channel"
9
- require "steam/packets/rcon/rcon_packet"
10
- require "steam/packets/rcon/rcon_packet_factory"
11
- require "steam/sockets/steam_socket"
6
+ require 'socket_channel'
7
+ require 'exceptions/rcon_ban_exception'
8
+ require 'steam/packets/rcon/rcon_packet'
9
+ require 'steam/packets/rcon/rcon_packet_factory'
10
+ require 'steam/sockets/steam_socket'
12
11
 
13
12
  class RCONSocket < SteamSocket
14
-
13
+
15
14
  def initialize(ip_address, port_number)
16
15
  super ip_address, port_number
17
16
  @channel = SocketChannel.open
18
17
  end
19
-
18
+
20
19
  def send(data_packet)
21
20
  if !@channel.connected?
22
21
  @channel.connect @remote_socket
23
22
  end
24
-
23
+
25
24
  @buffer = ByteBuffer.wrap data_packet.get_bytes
26
25
  @channel.write @buffer
27
26
  end
28
-
27
+
29
28
  def get_reply
30
- self.receive_packet 1440
29
+ if self.receive_packet(1440) == 0
30
+ raise RCONBanException
31
+ end
31
32
  packet_data = @buffer.array[0..@buffer.limit]
32
33
  packet_size = @buffer.get_long + 4
33
-
34
+
34
35
  if packet_size > 1440
35
- remaining_bytes = packet_size - 1440
36
+ remaining_bytes = packet_size - @buffer.limit
36
37
  begin
37
38
  if remaining_bytes < 1440
38
39
  self.receive_packet remaining_bytes
@@ -43,8 +44,8 @@ class RCONSocket < SteamSocket
43
44
  remaining_bytes -= @buffer.limit
44
45
  end while remaining_bytes > 0
45
46
  end
46
-
47
+
47
48
  return RCONPacketFactory.get_packet_from_data(packet_data)
48
49
  end
49
-
50
- end
50
+
51
+ end
@@ -1,9 +1,7 @@
1
1
  # This code is free software; you can redistribute it and/or modify it under the
2
2
  # terms of the new BSD License.
3
3
  #
4
- # Copyright (c) 2008, Sebastian Staudt
5
- #
6
- # $Id$
4
+ # Copyright (c) 2008-2009, Sebastian Staudt
7
5
 
8
6
  require "abstract_class"
9
7
  require "byte_buffer"
@@ -41,19 +39,18 @@ class SteamSocket
41
39
  @buffer = ByteBuffer.allocate buffer_length
42
40
  end
43
41
 
44
- @channel.read @buffer
45
- bytes_read = @buffer.position
42
+ bytes_read = @channel.read(@buffer)
46
43
  @buffer.rewind
47
44
  @buffer.limit = bytes_read
48
45
 
49
- return bytes_read
46
+ bytes_read
50
47
  end
51
48
 
52
49
  def send(data_packet)
53
50
  warn "Sending data packet of type \"#{data_packet.class.to_s}\"."
54
51
 
55
- @buffer = ByteBuffer.wrap data_packet.to_s
56
- @channel.write @buffer
52
+ @buffer = ByteBuffer.wrap(data_packet.to_s)
53
+ @channel.write(@buffer)
57
54
  end
58
55
 
59
56
  def finalize
@@ -8,9 +8,9 @@ require 'exceptions/steam_condenser_exception'
8
8
  # The SteamPlayer class represents a player connected to a server
9
9
  class SteamPlayer
10
10
 
11
- attr_reader :connect_time, :id, :name, :loss, :ping, :real_id, :score, :state,
12
- :steam_id
13
-
11
+ attr_reader :client_port, :connect_time, :id, :ip_address, :name, :loss,
12
+ :ping, :real_id, :score, :state, :steam_id
13
+
14
14
  # Creates a new SteamPlayer object based on the given information
15
15
  def initialize(id, name, score, connect_time)
16
16
  @connect_time = connect_time
@@ -32,7 +32,7 @@ class SteamPlayer
32
32
  if steam_id == 'BOT'
33
33
  @state = player_data[0]
34
34
  else
35
- @addr = player_data[4]
35
+ @ip_address, @client_port = player_data[4].split(':')
36
36
  @loss = player_data[2]
37
37
  @ping = player_data[1]
38
38
  @state = player_data[3]
@@ -47,5 +47,5 @@ class SteamPlayer
47
47
  "\##{@id} \"#{@name}\", Score: #{@score}, Time: #{@connect_time}"
48
48
  end
49
49
  end
50
-
50
+
51
51
  end
@@ -0,0 +1,76 @@
1
+ # This code is free software; you can redistribute it and/or modify it under the
2
+ # terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2009, Sebastian Staudt
5
+
6
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
7
+
8
+ require 'test/unit'
9
+ require 'byte_buffer'
10
+
11
+ class ByteBufferTests < Test::Unit::TestCase
12
+
13
+ def test_allocate
14
+ buffer = ByteBuffer.allocate(10)
15
+ assert_equal("\0" * 10, buffer.array)
16
+ end
17
+
18
+ def test_get_byte
19
+ buffer = ByteBuffer.wrap('test')
20
+ assert_equal('t'[0], buffer.get_byte)
21
+ assert_equal(3, buffer.remaining)
22
+ end
23
+
24
+ def test_get_float
25
+ buffer = ByteBuffer.wrap('test')
26
+ assert_equal('7.71353668494131e+31', buffer.get_float.to_s)
27
+ assert_equal(0, buffer.remaining)
28
+ end
29
+
30
+ def test_get_long
31
+ buffer = ByteBuffer.wrap('test')
32
+ assert_equal(1953719668, buffer.get_long)
33
+ assert_equal(0, buffer.remaining)
34
+ end
35
+
36
+ def test_get_short
37
+ buffer = ByteBuffer.wrap('test')
38
+ assert_equal(25972, buffer.get_short)
39
+ assert_equal(2, buffer.remaining)
40
+ end
41
+
42
+ def test_get_signed_long
43
+ buffer = ByteBuffer.wrap(" \255")
44
+ assert_equal(-1390403552, buffer.get_signed_long)
45
+ assert_equal(0, buffer.remaining)
46
+ end
47
+
48
+ def test_get_string
49
+ buffer = ByteBuffer.wrap("test\0test")
50
+ assert_equal('test', buffer.get_string)
51
+ assert_equal(4, buffer.remaining)
52
+ end
53
+
54
+ def test_put
55
+ buffer = ByteBuffer.wrap('te')
56
+ buffer.put('st')
57
+ assert_equal('st', buffer.array)
58
+ buffer = ByteBuffer.allocate(4)
59
+ buffer.put('test')
60
+ assert_equal('test', buffer.array)
61
+ end
62
+
63
+ def test_rewind
64
+ buffer = ByteBuffer.wrap('test')
65
+ assert_equal(25972, buffer.get_short)
66
+ buffer.rewind
67
+ assert_equal(25972, buffer.get_short)
68
+ end
69
+
70
+ def test_wrap
71
+ string = 'test'
72
+ buffer = ByteBuffer.wrap(string)
73
+ assert_equal(string, buffer.array)
74
+ end
75
+
76
+ end
@@ -0,0 +1,42 @@
1
+ # This code is free software; you can redistribute it and/or modify it under the
2
+ # terms of the new BSD License.
3
+ #
4
+ # Copyright (c) 2009, Sebastian Staudt
5
+
6
+ $:.push File.join(File.dirname(__FILE__), '..', 'lib')
7
+
8
+ require 'test/unit'
9
+
10
+ require 'byte_buffer'
11
+ require 'datagram_channel'
12
+
13
+ class DatagramChannelTests < Test::Unit::TestCase
14
+
15
+ def test_read_write
16
+ port = rand(65536 - 1024) + 1024
17
+
18
+ socket = UDPSocket.new
19
+ socket.bind('localhost', port)
20
+
21
+ channel = DatagramChannel.open
22
+ channel.connect('localhost', port)
23
+
24
+ string = 'test'
25
+
26
+ buffer = ByteBuffer.wrap(string)
27
+ channel.write(buffer)
28
+ sent, socket_addr = socket.recvfrom(4)
29
+ socket.send(string, 0, 'localhost', socket_addr[1])
30
+ buffer = ByteBuffer.allocate(4)
31
+ channel.read(buffer)
32
+
33
+ channel.close
34
+ socket.close
35
+
36
+ received = buffer.array
37
+
38
+ assert_equal(string, sent)
39
+ assert_equal(string, received)
40
+ end
41
+
42
+ end