steam-condenser 0.10.1 → 0.11.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.
- data/VERSION.yml +2 -2
- data/lib/datagram_channel.rb +30 -33
- data/lib/exceptions/packet_format_exception.rb +7 -3
- data/lib/exceptions/rcon_ban_exception.rb +7 -5
- data/lib/exceptions/rcon_no_auth_exception.rb +8 -6
- data/lib/exceptions/timeout_exception.rb +10 -4
- data/lib/socket_channel.rb +11 -17
- data/lib/steam/community/cacheable.rb +5 -7
- data/lib/steam/community/css/css_map.rb +31 -0
- data/lib/steam/community/css/css_stats.rb +116 -0
- data/lib/steam/community/css/css_weapon.rb +33 -0
- data/lib/steam/community/dods/dods_stats.rb +3 -3
- data/lib/steam/community/game_stats.rb +14 -13
- data/lib/steam/community/game_weapon.rb +3 -5
- data/lib/steam/community/l4d/abstract_l4d_stats.rb +4 -2
- data/lib/steam/community/l4d/l4d_explosive.rb +2 -2
- data/lib/steam/community/l4d/l4d_map.rb +3 -3
- data/lib/steam/community/steam_group.rb +2 -4
- data/lib/steam/community/steam_id.rb +2 -2
- data/lib/steam/community/tf2/tf2_class.rb +17 -17
- data/lib/steam/community/tf2/tf2_class_factory.rb +17 -17
- data/lib/steam/community/tf2/tf2_engineer.rb +9 -9
- data/lib/steam/community/tf2/tf2_medic.rb +9 -9
- data/lib/steam/community/tf2/tf2_sniper.rb +7 -7
- data/lib/steam/community/tf2/tf2_spy.rb +9 -9
- data/lib/steam/community/tf2/tf2_stats.rb +9 -9
- data/lib/steam/packets/a2a_ack_packet.rb +11 -9
- data/lib/steam/packets/a2a_ping_packet.rb +5 -4
- data/lib/steam/packets/a2m_get_servers_batch2_packet.rb +13 -12
- data/lib/steam/packets/a2s_info_packet.rb +8 -7
- data/lib/steam/packets/a2s_player_packet.rb +6 -6
- data/lib/steam/packets/a2s_rules_packet.rb +5 -5
- data/lib/steam/packets/a2s_serverquery_getchallenge_packet.rb +4 -3
- data/lib/steam/packets/m2a_server_batch_packet.rb +20 -22
- data/lib/steam/packets/rcon/rcon_auth_request.rb +5 -5
- data/lib/steam/packets/rcon/rcon_auth_response.rb +6 -6
- data/lib/steam/packets/rcon/rcon_exec_request.rb +5 -5
- data/lib/steam/packets/rcon/rcon_exec_response.rb +2 -2
- data/lib/steam/packets/rcon/rcon_goldsrc_request.rb +7 -7
- data/lib/steam/packets/rcon/rcon_goldsrc_response.rb +8 -8
- data/lib/steam/packets/rcon/rcon_packet.rb +12 -16
- data/lib/steam/packets/rcon/rcon_packet_factory.rb +19 -19
- data/lib/steam/packets/request_with_challenge.rb +5 -5
- data/lib/steam/packets/s2a_info2_packet.rb +28 -30
- data/lib/steam/packets/s2a_info_base_packet.rb +11 -16
- data/lib/steam/packets/s2a_info_detailed_packet.rb +30 -28
- data/lib/steam/packets/s2a_player_packet.rb +7 -9
- data/lib/steam/packets/s2a_rules_packet.rb +8 -12
- data/lib/steam/packets/s2c_challenge_packet.rb +7 -6
- data/lib/steam/packets/steam_packet.rb +7 -6
- data/lib/steam/packets/steam_packet_factory.rb +37 -38
- data/lib/steam/servers/game_server.rb +76 -86
- data/lib/steam/servers/goldsrc_server.rb +5 -5
- data/lib/steam/servers/master_server.rb +24 -24
- data/lib/steam/servers/source_server.rb +17 -19
- data/lib/steam/sockets/goldsrc_socket.rb +43 -46
- data/lib/steam/sockets/master_server_socket.rb +11 -13
- data/lib/steam/sockets/rcon_socket.rb +15 -17
- data/lib/steam/sockets/source_socket.rb +21 -21
- data/lib/steam/sockets/steam_socket.rb +25 -28
- data/lib/steam/steam_player.rb +3 -1
- data/lib/stringio_additions.rb +48 -0
- data/test/datagram_channel_tests.rb +8 -8
- data/test/query_tests.rb +15 -14
- data/test/rcon_tests.rb +32 -31
- data/test/socket_channel_tests.rb +7 -7
- data/test/steam/communtiy/steam_community_test_suite.rb +5 -2
- data/test/steam_community_tests.rb +4 -3
- data/test/stringio_additions_tests.rb +77 -0
- metadata +15 -8
- data/lib/byte_buffer.rb +0 -126
- data/lib/exceptions/buffer_underflow_exception.rb +0 -8
- data/test/byte_buffer_tests.rb +0 -76
@@ -1,12 +1,12 @@
|
|
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-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
6
|
+
require 'stringio_additions'
|
7
|
+
require 'steam/packets/steam_packet_factory'
|
8
|
+
require 'steam/packets/rcon/rcon_goldsrc_request'
|
9
|
+
require 'steam/sockets/steam_socket'
|
10
10
|
|
11
11
|
# The SourceSocket class is a sub class of SteamSocket respecting the
|
12
12
|
# specifications of the Source query protocol.
|
@@ -21,18 +21,18 @@ class GoldSrcSocket < SteamSocket
|
|
21
21
|
# maximum packet size of 1400 byte. Greater packets will be split over several
|
22
22
|
# UDP packets. This method reassembles split packets into single packet
|
23
23
|
# objects.
|
24
|
-
def
|
25
|
-
bytes_read =
|
26
|
-
|
27
|
-
if @buffer.
|
28
|
-
split_packets =
|
24
|
+
def reply
|
25
|
+
bytes_read = receive_packet 1400
|
26
|
+
|
27
|
+
if @buffer.long == 0xFFFFFFFE
|
28
|
+
split_packets = []
|
29
29
|
begin
|
30
30
|
# Parsing of split packet headers
|
31
|
-
request_id = @buffer.
|
32
|
-
packet_number_and_count = @buffer.
|
31
|
+
request_id = @buffer.long
|
32
|
+
packet_number_and_count = @buffer.byte.to_i
|
33
33
|
packet_count = packet_number_and_count & 0xF
|
34
34
|
packet_number = (packet_number_and_count >> 4) + 1
|
35
|
-
|
35
|
+
|
36
36
|
# Caching of split packet data
|
37
37
|
split_packets[packet_number - 1] = @buffer.get
|
38
38
|
|
@@ -41,68 +41,65 @@ class GoldSrcSocket < SteamSocket
|
|
41
41
|
# Receiving the next packet
|
42
42
|
if split_packets.size < packet_count
|
43
43
|
begin
|
44
|
-
bytes_read =
|
44
|
+
bytes_read = receive_packet
|
45
45
|
rescue TimeoutException
|
46
46
|
bytes_read = 0
|
47
47
|
end
|
48
48
|
else
|
49
49
|
bytes_read = 0
|
50
50
|
end
|
51
|
-
end while bytes_read > 0 && @buffer.
|
52
|
-
|
51
|
+
end while bytes_read > 0 && @buffer.long == 0xFFFFFFFE
|
52
|
+
|
53
53
|
packet = SteamPacketFactory.reassemble_packet(split_packets)
|
54
|
-
|
55
54
|
else
|
56
|
-
packet = SteamPacketFactory.
|
55
|
+
packet = SteamPacketFactory.packet_from_data(@buffer.get)
|
57
56
|
end
|
58
57
|
|
59
58
|
puts "Got reply of type \"#{packet.class.to_s}\"." if $DEBUG
|
60
59
|
|
61
|
-
|
60
|
+
packet
|
62
61
|
end
|
63
|
-
|
62
|
+
|
64
63
|
def rcon_exec(password, command)
|
65
|
-
|
66
|
-
|
67
|
-
|
64
|
+
rcon_challenge if @rcon_challenge.nil? or @is_hltv
|
65
|
+
|
66
|
+
rcon_send "rcon #{@rcon_challenge} #{password} #{command}"
|
68
67
|
if @is_hltv
|
69
68
|
begin
|
70
|
-
response =
|
69
|
+
response = reply.response
|
71
70
|
rescue TimeoutException
|
72
|
-
response =
|
71
|
+
response = ''
|
73
72
|
end
|
74
73
|
else
|
75
|
-
response =
|
74
|
+
response = reply.response
|
76
75
|
end
|
77
|
-
|
78
|
-
if response.strip ==
|
79
|
-
raise RCONNoAuthException
|
76
|
+
|
77
|
+
if response.strip == 'Bad rcon_password.' or response.strip == 'You have been banned from this server.'
|
78
|
+
raise RCONNoAuthException
|
80
79
|
end
|
81
|
-
|
80
|
+
|
82
81
|
begin
|
83
|
-
|
84
|
-
response_part =
|
82
|
+
loop do
|
83
|
+
response_part = reply.response
|
85
84
|
response << response_part
|
86
85
|
end
|
87
86
|
rescue TimeoutException
|
88
87
|
end
|
89
|
-
|
90
|
-
|
88
|
+
|
89
|
+
response
|
91
90
|
end
|
92
|
-
|
93
|
-
def
|
94
|
-
|
95
|
-
response =
|
96
|
-
|
97
|
-
if response ==
|
98
|
-
|
99
|
-
end
|
100
|
-
|
91
|
+
|
92
|
+
def rcon_challenge
|
93
|
+
rcon_send 'challenge rcon'
|
94
|
+
response = reply.response.strip
|
95
|
+
|
96
|
+
raise RCONNoAuthException if response == 'You have been banned from this server.'
|
97
|
+
|
101
98
|
@rcon_challenge = response[14..-1]
|
102
99
|
end
|
103
|
-
|
100
|
+
|
104
101
|
def rcon_send(command)
|
105
|
-
|
102
|
+
send RCONGoldSrcRequest.new(command)
|
106
103
|
end
|
107
|
-
|
104
|
+
|
108
105
|
end
|
@@ -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-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
require
|
6
|
+
require 'steam/sockets/steam_socket'
|
7
7
|
|
8
8
|
class MasterServerSocket < SteamSocket
|
9
|
-
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
return SteamPacketFactory.get_packet_from_data(@buffer.get)
|
9
|
+
|
10
|
+
def reply
|
11
|
+
receive_packet 1500
|
12
|
+
|
13
|
+
raise Exception.new("Master query response has wrong packet header.") unless @buffer.long == 0xFFFFFFFF
|
14
|
+
|
15
|
+
SteamPacketFactory.packet_from_data(@buffer.get)
|
18
16
|
end
|
19
|
-
|
20
|
-
end
|
17
|
+
|
18
|
+
end
|
@@ -1,7 +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-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
6
|
require 'socket_channel'
|
7
7
|
require 'exceptions/rcon_ban_exception'
|
@@ -17,35 +17,33 @@ class RCONSocket < SteamSocket
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def send(data_packet)
|
20
|
-
|
21
|
-
@channel.connect @remote_socket
|
22
|
-
end
|
20
|
+
@channel.connect @remote_socket unless @channel.connected?
|
23
21
|
|
24
|
-
@buffer =
|
22
|
+
@buffer = StringIO.new data_packet.bytes
|
25
23
|
@channel.write @buffer
|
26
24
|
end
|
27
25
|
|
28
|
-
def
|
29
|
-
if
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
def reply
|
27
|
+
raise RCONBanException if receive_packet(1440) == 0
|
28
|
+
|
29
|
+
packet_data = @buffer.get
|
30
|
+
packet_size = @buffer.long + 4
|
31
|
+
@buffer.rewind
|
34
32
|
|
35
33
|
if packet_size > 1440
|
36
|
-
remaining_bytes = packet_size - @buffer.
|
34
|
+
remaining_bytes = packet_size - @buffer.size
|
37
35
|
begin
|
38
36
|
if remaining_bytes < 1440
|
39
|
-
|
37
|
+
receive_packet remaining_bytes
|
40
38
|
else
|
41
|
-
|
39
|
+
receive_packet 1440
|
42
40
|
end
|
43
|
-
packet_data << @buffer.
|
44
|
-
remaining_bytes -= @buffer.
|
41
|
+
packet_data << @buffer.get
|
42
|
+
remaining_bytes -= @buffer.size
|
45
43
|
end while remaining_bytes > 0
|
46
44
|
end
|
47
45
|
|
48
|
-
|
46
|
+
RCONPacketFactory.packet_from_data(packet_data)
|
49
47
|
end
|
50
48
|
|
51
49
|
end
|
@@ -1,10 +1,10 @@
|
|
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-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require 'stringio_additions'
|
7
|
+
require 'steam/sockets/steam_socket'
|
8
8
|
|
9
9
|
# The SourceSocket class is a sub class of SteamSocket respecting the
|
10
10
|
# specifications of the Source query protocol.
|
@@ -14,24 +14,24 @@ class SourceSocket < SteamSocket
|
|
14
14
|
# maximum packet size of 1400 byte. Greater packets will be split over several
|
15
15
|
# UDP packets. This method reassembles split packets into single packet
|
16
16
|
# objects.
|
17
|
-
def
|
18
|
-
bytes_read =
|
17
|
+
def reply
|
18
|
+
bytes_read = receive_packet 1400
|
19
19
|
is_compressed = false
|
20
20
|
|
21
|
-
if @buffer.
|
22
|
-
split_packets =
|
21
|
+
if @buffer.long == 0xFFFFFFFE
|
22
|
+
split_packets = []
|
23
23
|
begin
|
24
24
|
# Parsing of split packet headers
|
25
|
-
request_id = @buffer.
|
25
|
+
request_id = @buffer.long
|
26
26
|
is_compressed = ((request_id & 0x80000000) != 0)
|
27
|
-
packet_count = @buffer.
|
28
|
-
packet_number = @buffer.
|
29
|
-
|
27
|
+
packet_count = @buffer.byte.to_i
|
28
|
+
packet_number = @buffer.byte.to_i + 1
|
29
|
+
|
30
30
|
if is_compressed
|
31
|
-
|
32
|
-
packet_checksum = @buffer.
|
31
|
+
@buffer.long
|
32
|
+
packet_checksum = @buffer.long
|
33
33
|
else
|
34
|
-
|
34
|
+
@buffer.short
|
35
35
|
end
|
36
36
|
|
37
37
|
# Caching of split packet data
|
@@ -42,22 +42,22 @@ class SourceSocket < SteamSocket
|
|
42
42
|
# Receiving the next packet
|
43
43
|
if split_packets.size < packet_count
|
44
44
|
begin
|
45
|
-
bytes_read =
|
45
|
+
bytes_read = receive_packet
|
46
46
|
rescue TimeoutException
|
47
47
|
bytes_read = 0
|
48
48
|
end
|
49
49
|
else
|
50
50
|
bytes_read = 0
|
51
51
|
end
|
52
|
-
end while bytes_read > 0 && @buffer.
|
53
|
-
|
52
|
+
end while bytes_read > 0 && @buffer.long == 0xFFFFFFFE
|
53
|
+
|
54
54
|
if is_compressed
|
55
55
|
packet = SteamPacketFactory.reassemble_packet(split_packets, true, packet_checksum)
|
56
56
|
else
|
57
57
|
packet = SteamPacketFactory.reassemble_packet(split_packets)
|
58
58
|
end
|
59
59
|
else
|
60
|
-
packet = SteamPacketFactory.
|
60
|
+
packet = SteamPacketFactory.packet_from_data(@buffer.get)
|
61
61
|
end
|
62
62
|
|
63
63
|
if is_compressed
|
@@ -65,8 +65,8 @@ class SourceSocket < SteamSocket
|
|
65
65
|
else
|
66
66
|
puts "Got reply of type \"#{packet.class.to_s}\"." if $DEBUG
|
67
67
|
end
|
68
|
-
|
69
|
-
|
68
|
+
|
69
|
+
packet
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
end
|
@@ -1,60 +1,57 @@
|
|
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-
|
4
|
+
# Copyright (c) 2008-2010, Sebastian Staudt
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
6
|
+
require 'abstract_class'
|
7
|
+
require 'datagram_channel'
|
8
|
+
require 'ipaddr'
|
9
|
+
require 'stringio_additions'
|
10
|
+
require 'exceptions/timeout_exception'
|
11
11
|
|
12
|
-
#
|
13
|
-
#
|
12
|
+
# Defines common methods for sockets used to connect to game and master
|
13
|
+
# servers.
|
14
14
|
class SteamSocket
|
15
|
-
|
15
|
+
|
16
16
|
include AbstractClass
|
17
|
-
|
17
|
+
|
18
18
|
def initialize(*args)
|
19
19
|
@channel = DatagramChannel.open
|
20
20
|
@channel.connect *args
|
21
21
|
@channel.configure_blocking false
|
22
|
-
|
22
|
+
|
23
23
|
@remote_socket = Socket.getaddrinfo args[0].to_s, args[1]
|
24
24
|
end
|
25
25
|
|
26
|
-
# Abstract
|
27
|
-
def
|
26
|
+
# Abstract +reply+ method
|
27
|
+
def reply
|
28
28
|
raise NotImplementedError
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
def receive_packet(buffer_length = 0)
|
32
|
-
if select([@channel.socket], nil, nil, 1)
|
33
|
-
raise TimeoutException.new
|
34
|
-
end
|
32
|
+
raise TimeoutException if select([@channel.socket], nil, nil, 1).nil?
|
35
33
|
|
36
34
|
if buffer_length == 0
|
37
|
-
@buffer.
|
35
|
+
@buffer.truncate @buffer.size
|
38
36
|
else
|
39
|
-
@buffer =
|
37
|
+
@buffer = StringIO.allocate buffer_length
|
40
38
|
end
|
41
|
-
|
42
|
-
bytes_read = @channel.read
|
39
|
+
|
40
|
+
bytes_read = @channel.read @buffer
|
43
41
|
@buffer.rewind
|
44
|
-
|
45
|
-
|
42
|
+
|
46
43
|
bytes_read
|
47
44
|
end
|
48
|
-
|
45
|
+
|
49
46
|
def send(data_packet)
|
50
47
|
puts "Sending data packet of type \"#{data_packet.class.to_s}\"." if $DEBUG
|
51
48
|
|
52
|
-
@buffer =
|
53
|
-
@channel.write
|
49
|
+
@buffer = StringIO.new data_packet.to_s
|
50
|
+
@channel.write @buffer
|
54
51
|
end
|
55
|
-
|
52
|
+
|
56
53
|
def finalize
|
57
54
|
@channel.close
|
58
55
|
end
|
59
|
-
|
56
|
+
|
60
57
|
end
|
data/lib/steam/steam_player.rb
CHANGED
@@ -25,7 +25,9 @@ class SteamPlayer
|
|
25
25
|
def add_info(real_id, name, steam_id, *player_data)
|
26
26
|
@extended = true
|
27
27
|
|
28
|
-
|
28
|
+
unless name == @name
|
29
|
+
raise SteamCondenserException.new('Information to add belongs to a different player.')
|
30
|
+
end
|
29
31
|
|
30
32
|
@real_id = real_id
|
31
33
|
@steam_id = steam_id
|
@@ -0,0 +1,48 @@
|
|
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) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'stringio'
|
7
|
+
|
8
|
+
class StringIO
|
9
|
+
|
10
|
+
alias_method :data, :string
|
11
|
+
|
12
|
+
def self.allocate(size)
|
13
|
+
new "\0" * size
|
14
|
+
end
|
15
|
+
|
16
|
+
def byte
|
17
|
+
read(1)[0]
|
18
|
+
end
|
19
|
+
|
20
|
+
def float
|
21
|
+
read(4).unpack('e')[0]
|
22
|
+
end
|
23
|
+
|
24
|
+
def get
|
25
|
+
read remaining
|
26
|
+
end
|
27
|
+
|
28
|
+
def long
|
29
|
+
read(4).unpack('V')[0]
|
30
|
+
end
|
31
|
+
|
32
|
+
def remaining
|
33
|
+
size - pos
|
34
|
+
end
|
35
|
+
|
36
|
+
def short
|
37
|
+
read(2).unpack('v')[0]
|
38
|
+
end
|
39
|
+
|
40
|
+
def signed_long
|
41
|
+
read(4).unpack('l')[0]
|
42
|
+
end
|
43
|
+
|
44
|
+
def string
|
45
|
+
gets("\0")[0..-2]
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|