steam-condenser 0.8.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/LICENSE +25 -0
- data/README.md +30 -0
- data/Rakefile +42 -0
- data/lib/abstract_class.rb +40 -0
- data/lib/byte_buffer.rb +126 -0
- data/lib/datagram_channel.rb +70 -0
- data/lib/exceptions/buffer_underflow_exception.rb +10 -0
- data/lib/exceptions/packet_format_exception.rb +12 -0
- data/lib/exceptions/rcon_no_auth_exception.rb +14 -0
- data/lib/exceptions/steam_condenser_exception.rb +8 -0
- data/lib/exceptions/timeout_exception.rb +10 -0
- data/lib/socket_channel.rb +54 -0
- data/lib/steam-condenser.rb +3 -0
- data/lib/steam/community/dods/dods_class.rb +32 -0
- data/lib/steam/community/dods/dods_stats.rb +47 -0
- data/lib/steam/community/dods/dods_weapon.rb +54 -0
- data/lib/steam/community/game_achievement.rb +26 -0
- data/lib/steam/community/game_class.rb +15 -0
- data/lib/steam/community/game_stats.rb +92 -0
- data/lib/steam/community/game_weapon.rb +29 -0
- data/lib/steam/community/l4d/l4d_explosive.rb +23 -0
- data/lib/steam/community/l4d/l4d_map.rb +34 -0
- data/lib/steam/community/l4d/l4d_stats.rb +166 -0
- data/lib/steam/community/l4d/l4d_weapon.rb +23 -0
- data/lib/steam/community/steam_group.rb +16 -0
- data/lib/steam/community/steam_id.rb +212 -0
- data/lib/steam/community/tf2/tf2_class.rb +31 -0
- data/lib/steam/community/tf2/tf2_class_factory.rb +38 -0
- data/lib/steam/community/tf2/tf2_engineer.rb +25 -0
- data/lib/steam/community/tf2/tf2_medic.rb +22 -0
- data/lib/steam/community/tf2/tf2_sniper.rb +20 -0
- data/lib/steam/community/tf2/tf2_spy.rb +23 -0
- data/lib/steam/community/tf2/tf2_stats.rb +39 -0
- data/lib/steam/packets/a2a_ack_packet.rb +21 -0
- data/lib/steam/packets/a2a_ping_packet.rb +18 -0
- data/lib/steam/packets/a2m_get_servers_batch2_packet.rb +25 -0
- data/lib/steam/packets/a2s_info_packet.rb +18 -0
- data/lib/steam/packets/a2s_player_packet.rb +22 -0
- data/lib/steam/packets/a2s_rules_packet.rb +21 -0
- data/lib/steam/packets/a2s_serverquery_getchallenge_packet.rb +18 -0
- data/lib/steam/packets/m2a_server_batch_packet.rb +37 -0
- data/lib/steam/packets/rcon/rcon_auth_request.rb +16 -0
- data/lib/steam/packets/rcon/rcon_auth_response.rb +16 -0
- data/lib/steam/packets/rcon/rcon_exec_request.rb +16 -0
- data/lib/steam/packets/rcon/rcon_exec_response.rb +20 -0
- data/lib/steam/packets/rcon/rcon_goldsrc_request.rb +20 -0
- data/lib/steam/packets/rcon/rcon_goldsrc_response.rb +20 -0
- data/lib/steam/packets/rcon/rcon_packet.rb +36 -0
- data/lib/steam/packets/rcon/rcon_packet_factory.rb +37 -0
- data/lib/steam/packets/request_with_challenge.rb +16 -0
- data/lib/steam/packets/s2a_info2_packet.rb +48 -0
- data/lib/steam/packets/s2a_info_base_packet.rb +29 -0
- data/lib/steam/packets/s2a_info_detailed_packet.rb +50 -0
- data/lib/steam/packets/s2a_player_packet.rb +32 -0
- data/lib/steam/packets/s2a_rules_packet.rb +33 -0
- data/lib/steam/packets/s2c_challenge_packet.rb +23 -0
- data/lib/steam/packets/steam_packet.rb +48 -0
- data/lib/steam/packets/steam_packet_factory.rb +90 -0
- data/lib/steam/servers/game_server.rb +222 -0
- data/lib/steam/servers/goldsrc_server.rb +36 -0
- data/lib/steam/servers/master_server.rb +60 -0
- data/lib/steam/servers/source_server.rb +65 -0
- data/lib/steam/sockets/goldsrc_socket.rb +108 -0
- data/lib/steam/sockets/master_server_socket.rb +20 -0
- data/lib/steam/sockets/rcon_socket.rb +50 -0
- data/lib/steam/sockets/source_socket.rb +72 -0
- data/lib/steam/sockets/steam_socket.rb +63 -0
- data/lib/steam/steam_player.rb +51 -0
- data/test/query_tests.rb +71 -0
- data/test/rcon_tests.rb +79 -0
- data/test/steam_community_tests.rb +36 -0
- metadata +132 -0
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2008, Sebastian Staudt
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name of the author nor the names of its contributors
|
13
|
+
may be used to endorse or promote products derived from this software
|
14
|
+
without specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
17
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
20
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
23
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Steam Condenser
|
2
|
+
===============
|
3
|
+
|
4
|
+
The Steam Condenser is a multi-language library for querying the Steam
|
5
|
+
Community, Source and GoldSrc game servers as well as the Steam master servers.
|
6
|
+
Currently it is implemented in Java, PHP and Ruby.
|
7
|
+
|
8
|
+
## Requirements
|
9
|
+
|
10
|
+
* Linux, MacOS X or Windows
|
11
|
+
* Ruby 1.8.6 or newer
|
12
|
+
* [Ruby BZ2 module](http://www.rubyforge.org/projects/bz2)
|
13
|
+
|
14
|
+
## License
|
15
|
+
|
16
|
+
This code is free software; you can redistribute it and/or modify it under the
|
17
|
+
terms of the new BSD License. A copy of this license can be found in the LICENSE
|
18
|
+
file.
|
19
|
+
|
20
|
+
## Credits
|
21
|
+
|
22
|
+
* Sebastian Staudt -- koraktor(at)gmail.com
|
23
|
+
|
24
|
+
## See Also
|
25
|
+
|
26
|
+
* [Steam Condenser home](http://koraktor.github.com/steam-condenser)
|
27
|
+
* [Documentation](http://www.rdoc.info/projects/koraktor/steam-condenser)
|
28
|
+
* [GitHub project page](http://github.com/koraktor/steam-condenser)
|
29
|
+
* [Google group](http://groups.google.com/group/steam-condenser)
|
30
|
+
* [Ohloh profile](http://www.ohloh.net/projects/steam-condenser)
|
data/Rakefile
ADDED
@@ -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) 2008-2009, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
require 'rake/gempackagetask'
|
8
|
+
require 'rubygems'
|
9
|
+
require 'jeweler'
|
10
|
+
|
11
|
+
src_files = Dir.glob(File.join("lib", "**", "*.rb"))
|
12
|
+
test_files = Dir.glob(File.join("test", "**", "*.rb"))
|
13
|
+
|
14
|
+
# Gem specification
|
15
|
+
Jeweler::Tasks.new do |s|
|
16
|
+
s.name = "steam-condenser"
|
17
|
+
s.date = Time.now
|
18
|
+
s.description = s.summary = 'A multi-language library for querying Source, GoldSrc servers and Steam master servers'
|
19
|
+
s.authors = ['Sebastian Staudt']
|
20
|
+
s.email = 'koraktor@gmail.com'
|
21
|
+
s.homepage = 'http://github.com/koraktor/steam-condenser'
|
22
|
+
|
23
|
+
s.files = %w(README.md Rakefile LICENSE) + src_files + test_files
|
24
|
+
s.rdoc_options = ["--all", "--inline-source", "--line-numbers", "--charset=utf-8", "--webcvs=http://github.com/koraktor/steam-condenser/source/blob/master/ruby/%s"]
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a rake task +:rdoc+ to build the documentation
|
28
|
+
desc "Building docs"
|
29
|
+
Rake::RDocTask.new do |rdoc|
|
30
|
+
rdoc.title = "Steam Condenser documentation"
|
31
|
+
rdoc.rdoc_files.include ["lib/**/*.rb", "test/**/*.rb", "LICENSE", "README.md"]
|
32
|
+
rdoc.main = "README.md"
|
33
|
+
rdoc.rdoc_dir = "rdoc"
|
34
|
+
rdoc.options = ["--all", "--inline-source", "--line-numbers", "--charset=utf-8", "--webcvs=http://github.com/koraktor/steam-condenser/source/blob/master/ruby/%s"]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Task for cleaning documentation and package directories
|
38
|
+
desc "Clean documentation and package directories"
|
39
|
+
task :clean do
|
40
|
+
FileUtils.rm_rf "doc"
|
41
|
+
FileUtils.rm_rf "pkg"
|
42
|
+
end
|
@@ -0,0 +1,40 @@
|
|
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) 2008, Sebastian Staudt
|
5
|
+
#
|
6
|
+
# $Id$
|
7
|
+
|
8
|
+
# This module is used to mimic the behavior of abstract classes known from other
|
9
|
+
# object-oriented programming languages
|
10
|
+
module AbstractClass
|
11
|
+
|
12
|
+
# If this module is included in a class:
|
13
|
+
# * protect the constructor of the class
|
14
|
+
# * make sure every derived class has a constructor calling the super
|
15
|
+
# constructor
|
16
|
+
def self.included(klass)
|
17
|
+
klass.module_eval do
|
18
|
+
|
19
|
+
class << self
|
20
|
+
protected :new
|
21
|
+
|
22
|
+
# Each derived class gets a constructor calling the super constructor
|
23
|
+
def inherited(klass)
|
24
|
+
klass.module_eval do
|
25
|
+
|
26
|
+
# The constructor for derived classes, simply calling the super
|
27
|
+
# constructor
|
28
|
+
def self.new(*args)
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/byte_buffer.rb
ADDED
@@ -0,0 +1,126 @@
|
|
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) 2008, Sebastian Staudt
|
5
|
+
|
6
|
+
require "exceptions/buffer_underflow_exception"
|
7
|
+
|
8
|
+
# The ByteBuffer class derived from Java's java.nio.ByteBuffer
|
9
|
+
class ByteBuffer
|
10
|
+
|
11
|
+
attr_accessor :limit
|
12
|
+
attr_reader :position
|
13
|
+
protected :initialize
|
14
|
+
|
15
|
+
# Creates a new buffer with the given size in bytes
|
16
|
+
def self.allocate(length)
|
17
|
+
return ByteBuffer.new(0.chr * length)
|
18
|
+
end
|
19
|
+
|
20
|
+
# Creates a new buffer from an existing String
|
21
|
+
def self.wrap(byte_array)
|
22
|
+
return ByteBuffer.new(byte_array.to_s)
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
def initialize(byte_array)
|
27
|
+
if byte_array.is_a? ByteBuffer
|
28
|
+
raise Exception.new
|
29
|
+
end
|
30
|
+
|
31
|
+
@byte_array = byte_array.to_s
|
32
|
+
@capacity = @byte_array.length
|
33
|
+
@limit = @capacity
|
34
|
+
@position = 0
|
35
|
+
@mark = -1
|
36
|
+
end
|
37
|
+
|
38
|
+
def array
|
39
|
+
return @byte_array
|
40
|
+
end
|
41
|
+
|
42
|
+
def clear
|
43
|
+
@limit = @capacity
|
44
|
+
@position = 0
|
45
|
+
@mark = -1
|
46
|
+
|
47
|
+
return self
|
48
|
+
end
|
49
|
+
|
50
|
+
def flip
|
51
|
+
@limit = @position
|
52
|
+
@position = 0
|
53
|
+
@mark = -1
|
54
|
+
|
55
|
+
return self
|
56
|
+
end
|
57
|
+
|
58
|
+
def get(length = nil)
|
59
|
+
if length == nil
|
60
|
+
length = @limit - @position
|
61
|
+
elsif length > self.remaining
|
62
|
+
BufferUnderflowException.new
|
63
|
+
end
|
64
|
+
|
65
|
+
data = @byte_array[@position, length]
|
66
|
+
@position += length
|
67
|
+
|
68
|
+
return data
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_byte
|
72
|
+
return self.get(1)[0]
|
73
|
+
end
|
74
|
+
|
75
|
+
def get_float
|
76
|
+
return self.get(4).unpack("e")[0]
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_long
|
80
|
+
return self.get(4).unpack("V")[0]
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_short
|
84
|
+
return self.get(2).unpack("v")[0]
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_signed_long
|
88
|
+
return self.get(4).unpack('l')[0]
|
89
|
+
end
|
90
|
+
|
91
|
+
def get_string
|
92
|
+
zero_byte_index = @byte_array.index("\0", @position)
|
93
|
+
if zero_byte_index == nil
|
94
|
+
return ""
|
95
|
+
else
|
96
|
+
data_string = self.get(zero_byte_index - @position)
|
97
|
+
@position += 1
|
98
|
+
return data_string
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def length
|
103
|
+
return @byte_array.length
|
104
|
+
end
|
105
|
+
|
106
|
+
def remaining
|
107
|
+
return @limit - @position
|
108
|
+
end
|
109
|
+
|
110
|
+
def rewind
|
111
|
+
@position = 0
|
112
|
+
@mark = -1
|
113
|
+
|
114
|
+
return self
|
115
|
+
end
|
116
|
+
|
117
|
+
def put(source_byte_array)
|
118
|
+
new_position = [source_byte_array.length, self.remaining].min
|
119
|
+
|
120
|
+
@byte_array[@position, new_position] = source_byte_array
|
121
|
+
@position = new_position
|
122
|
+
|
123
|
+
return self
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
@@ -0,0 +1,70 @@
|
|
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) 2008, Sebastian Staudt
|
5
|
+
#
|
6
|
+
# $Id$
|
7
|
+
|
8
|
+
require "byte_buffer"
|
9
|
+
|
10
|
+
class DatagramChannel
|
11
|
+
|
12
|
+
attr_reader :socket
|
13
|
+
|
14
|
+
def self.open
|
15
|
+
return DatagramChannel.new
|
16
|
+
end
|
17
|
+
|
18
|
+
def close
|
19
|
+
@socket.close
|
20
|
+
end
|
21
|
+
|
22
|
+
def connect(*args)
|
23
|
+
if args[0].is_a? IPAddr
|
24
|
+
ip_address = args[0].to_s
|
25
|
+
elsif args[0].is_a? String
|
26
|
+
sockaddr = (Socket.gethostbyname args[0])[3]
|
27
|
+
ip_address = "#{sockaddr[0]}.#{sockaddr[1]}.#{sockaddr[2]}.#{sockaddr[3]}"
|
28
|
+
end
|
29
|
+
|
30
|
+
if args[1].is_a? Numeric
|
31
|
+
port_number = args[1]
|
32
|
+
else
|
33
|
+
port_number = args[1].to_i
|
34
|
+
end
|
35
|
+
|
36
|
+
@socket.connect ip_address, port_number
|
37
|
+
|
38
|
+
return self
|
39
|
+
end
|
40
|
+
|
41
|
+
def configure_blocking(do_block)
|
42
|
+
end
|
43
|
+
|
44
|
+
def read(destination_buffer)
|
45
|
+
if !destination_buffer.is_a? ByteBuffer
|
46
|
+
raise ArgumentError
|
47
|
+
end
|
48
|
+
|
49
|
+
length = destination_buffer.remaining
|
50
|
+
data = @socket.recv length
|
51
|
+
destination_buffer.put data
|
52
|
+
|
53
|
+
return data.length
|
54
|
+
end
|
55
|
+
|
56
|
+
def write(source_buffer)
|
57
|
+
if !source_buffer.is_a? ByteBuffer
|
58
|
+
raise ArgumentError
|
59
|
+
end
|
60
|
+
|
61
|
+
return @socket.send(source_buffer.get, 0)
|
62
|
+
end
|
63
|
+
|
64
|
+
protected
|
65
|
+
|
66
|
+
def initialize
|
67
|
+
@socket = UDPSocket.new
|
68
|
+
self.configure_blocking true
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,12 @@
|
|
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) 2008, Sebastian Staudt
|
5
|
+
#
|
6
|
+
# $Id$
|
7
|
+
|
8
|
+
require "exceptions/steam_condenser_exception"
|
9
|
+
|
10
|
+
class PacketFormatException < SteamCondenserException
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
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) 2008, Sebastian Staudt
|
5
|
+
#
|
6
|
+
# $Id$
|
7
|
+
|
8
|
+
class RCONNoAuthException < Exception
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
super "Not authenticated yet."
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,54 @@
|
|
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) 2008-2009, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'byte_buffer'
|
7
|
+
require 'timeout'
|
8
|
+
|
9
|
+
class SocketChannel
|
10
|
+
|
11
|
+
attr_reader :socket
|
12
|
+
|
13
|
+
def self.open
|
14
|
+
return SocketChannel.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def connect(*args)
|
18
|
+
timeout(1) do
|
19
|
+
@socket = TCPSocket.new args[0][0][3], args[0][0][1]
|
20
|
+
@connected = true
|
21
|
+
end
|
22
|
+
|
23
|
+
return self
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize
|
27
|
+
@connected = false
|
28
|
+
end
|
29
|
+
|
30
|
+
def connected?
|
31
|
+
return @connected
|
32
|
+
end
|
33
|
+
|
34
|
+
def read(destination_buffer)
|
35
|
+
if !destination_buffer.is_a? ByteBuffer
|
36
|
+
raise ArgumentError
|
37
|
+
end
|
38
|
+
|
39
|
+
length = destination_buffer.remaining
|
40
|
+
data = @socket.recv length
|
41
|
+
destination_buffer.put data
|
42
|
+
|
43
|
+
return data.length
|
44
|
+
end
|
45
|
+
|
46
|
+
def write(source_buffer)
|
47
|
+
if !source_buffer.is_a? ByteBuffer
|
48
|
+
raise ArgumentError
|
49
|
+
end
|
50
|
+
|
51
|
+
return @socket.send(source_buffer.get, 0)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|