steam_mist 1.3.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.
- checksums.yaml +7 -0
- data/LICENSE +19 -0
- data/README.md +29 -0
- data/lib/steam_mist/connector.rb +167 -0
- data/lib/steam_mist/connectors/eager_connector.rb +24 -0
- data/lib/steam_mist/connectors/lazy_connector.rb +33 -0
- data/lib/steam_mist/connectors.rb +11 -0
- data/lib/steam_mist/pseudo_interface/pseudo_method.rb +187 -0
- data/lib/steam_mist/pseudo_interface.rb +75 -0
- data/lib/steam_mist/rcon/listener.rb +114 -0
- data/lib/steam_mist/rcon/packet.rb +146 -0
- data/lib/steam_mist/rcon/packet_factory.rb +45 -0
- data/lib/steam_mist/rcon/pass.rb +123 -0
- data/lib/steam_mist/rcon.rb +47 -0
- data/lib/steam_mist/request_uri.rb +77 -0
- data/lib/steam_mist/schema.rb +42 -0
- data/lib/steam_mist/session.rb +60 -0
- data/lib/steam_mist/version.rb +5 -0
- data/lib/steam_mist.rb +7 -0
- data/spec/cache_spec.rb +25 -0
- data/spec/packet_factory_spec.rb +8 -0
- data/spec/packet_spec.rb +26 -0
- data/spec/pseudo_interface_spec.rb +15 -0
- data/spec/pseudo_method_spec.rb +37 -0
- data/spec/request_uri_spec.rb +19 -0
- data/spec/schema_spec.rb +17 -0
- data/spec/session_spec.rb +9 -0
- metadata +97 -0
@@ -0,0 +1,146 @@
|
|
1
|
+
module SteamMist
|
2
|
+
class Rcon
|
3
|
+
|
4
|
+
# Represents a packet either received from the server or sent by the
|
5
|
+
# client.
|
6
|
+
class Packet
|
7
|
+
|
8
|
+
# This is used as a {#type}. This is for the client, authenticating to
|
9
|
+
# the server.
|
10
|
+
SERVERDATA_AUTH = 3
|
11
|
+
|
12
|
+
# Used for {#type}. This is for the response from the server from the
|
13
|
+
# client.
|
14
|
+
SERVERDATA_AUTH_RESPONSE = 2
|
15
|
+
|
16
|
+
# Used for {#type}. This is for the client executing a response to the
|
17
|
+
# server.
|
18
|
+
SERVERDATA_EXECCOMMAND = 2
|
19
|
+
|
20
|
+
# Used for {#type}. This is for the server sending back response data
|
21
|
+
# for `EXECCOMMAND`.
|
22
|
+
SERVERDATA_RESPONSE_VALUE = 0
|
23
|
+
|
24
|
+
# This matches the requests with their responses.
|
25
|
+
RESPONSE_MATCH = { SERVERDATA_AUTH => SERVERDATA_AUTH_RESPONSE,
|
26
|
+
SERVERDATA_EXECCOMMAND => SERVERDATA_RESPONSE_VALUE }
|
27
|
+
|
28
|
+
# The id of the packet. This is mainly used to match request packets
|
29
|
+
# with their response.
|
30
|
+
#
|
31
|
+
# @return [Numeric]
|
32
|
+
attr_accessor :id
|
33
|
+
|
34
|
+
# The type of the packet.
|
35
|
+
#
|
36
|
+
# @return [Numeric]
|
37
|
+
attr_accessor :type
|
38
|
+
|
39
|
+
# The body of the packet.
|
40
|
+
#
|
41
|
+
# @return [Numeric]
|
42
|
+
attr_accessor :body
|
43
|
+
|
44
|
+
# Initialize the packet.
|
45
|
+
#
|
46
|
+
# @param id [Numeric] the id of the packet.
|
47
|
+
def initialize(id=nil)
|
48
|
+
@id = id || 0
|
49
|
+
@type = SERVERDATA_EXECCOMMAND
|
50
|
+
@body = ""
|
51
|
+
end
|
52
|
+
|
53
|
+
# Formats the packet for sending to the server. See
|
54
|
+
# [this](https://developer.valvesoftware.com/wiki/Source_RCON_Protocol)
|
55
|
+
# on how it's done.
|
56
|
+
#
|
57
|
+
# @return [String] a formatted string containing the data.
|
58
|
+
def format
|
59
|
+
[size, id, type, body].pack("l<l<l<a#{body.bytesize+1}x")
|
60
|
+
end
|
61
|
+
|
62
|
+
# This returns the size of the packet. This is the size of the body, in
|
63
|
+
# bytes. It also adds 10 bytes for the type (4 bytes), id (4 bytes), and
|
64
|
+
# the two nul-terminators (one for the body and one for the packet).
|
65
|
+
#
|
66
|
+
# @return [Numeric]
|
67
|
+
def size
|
68
|
+
body.bytesize + 10
|
69
|
+
end
|
70
|
+
|
71
|
+
# Compare this with another object. Calls {#to_i} on the other object
|
72
|
+
# and this one and delegates to that.
|
73
|
+
#
|
74
|
+
# @return [Numeric]
|
75
|
+
def <=>(other)
|
76
|
+
self.to_i <=> other.to_i
|
77
|
+
end
|
78
|
+
|
79
|
+
# Shows whether or not the packet is empty. The packet is not empty if
|
80
|
+
# the body contains more than "" and the type is not 2.
|
81
|
+
#
|
82
|
+
# @return [Boolean]
|
83
|
+
def empty?
|
84
|
+
body.empty? && (type != 2)
|
85
|
+
end
|
86
|
+
|
87
|
+
# This checks to see if it is SRCDS's weird packet response.
|
88
|
+
#
|
89
|
+
# @return [Boolean]
|
90
|
+
def weird?
|
91
|
+
(type == 0) and (body == "\x00\x01\x00\x00")
|
92
|
+
end
|
93
|
+
|
94
|
+
# This loads the packet data from a hash. Overwrites the contents of the
|
95
|
+
# packet.
|
96
|
+
#
|
97
|
+
# @param hash [Hash]
|
98
|
+
# @return [self]
|
99
|
+
def load!(hash)
|
100
|
+
self.id = hash[:id] || hash["id"] || id
|
101
|
+
self.type = hash[:type] || hash["type"] || type
|
102
|
+
self.body = hash[:body] || hash["body"] || body
|
103
|
+
self
|
104
|
+
end
|
105
|
+
|
106
|
+
alias :to_i :id
|
107
|
+
|
108
|
+
# This takes a formatted string and turns it into a packet instance.
|
109
|
+
# This is mainly used for responses from the server.
|
110
|
+
#
|
111
|
+
# @param raw [String] the raw data from the server.
|
112
|
+
# @return [Packet] the packet representing the data.
|
113
|
+
def self.from_raw(raw)
|
114
|
+
packet = Packet.new
|
115
|
+
size, = raw.unpack("l<")
|
116
|
+
_, packet.id, packet.type, packet.body =
|
117
|
+
raw.unpack("l<l<l<a#{size - 10}xx")
|
118
|
+
packet
|
119
|
+
end
|
120
|
+
|
121
|
+
# This reads from a stream and converts it into a packet.
|
122
|
+
#
|
123
|
+
# @param socket [#read] the stream to read from.
|
124
|
+
# @return [Packet] the packet representing the data.
|
125
|
+
def self.from_stream(socket)
|
126
|
+
packet = Packet.new
|
127
|
+
size, = socket.read(4).unpack("l<")
|
128
|
+
packet.id, packet.type, packet.body =
|
129
|
+
socket.read(size).unpack("l<l<a#{size - 10}xx")
|
130
|
+
packet
|
131
|
+
end
|
132
|
+
|
133
|
+
# This sets up the packet from a given hash.
|
134
|
+
#
|
135
|
+
# @param data [Hash] the data to map to the packet.
|
136
|
+
# @return [Packet]
|
137
|
+
def self.from_hash(data)
|
138
|
+
packet = Packet.new
|
139
|
+
packet.load! data
|
140
|
+
|
141
|
+
packet
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'set'
|
2
|
+
|
3
|
+
module SteamMist
|
4
|
+
class Rcon
|
5
|
+
|
6
|
+
# Creates packets for use.
|
7
|
+
class PacketFactory
|
8
|
+
|
9
|
+
# An {SortedSet} containing all of the packets that have been created.
|
10
|
+
#
|
11
|
+
# @return [SortedSet]
|
12
|
+
attr_accessor :packets
|
13
|
+
|
14
|
+
# The current packet number.
|
15
|
+
#
|
16
|
+
# @return [Numeric]
|
17
|
+
attr_accessor :number
|
18
|
+
|
19
|
+
# initializes.
|
20
|
+
def initialize
|
21
|
+
@number = 1
|
22
|
+
@packets = SortedSet.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# Creates a packet. Automatically assigns it an id, based off of the
|
26
|
+
# current packet number.
|
27
|
+
#
|
28
|
+
# @return [Packet]
|
29
|
+
def create_packet
|
30
|
+
packet = Packet.new(@number)
|
31
|
+
@packets << packet
|
32
|
+
@number = @number + 1
|
33
|
+
packet
|
34
|
+
end
|
35
|
+
|
36
|
+
# Pretty inspect
|
37
|
+
#
|
38
|
+
# @return [String]
|
39
|
+
def inspect
|
40
|
+
"#<SteamMist::Rcon::PacketFactory #{@number}>"
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module SteamMist
|
2
|
+
class Rcon
|
3
|
+
|
4
|
+
# This basically handles sending and receiving packets.
|
5
|
+
class Pass
|
6
|
+
|
7
|
+
# The packet factory that should be used when creating packets. This
|
8
|
+
# factory is used to increment the ID number on sequential packets.
|
9
|
+
#
|
10
|
+
# @return [PacketFactory]
|
11
|
+
attr_reader :packet_factory
|
12
|
+
|
13
|
+
# The listener for sending and receiving data from the server.
|
14
|
+
#
|
15
|
+
# @return [Listener]
|
16
|
+
attr_reader :listener
|
17
|
+
|
18
|
+
# Initialize.
|
19
|
+
#
|
20
|
+
# @param ip [String] the IP address of the Rcon server. Passed to
|
21
|
+
# Listener.
|
22
|
+
# @param port [Numeric] the port of the Rcon server. Passed to Listener.
|
23
|
+
def initialize(ip, port = 27015)
|
24
|
+
@packet_factory = PacketFactory.new
|
25
|
+
@listener = Listener.new ip, port
|
26
|
+
@empty_packet = Packet.from_hash :type => Packet::SERVERDATA_RESPONSE_VALUE
|
27
|
+
end
|
28
|
+
|
29
|
+
# Retrieves the next packet from the stream. If a block is given, it
|
30
|
+
# yields to that.
|
31
|
+
#
|
32
|
+
# @yieldparam packet [Packet]
|
33
|
+
# @return [Packet]
|
34
|
+
def on_packet(&block)
|
35
|
+
ensure_connected.on_data do |con|
|
36
|
+
packet = Packet.from_stream con
|
37
|
+
|
38
|
+
if block
|
39
|
+
block.call packet
|
40
|
+
end
|
41
|
+
|
42
|
+
packet
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Sends the given packet to the server.
|
47
|
+
#
|
48
|
+
# @param packet [Packet]
|
49
|
+
# @return [void, Numeric]
|
50
|
+
def write(packet)
|
51
|
+
ensure_connected.write packet.format
|
52
|
+
end
|
53
|
+
|
54
|
+
# Sends a packet along with an empty packet. This allows the client to
|
55
|
+
# figure out the server sent multiple packets to the client for the same
|
56
|
+
# request packet. Returns an array of packets if the server sent
|
57
|
+
# multiple packets.
|
58
|
+
#
|
59
|
+
# @param packet [Packet] the packet to send
|
60
|
+
# @return [Packet, Array<Packet>]
|
61
|
+
def send_packet(packet)
|
62
|
+
empty_packet = @empty_packet.dup
|
63
|
+
empty_packet.id = packet.id
|
64
|
+
write(packet) and write(empty_packet)
|
65
|
+
response_packets = []
|
66
|
+
|
67
|
+
begin
|
68
|
+
while response_packets.empty? || !response_packets.last.weird? do
|
69
|
+
response_packets << on_packet
|
70
|
+
end
|
71
|
+
|
72
|
+
rescue TimeoutError; end
|
73
|
+
|
74
|
+
response_packets.pop(2)
|
75
|
+
|
76
|
+
if response_packets.length == 1
|
77
|
+
response_packets[0]
|
78
|
+
else
|
79
|
+
response_packets
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# This authenticates the connection with the server. A password is
|
84
|
+
# required.
|
85
|
+
#
|
86
|
+
# @param password [String] the password to authenticate with.
|
87
|
+
# @return [Boolean]
|
88
|
+
def auth(password)
|
89
|
+
packet = packet_factory.create_packet
|
90
|
+
packet.type = Packet::SERVERDATA_AUTH
|
91
|
+
packet.body = password
|
92
|
+
|
93
|
+
#response = send_packet packet
|
94
|
+
write packet
|
95
|
+
|
96
|
+
# discard
|
97
|
+
on_packet
|
98
|
+
|
99
|
+
response = on_packet
|
100
|
+
|
101
|
+
response.id == packet.id
|
102
|
+
end
|
103
|
+
|
104
|
+
# This closes the connection by calling {Listener#close}.
|
105
|
+
#
|
106
|
+
# @return [void]
|
107
|
+
def close
|
108
|
+
listener.close
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
# This makes sure the listener is connected before trying to perform an
|
114
|
+
# I/O operation.
|
115
|
+
#
|
116
|
+
# @return [Listener]
|
117
|
+
def ensure_connected
|
118
|
+
listener.bind! unless listener.connection
|
119
|
+
listener
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require 'steam_mist/rcon/pass'
|
3
|
+
require 'steam_mist/rcon/packet'
|
4
|
+
require 'steam_mist/rcon/listener'
|
5
|
+
require 'steam_mist/rcon/packet_factory'
|
6
|
+
|
7
|
+
module SteamMist
|
8
|
+
|
9
|
+
# This class provides RCON capabilities.
|
10
|
+
class Rcon
|
11
|
+
|
12
|
+
extend Forwardable
|
13
|
+
|
14
|
+
# This is the class that handles reading and writing packets from the
|
15
|
+
# listener.
|
16
|
+
#
|
17
|
+
# @return [Pass]
|
18
|
+
attr_reader :pass
|
19
|
+
|
20
|
+
# Initialize.
|
21
|
+
#
|
22
|
+
# @param ip [String] the IP to connect to.
|
23
|
+
# @param port [Numeric] the port to connect to.
|
24
|
+
def initialize(ip, port = 27015)
|
25
|
+
@pass = Pass.new(ip, port)
|
26
|
+
end
|
27
|
+
|
28
|
+
# This takes a hash, turns it into a packet, and sends it.
|
29
|
+
#
|
30
|
+
# @param hash [Hash] the data to turn into a packet.
|
31
|
+
# @return [Packet, Array<Packet>]
|
32
|
+
def send(hash)
|
33
|
+
send_packet packet_factory.create_packet.load!(hash)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Pretty inspect
|
37
|
+
#
|
38
|
+
# @return [String]
|
39
|
+
def inspect
|
40
|
+
"#<SteamMist::Rcon>"
|
41
|
+
end
|
42
|
+
|
43
|
+
def_delegators :@pass, :on_packet, :send_packet, :auth, :close,
|
44
|
+
:packet_factory
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module SteamMist
|
2
|
+
|
3
|
+
# This represents a request that may be made to the steam api. It is mainly
|
4
|
+
# used for obtaining paths to request to.
|
5
|
+
class RequestUri
|
6
|
+
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# This is the interface the request will be made to, like +ISteamUser+.
|
10
|
+
#
|
11
|
+
# @return [String]
|
12
|
+
attr_accessor :interface
|
13
|
+
|
14
|
+
# This is the method of the interface the request will be made to.
|
15
|
+
#
|
16
|
+
# @return [String]
|
17
|
+
attr_accessor :method
|
18
|
+
|
19
|
+
# These are the arguments that will be passed for the request.
|
20
|
+
#
|
21
|
+
# @return [Enumerable]
|
22
|
+
attr_accessor :arguments
|
23
|
+
|
24
|
+
# The version of the method to request.
|
25
|
+
#
|
26
|
+
# @return [Numeric]
|
27
|
+
attr_accessor :version
|
28
|
+
|
29
|
+
# The domain to make the reuqest to.
|
30
|
+
#
|
31
|
+
# @return [String]
|
32
|
+
attr_accessor :domain
|
33
|
+
|
34
|
+
# Initialize the request. Can take a hash. Options for the hash can be
|
35
|
+
# `:interface`, `:method`, `:version`, `:domain` and `:arguments`.
|
36
|
+
# Anything else will cause an argument error. See the attributes for
|
37
|
+
# each respectively on what they're for.
|
38
|
+
#
|
39
|
+
# @param options [Hash] the options to be used.
|
40
|
+
def initialize(options)
|
41
|
+
{
|
42
|
+
:interface => "",
|
43
|
+
:method => "",
|
44
|
+
:arguments => {},
|
45
|
+
:version => 0,
|
46
|
+
:domain => "api.steampowered.com"
|
47
|
+
}.merge(options).each do |k, v|
|
48
|
+
if respond_to? "#{k}="
|
49
|
+
send "#{k}=", v
|
50
|
+
else
|
51
|
+
raise ArgumentError, "don't know how to handle #{k}!"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Takes the request data and formats it into an URI.
|
57
|
+
#
|
58
|
+
# @return [URI] the URI of the request.
|
59
|
+
def format_uri
|
60
|
+
basic = "http://%s/%s/%s/v%04d" % [domain, interface, method, version]
|
61
|
+
|
62
|
+
uri = URI(basic)
|
63
|
+
uri.query = URI.encode_www_form(arguments)
|
64
|
+
|
65
|
+
uri
|
66
|
+
end
|
67
|
+
|
68
|
+
# Outputs a string version of the request.
|
69
|
+
#
|
70
|
+
# @return [String] the fully formated URL of the request.
|
71
|
+
def to_s
|
72
|
+
format_uri.to_s
|
73
|
+
end
|
74
|
+
|
75
|
+
def_delegator :format_uri, :open
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'hashie/mash'
|
3
|
+
|
4
|
+
module SteamMist
|
5
|
+
|
6
|
+
# Handles the Schema for games.
|
7
|
+
#
|
8
|
+
# @todo More tests.
|
9
|
+
class Schema
|
10
|
+
|
11
|
+
# Initialize the schema. The first argument is the application id,
|
12
|
+
# which valve uses internally to distinguish games from each other.
|
13
|
+
#
|
14
|
+
# @param app_id [Numeric]
|
15
|
+
# @param lang [String] the language the schema should return its
|
16
|
+
# results in.
|
17
|
+
def initialize(key, app_id, lang = nil)
|
18
|
+
@app_id = app_id
|
19
|
+
@session = Session.new
|
20
|
+
@get_schema = @session.get_interface("IEconItems_#{app_id}").get_schema
|
21
|
+
|
22
|
+
if lang
|
23
|
+
@get_schema.with_arguments!(:language => lang)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns a list of items in the schema.
|
28
|
+
#
|
29
|
+
# @return [SortedSet<Item>]
|
30
|
+
def items
|
31
|
+
@_items ||= data.items
|
32
|
+
end
|
33
|
+
|
34
|
+
# Retrieves the data from the request.
|
35
|
+
#
|
36
|
+
# @return [Hashie::Mash]
|
37
|
+
def data
|
38
|
+
@_data ||= Hashie::Mash.new(@get_schema.get.data["result"])
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# We're placing these here so that if someone wants to only use this part of
|
2
|
+
# the library, they don't have to require the entire thing.
|
3
|
+
require 'oj'
|
4
|
+
require 'uri'
|
5
|
+
require 'forwardable'
|
6
|
+
require 'steam_mist/version'
|
7
|
+
require 'steam_mist/connector'
|
8
|
+
require 'steam_mist/connectors'
|
9
|
+
require 'steam_mist/request_uri'
|
10
|
+
require 'steam_mist/pseudo_interface'
|
11
|
+
require 'steam_mist/schema'
|
12
|
+
|
13
|
+
module SteamMist
|
14
|
+
|
15
|
+
# The session is used as a starting point for connecting to the Steam API.
|
16
|
+
class Session
|
17
|
+
|
18
|
+
# The connector that the session is going to use.
|
19
|
+
#
|
20
|
+
# @return [Class] the connector.
|
21
|
+
attr_accessor :connector
|
22
|
+
|
23
|
+
# The default arguments that the session will use.
|
24
|
+
#
|
25
|
+
# @return [Hash]
|
26
|
+
attr_accessor :default_arguments
|
27
|
+
|
28
|
+
# Initialize.
|
29
|
+
#
|
30
|
+
# @param connector [Class] the connector (should be subclass of {Connector}).
|
31
|
+
def initialize(connector = Connectors::LazyConnector)
|
32
|
+
@connector = connector
|
33
|
+
@_interfaces = {}
|
34
|
+
@default_arguments = {}
|
35
|
+
end
|
36
|
+
|
37
|
+
# Grabs an interface for use. These are cached, so every call with the
|
38
|
+
# same argument returns the same object.
|
39
|
+
#
|
40
|
+
# @param interface [Symbol] the interface name.
|
41
|
+
# @return [PseudoInterface]
|
42
|
+
def get_interface(interface)
|
43
|
+
@_interfaces[interface] ||= PseudoInterface.new(self, interface)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Some {#method_missing} magic. Sorry @charliesome!
|
47
|
+
#
|
48
|
+
# @see {#get_interface}
|
49
|
+
def method_missing(method, *args)
|
50
|
+
super if args.length > 0 or block_given?
|
51
|
+
get_interface method
|
52
|
+
end
|
53
|
+
|
54
|
+
# pretty inspection
|
55
|
+
def inspect
|
56
|
+
"#<SteamMist::Session #{connector.inspect}>"
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
data/lib/steam_mist.rb
ADDED
data/spec/cache_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
describe SteamMist::Connectors::LazyConnector do
|
2
|
+
|
3
|
+
subject { described_class.new(request_uri) }
|
4
|
+
let(:request_uri) { "https://api.twitter.com/1/statuses/oembed.json?id=133640144317198338" }
|
5
|
+
|
6
|
+
it "can cache" do
|
7
|
+
subject.enable_caching "tmp/example_cache.json"
|
8
|
+
expect(subject).to be_cache
|
9
|
+
end
|
10
|
+
|
11
|
+
it "does cache" do
|
12
|
+
subject.enable_caching "tmp/example_cache.json"
|
13
|
+
subject.data
|
14
|
+
expect { |p| subject.send(:with_cache, &p) }.to_not yield_control
|
15
|
+
end
|
16
|
+
|
17
|
+
it "loads from cache file" do
|
18
|
+
subject.enable_caching "tmp/example_cache.json"
|
19
|
+
expect { |p| subject.send(:with_cache, &p) }.to_not yield_control
|
20
|
+
end
|
21
|
+
|
22
|
+
after :all do
|
23
|
+
File.unlink "tmp/example_cache.json"
|
24
|
+
end
|
25
|
+
end
|
data/spec/packet_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
describe SteamMist::Rcon::Packet do
|
4
|
+
it "should format itself correctly" do
|
5
|
+
subject.id = 5
|
6
|
+
subject.type = 2
|
7
|
+
subject.body << "hello world"
|
8
|
+
|
9
|
+
subject.format.should eq "\x15\0\0\0\x05\0\0\0\x02\0\0\0hello world\0\0"
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should properly deserialize data from raw" do
|
13
|
+
packet = described_class.from_raw "\x15\0\0\0\x05\0\0\0\x02\0\0\0hello world\0\0"
|
14
|
+
packet.id.should be 5
|
15
|
+
packet.type.should be 2
|
16
|
+
packet.body.should eq "hello world"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should properly deserialize data from a stream" do
|
20
|
+
s = StringIO.new "\x15\0\0\0\x05\0\0\0\x02\0\0\0hello world\0\0"
|
21
|
+
packet = described_class.from_stream s
|
22
|
+
packet.id.should be 5
|
23
|
+
packet.type.should be 2
|
24
|
+
packet.body.should eq "hello world"
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
describe SteamMist::PseudoInterface do
|
2
|
+
|
3
|
+
subject(:interface) do
|
4
|
+
described_class.new(nil, :some_interface)
|
5
|
+
end
|
6
|
+
|
7
|
+
it "turns the interface name into the correct api name" do
|
8
|
+
interface.api_name.should == "ISomeInterface"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "gives a pseudo method" do
|
12
|
+
interface.get_method(:some_method) \
|
13
|
+
.should be_instance_of SteamMist::PseudoInterface::PseudoMethod
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
describe SteamMist::PseudoInterface::PseudoMethod do
|
2
|
+
|
3
|
+
subject(:pseudo_method) do
|
4
|
+
session = SteamMist::Session.new(SteamMist::Connectors::LazyConnector)
|
5
|
+
session.default_arguments[:something] = "value"
|
6
|
+
interface = SteamMist::PseudoInterface.new(session, :some_interface)
|
7
|
+
described_class.new(interface, :some_method, 4)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should turn the method name into an api name" do
|
11
|
+
pseudo_method.api_name.should == "SomeMethod"
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return a copy when adding arguments" do
|
15
|
+
pseudo_method.with_arguments(:hello => "world").should_not be pseudo_method
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return a copy when changing versions" do
|
19
|
+
pseudo_method.with_version(3).should_not be pseudo_method
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return a request uri" do
|
23
|
+
pseudo_method.request_uri.should be_instance_of SteamMist::RequestUri
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should give a connector instance" do
|
27
|
+
pseudo_method.get.should be_instance_of SteamMist::Connectors::LazyConnector
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should use default arguments" do
|
31
|
+
pseudo_method.request_uri.arguments.should include(:something => "value")
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should give a connector with caching" do
|
35
|
+
expect(pseudo_method.with_caching("some_file").get).to be_cache
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
describe SteamMist::RequestUri do
|
2
|
+
|
3
|
+
subject(:request_uri) do
|
4
|
+
SteamMist::RequestUri.new(:interface => "ISomeInterface", :method => "SomeMethod",
|
5
|
+
:version => 1)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should raise an argument error" do
|
9
|
+
expect { described_class.new(:something => :else) }.to raise_error(ArgumentError)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should return a uri" do
|
13
|
+
request_uri.format_uri.should be_instance_of(URI::HTTP)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should format the right string" do
|
17
|
+
request_uri.to_s.should eq "http://api.steampowered.com/ISomeInterface/SomeMethod/v0001?"
|
18
|
+
end
|
19
|
+
end
|