steam-condenser 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|