steam-condenser 0.14.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. data/Gemfile +3 -0
  2. data/Gemfile.lock +22 -0
  3. data/LICENSE +1 -1
  4. data/README.md +14 -6
  5. data/Rakefile +35 -0
  6. data/lib/{stringio_additions.rb → core_ext/stringio.rb} +1 -1
  7. data/lib/{exceptions/packet_format_exception.rb → errors/packet_format_error.rb} +5 -5
  8. data/lib/{exceptions/rcon_ban_exception.rb → errors/rcon_ban_error.rb} +5 -5
  9. data/lib/{exceptions/rcon_no_auth_exception.rb → errors/rcon_no_auth_error.rb} +5 -5
  10. data/lib/{exceptions/steam_condenser_exception.rb → errors/steam_condenser_error.rb} +3 -3
  11. data/lib/errors/timeout_error.rb +28 -0
  12. data/lib/{exceptions/web_api_exception.rb → errors/web_api_error.rb} +8 -8
  13. data/lib/steam/community/alien_swarm/alien_swarm_mission.rb +86 -11
  14. data/lib/steam/community/alien_swarm/alien_swarm_stats.rb +38 -15
  15. data/lib/steam/community/alien_swarm/alien_swarm_weapon.rb +29 -8
  16. data/lib/steam/community/app_news.rb +91 -27
  17. data/lib/steam/community/cacheable.rb +65 -21
  18. data/lib/steam/community/css/css_map.rb +39 -9
  19. data/lib/steam/community/css/css_stats.rb +32 -12
  20. data/lib/steam/community/css/css_weapon.rb +46 -10
  21. data/lib/steam/community/defense_grid/defense_grid_stats.rb +129 -17
  22. data/lib/steam/community/dods/dods_class.rb +66 -10
  23. data/lib/steam/community/dods/dods_stats.rb +20 -7
  24. data/lib/steam/community/dods/dods_weapon.rb +35 -24
  25. data/lib/steam/community/game_achievement.rb +50 -19
  26. data/lib/steam/community/game_class.rb +16 -5
  27. data/lib/steam/community/game_inventory.rb +37 -4
  28. data/lib/steam/community/game_item.rb +64 -3
  29. data/lib/steam/community/game_stats.rb +81 -16
  30. data/lib/steam/community/game_weapon.rb +29 -11
  31. data/lib/steam/community/l4d/abstract_l4d_stats.rb +91 -65
  32. data/lib/steam/community/l4d/abstract_l4d_weapon.rb +38 -8
  33. data/lib/steam/community/l4d/l4d2_map.rb +30 -5
  34. data/lib/steam/community/l4d/l4d2_stats.rb +83 -45
  35. data/lib/steam/community/l4d/l4d2_weapon.rb +20 -6
  36. data/lib/steam/community/l4d/l4d_explosive.rb +13 -5
  37. data/lib/steam/community/l4d/l4d_map.rb +35 -7
  38. data/lib/steam/community/l4d/l4d_stats.rb +23 -10
  39. data/lib/steam/community/l4d/l4d_weapon.rb +11 -7
  40. data/lib/steam/community/portal2/portal2_inventory.rb +4 -0
  41. data/lib/steam/community/portal2/portal2_item.rb +13 -1
  42. data/lib/steam/community/portal2/portal2_stats.rb +10 -6
  43. data/lib/steam/community/steam_game.rb +74 -0
  44. data/lib/steam/community/steam_group.rb +48 -14
  45. data/lib/steam/community/steam_id.rb +295 -64
  46. data/lib/steam/community/tf2/tf2_class.rb +66 -7
  47. data/lib/steam/community/tf2/tf2_class_factory.rb +14 -7
  48. data/lib/steam/community/tf2/tf2_engineer.rb +26 -6
  49. data/lib/steam/community/tf2/tf2_golden_wrench.rb +37 -10
  50. data/lib/steam/community/tf2/tf2_inventory.rb +4 -0
  51. data/lib/steam/community/tf2/tf2_item.rb +13 -1
  52. data/lib/steam/community/tf2/tf2_medic.rb +20 -5
  53. data/lib/steam/community/tf2/tf2_sniper.rb +15 -5
  54. data/lib/steam/community/tf2/tf2_spy.rb +20 -6
  55. data/lib/steam/community/tf2/tf2_stats.rb +20 -6
  56. data/lib/steam/community/web_api.rb +50 -32
  57. data/lib/steam/packets/c2m_checkmd5_packet.rb +1 -1
  58. data/lib/steam/packets/m2a_server_batch_packet.rb +3 -2
  59. data/lib/steam/packets/m2s_requestrestart_packet.rb +3 -3
  60. data/lib/steam/packets/rcon/rcon_packet_factory.rb +4 -4
  61. data/lib/steam/packets/request_with_challenge.rb +1 -1
  62. data/lib/steam/packets/s2a_info_base_packet.rb +1 -1
  63. data/lib/steam/packets/s2a_info_detailed_packet.rb +10 -10
  64. data/lib/steam/packets/s2a_player_packet.rb +5 -1
  65. data/lib/steam/packets/s2a_rules_packet.rb +4 -3
  66. data/lib/steam/packets/s2m_heartbeat2_packet.rb +2 -2
  67. data/lib/steam/packets/steam_packet.rb +1 -1
  68. data/lib/steam/packets/steam_packet_factory.rb +12 -16
  69. data/lib/steam/servers/game_server.rb +38 -32
  70. data/lib/steam/servers/goldsrc_server.rb +10 -1
  71. data/lib/steam/servers/master_server.rb +42 -21
  72. data/lib/steam/servers/server.rb +4 -5
  73. data/lib/steam/servers/source_server.rb +20 -5
  74. data/lib/steam/sockets/goldsrc_socket.rb +53 -22
  75. data/lib/steam/sockets/master_server_socket.rb +14 -4
  76. data/lib/steam/sockets/rcon_socket.rb +39 -6
  77. data/lib/steam/sockets/source_socket.rb +19 -15
  78. data/lib/steam/sockets/steam_socket.rb +33 -23
  79. data/lib/steam/steam_player.rb +86 -11
  80. data/lib/steam-condenser/community.rb +24 -24
  81. data/lib/steam-condenser/servers.rb +2 -2
  82. data/lib/steam-condenser/version.rb +3 -3
  83. data/steam-condenser.gemspec +23 -0
  84. data/test/query_tests.rb +12 -12
  85. data/test/rcon_tests.rb +3 -3
  86. data/test/steam/communtiy/steam_community_test_suite.rb +12 -0
  87. data/test/steam/communtiy/steam_group_tests.rb +6 -5
  88. data/test/steam/communtiy/steam_id_tests.rb +6 -5
  89. data/test/steam_community_tests.rb +3 -3
  90. data/test/stringio_additions_tests.rb +7 -7
  91. metadata +61 -43
  92. data/lib/exceptions/timeout_exception.rb +0 -24
  93. data/test/datagram_channel_tests.rb +0 -42
  94. data/test/socket_channel_tests.rb +0 -43
@@ -1,32 +1,37 @@
1
1
  # This code is free software; you can redistribute it and/or modify it under
2
2
  # the terms of the new BSD License.
3
3
  #
4
- # Copyright (c) 2010, Sebastian Staudt
4
+ # Copyright (c) 2010-2011, Sebastian Staudt
5
5
 
6
- require 'json'
6
+ require 'multi_json'
7
7
  require 'open-uri'
8
8
 
9
- require 'exceptions/web_api_exception'
9
+ require 'errors/web_api_error'
10
10
 
11
- # This adds support for Steam Web API to classes needing this functionality.
11
+ # This module provides functionality for accessing Steam's Web API
12
+ #
12
13
  # The Web API requires you to register a domain with your Steam account to
13
14
  # acquire an API key. See http://steamcommunity.com/dev for further details.
15
+ #
16
+ # @author Sebastian
14
17
  module WebApi
15
18
 
16
- @@api_key = nil
17
-
18
- # Returns the Steam Web API key
19
+ # Returns the Steam Web API key currently used by Steam Condenser
20
+ #
21
+ # @return [String] The currently active Steam Web API key
19
22
  def self.api_key
20
23
  @@api_key
21
24
  end
22
25
 
23
- # Sets the Steam Web API key.
26
+ # Sets the Steam Web API key
24
27
  #
25
- # [+api_key+] The 128bit API key that has to be requested from
26
- # http://steamcommunity.com/dev
28
+ # @param [String] api_key The 128bit API key as a hexadecimal string that has
29
+ # to be requested from http://steamcommunity.com/dev
30
+ # @raise [WebApiError] if the given API key is not a valid 128bit hexadecimal
31
+ # string
27
32
  def self.api_key=(api_key)
28
33
  unless api_key.nil? || api_key.match(/^[0-9A-F]{32}$/)
29
- raise WebApiException.new(:invalid_key)
34
+ raise WebApiError, :invalid_key
30
35
  end
31
36
 
32
37
  @@api_key = api_key
@@ -36,44 +41,57 @@ module WebApi
36
41
  # and version. Additional parameters are supplied via HTTP GET.
37
42
  # Data is returned as a JSON-encoded string.
38
43
  #
39
- # [+interface+] The Web API interface to call, e.g. +ISteamUser+
40
- # [+method+] The Web API method to call, e.g. +GetPlayerSummaries+
41
- # [+version+] The API method version to use (default: 1)
42
- # [+params+] A Hash of additional parameters to supply via HTTP GET
44
+ # @param [String] interface The Web API interface to call, e.g. `ISteamUser`
45
+ # @param [String] method The Web API method to call, e.g.
46
+ # `GetPlayerSummaries`
47
+ # @param [Fixnum] version The API method version to use
48
+ # @param [Hash<Symbol, Object>] params Additional parameters to supply via
49
+ # HTTP GET
50
+ # @raise [WebApiError] if the request to Steam's Web API fails
51
+ # @return [String] The raw JSON data replied to the request
43
52
  def self.json(interface, method, version = 1, params = nil)
44
- load(:json, interface, method, version, params)
53
+ get(:json, interface, method, version, params)
45
54
  end
46
55
 
47
56
  # Fetches JSON data from Steam Web API using the specified interface, method
48
57
  # and version. Additional parameters are supplied via HTTP GET.
49
58
  # Data is returned as a Hash containing the JSON data.
50
59
  #
51
- # [+interface+] The Web API interface to call, e.g. +ISteamUser+
52
- # [+method+] The Web API method to call, e.g. +GetPlayerSummaries+
53
- # [+version+] The API method version to use (default: 1)
54
- # [+params+] A Hash of additional parameters to supply via HTTP GET
60
+ # @param [String] interface The Web API interface to call, e.g. `ISteamUser`
61
+ # @param [String] method The Web API method to call, e.g.
62
+ # `GetPlayerSummaries`
63
+ # @param [Fixnum] version The API method version to use
64
+ # @param [Hash<Symbol, Object>] params Additional parameters to supply via
65
+ # HTTP GET
66
+ # @raise [WebApiError] if the request to Steam's Web API fails
67
+ # @return [Hash<Symbol, Object>] The JSON data replied to the request
55
68
  def self.json!(interface, method, version = 1, params = nil)
56
69
  data = json(interface, method, version, params)
57
- result = JSON.parse(data, { :symbolize_names => true })[:result]
70
+ result = MultiJson.decode(data, { :symbolize_keys => true })[:result]
58
71
 
59
72
  status = result[:status]
60
73
  if status != 1
61
- raise WebApiException.new(:status_bad, status, result[:statusDetail])
74
+ raise WebApiError.new :status_bad, status, result[:statusDetail]
62
75
  end
63
76
 
64
77
  result
65
78
  end
66
79
 
67
80
  # Fetches data from Steam Web API using the specified interface, method and
68
- # version. Additional parameters are supplied via HTTP GET.
69
- # Data is returned as a String in the given format.
81
+ # version. Additional parameters are supplied via HTTP GET. Data is returned
82
+ # as a string in the given format.
70
83
  #
71
- # [+format+] The format to load from the API ('json', 'vdf', or 'xml')
72
- # [+interface+] The Web API interface to call, e.g. +ISteamUser+
73
- # [+method+] The Web API method to call, e.g. +GetPlayerSummaries+
74
- # [+version+] The API method version to use (default: 1)
75
- # [+params+] A Hash of additional parameters to supply via HTTP GET
76
- def self.load(format, interface, method, version = 1, params = nil)
84
+ # @param [Symbol] format The format to load from the API (`:json`, `:vdf`, or
85
+ # `:xml`)
86
+ # @param [String] interface The Web API interface to call, e.g. `ISteamUser`
87
+ # @param [String] method The Web API method to call, e.g.
88
+ # `GetPlayerSummaries`
89
+ # @param [Fixnum] version The API method version to use
90
+ # @param [Hash<Symbol, Object>] params Additional parameters to supply via
91
+ # HTTP GET
92
+ # @raise [WebApiError] if the request to Steam's Web API fails
93
+ # @return [String] The data as replied by the Web API in the desired format
94
+ def self.get(format, interface, method, version = 1, params = nil)
77
95
  version = version.to_s.rjust(4, '0')
78
96
  url = "http://api.steampowered.com/#{interface}/#{method}/v#{version}/"
79
97
  params = {} unless params.is_a?(Hash)
@@ -89,8 +107,8 @@ module WebApi
89
107
  rescue OpenURI::HTTPError
90
108
  status = $!.io.status[0]
91
109
  status = [status, ''] unless status.is_a? Array
92
- raise WebApiException.new(:unauthorized) if status[0].to_i == 401
93
- raise WebApiException.new(:http_error, status[0].to_i, status[1])
110
+ raise WebApiError, :unauthorized if status[0].to_i == 401
111
+ raise WebApiError.new :http_error, status[0].to_i, status[1]
94
112
  end
95
113
  end
96
114
 
@@ -22,7 +22,7 @@ class C2M_CHECKMD5_Packet
22
22
 
23
23
  # Returns the raw data representing this packet
24
24
  #
25
- # @return string A string containing the raw data of this request packet
25
+ # @return [String] A string containing the raw data of this request packet
26
26
  def to_s
27
27
  [@header_data, 0xFF].pack('c2')
28
28
  end
@@ -3,6 +3,7 @@
3
3
  #
4
4
  # Copyright (c) 2008-2011, Sebastian Staudt
5
5
 
6
+ require 'errors/packet_format_error'
6
7
  require 'steam/packets/steam_packet'
7
8
 
8
9
  # This packet class represents a M2A_SERVER_BATCH response replied by a master
@@ -26,12 +27,12 @@ class M2A_SERVER_BATCH_Packet
26
27
  # Creates a new M2A_SERVER_BATCH response object based on the given data
27
28
  #
28
29
  # @param [String] data The raw packet data replied from the server
29
- # @raises PacketFormatException if the packet data is not well formatted
30
+ # @raise [PacketFormatError] if the packet data is not well formatted
30
31
  def initialize(data)
31
32
  super M2A_SERVER_BATCH_HEADER, data
32
33
 
33
34
  unless @content_data.byte == 0x0A
34
- raise PacketFormatException.new('Master query response is missing additional 0x0A byte.')
35
+ raise PacketFormatError, 'Master query response is missing additional 0x0A byte.'
35
36
  end
36
37
 
37
38
  @servers = []
@@ -1,5 +1,5 @@
1
- # This code is free software; you can redistribute it and/or modify it under the
2
- # terms of the new BSD License.
1
+ # This code is free software; you can redistribute it and/or modify it under
2
+ # the terms of the new BSD License.
3
3
  #
4
4
  # Copyright (c) 2011, Sebastian Staudt
5
5
 
@@ -12,7 +12,7 @@ require 'steam/packets/steam_packet'
12
12
  # outdated.
13
13
  #
14
14
  # @author Sebastian Staudt
15
- # @see MasterServer#sendHeartbeat
15
+ # @see MasterServer#send_heartbeat
16
16
  class M2S_REQUESTRESTART_Packet
17
17
 
18
18
  include SteamPacket
@@ -3,8 +3,8 @@
3
3
  #
4
4
  # Copyright (c) 2008-2011, Sebastian Staudt
5
5
 
6
- require 'stringio_additions'
7
- require 'exceptions/packet_format_exception'
6
+ require 'core_ext/stringio'
7
+ require 'errors/packet_format_error'
8
8
  require 'steam/packets/steam_packet_factory'
9
9
  require 'steam/packets/rcon/rcon_auth_response'
10
10
  require 'steam/packets/rcon/rcon_exec_response'
@@ -21,7 +21,7 @@ module RCONPacketFactory
21
21
  # Creates a new packet object based on the header byte of the given raw data
22
22
  #
23
23
  # @param [String] raw_data The raw data of the packet
24
- # @raise [PacketFormatException] if the packet header is not recognized
24
+ # @raise [PacketFormatError] if the packet header is not recognized
25
25
  # @return [RCONPacket] The packet object generated from the packet data
26
26
  def self.packet_from_data(raw_data)
27
27
  byte_buffer = StringIO.new raw_data
@@ -36,7 +36,7 @@ module RCONPacketFactory
36
36
  when RCONPacket::SERVERDATA_RESPONSE_VALUE then
37
37
  return RCONExecResponse.new(request_id, data)
38
38
  else
39
- raise PacketFormatException.new("Unknown packet with header #{header.to_s(16)} received.")
39
+ raise PacketFormatError, "Unknown packet with header #{header.to_s(16)} received."
40
40
  end
41
41
  end
42
42
 
@@ -11,7 +11,7 @@ module RequestWithChallenge
11
11
 
12
12
  # Returns the raw data representing this packet
13
13
  #
14
- # @return string A string containing the raw data of this request packet
14
+ # @return [String] A string containing the raw data of this request packet
15
15
  def to_s
16
16
  [0xFF, 0xFF, 0xFF, 0xFF, @header_data, @content_data.string.to_i].pack('c5l')
17
17
  end
@@ -27,7 +27,7 @@ module S2A_INFO_BasePacket
27
27
  def generate_info_hash
28
28
  @info_hash = Hash[
29
29
  *instance_variables.map { |var|
30
- [var[1..-1], instance_variable_get(var)] if var != '@content_data' && var != '@header_data'
30
+ [var[1..-1].to_sym, instance_variable_get(var)] if var != '@content_data' && var != '@header_data'
31
31
  }.compact.flatten
32
32
  ]
33
33
  end
@@ -3,15 +3,15 @@
3
3
  #
4
4
  # Copyright (c) 2008-2011 Sebastian Staudt
5
5
 
6
- require "steam/packets/s2a_info_base_packet"
6
+ require 'steam/packets/s2a_info_base_packet'
7
7
 
8
8
  # This class represents a S2A_INFO_DETAILED response packet sent by a GoldSrc
9
9
  # server
10
10
  #
11
- # This is deprecated by 10/24/2008. GoldSrc servers use the same format as
12
- # Source servers now (see {S2A_INFO2_Packet}).
13
- #
14
11
  # @author Sebastian Staudt
12
+ # @deprecated Only outdated GoldSrc servers (before 10/24/2008) use this
13
+ # format. Newer ones use the same format as Source servers now (see
14
+ # {S2A_INFO2_Packet}).
15
15
  # @see GameServer#update_server_info
16
16
  class S2A_INFO_DETAILED_Packet
17
17
 
@@ -39,14 +39,14 @@ class S2A_INFO_DETAILED_Packet
39
39
 
40
40
  if @is_mod
41
41
  @mod_info = {}
42
- @mod_info['url_info'] = @content_data.cstring
43
- @mod_info['url_dl'] = @content_data.cstring
42
+ @mod_info[:url_info] = @content_data.cstring
43
+ @mod_info[:url_dl] = @content_data.cstring
44
44
  @content_data.byte
45
45
  if @content_data.remaining == 12
46
- @mod_info['mod_version'] = @content_data.long
47
- @mod_info['mod_size'] = @content_data.long
48
- @mod_info['sv_only'] = @content_data.byte == 1
49
- @mod_info['cl_dll'] = @content_data.byte == 1
46
+ @mod_info[:mod_version] = @content_data.long
47
+ @mod_info[:mod_size] = @content_data.long
48
+ @mod_info[:sv_only] = @content_data.byte == 1
49
+ @mod_info[:cl_dll] = @content_data.byte == 1
50
50
  @secure = @content_data.byte == 1
51
51
  @number_of_bots = @content_data.byte
52
52
  end
@@ -3,6 +3,7 @@
3
3
  #
4
4
  # Copyright (c) 2008-2011, Sebastian Staudt
5
5
 
6
+ require 'errors/packet_format_error'
6
7
  require 'steam/packets/steam_packet'
7
8
 
8
9
  # This class represents a S2A_PLAYER response sent by a game server
@@ -23,8 +24,11 @@ class S2A_PLAYER_Packet
23
24
  # Creates a new S2A_PLAYER response object based on the given data
24
25
  #
25
26
  # @param [String] content_data The raw packet data sent by the server
27
+ # @raise [PacketFormatError] if the packet data is not well formatted
26
28
  def initialize(content_data)
27
- raise Exception.new('Wrong formatted S2A_PLAYER packet.') if content_data.nil?
29
+ if content_data.nil?
30
+ raise PacketFormatError, 'Wrong formatted S2A_PLAYER packet.'
31
+ end
28
32
 
29
33
  super S2A_PLAYER_HEADER, content_data
30
34
 
@@ -25,7 +25,9 @@ class S2A_RULES_Packet
25
25
  #
26
26
  # @param [String] content_data The raw packet data sent by the server
27
27
  def initialize(content_data)
28
- raise Exception.new('Wrong formatted S2A_RULES response packet.') if content_data.nil?
28
+ if content_data.nil?
29
+ raise PacketFormatError, 'Wrong formatted S2A_RULES response packet.'
30
+ end
29
31
 
30
32
  super SteamPacket::S2A_RULES_HEADER, content_data
31
33
 
@@ -37,8 +39,7 @@ class S2A_RULES_Packet
37
39
  rule = @content_data.cstring
38
40
  value = @content_data.cstring
39
41
 
40
- # This is a workaround for servers sending corrupt replies
41
- break if rule.empty? or value.empty?
42
+ break if rule.empty? || value.empty?
42
43
 
43
44
  @rules_hash[rule] = value
44
45
  end
@@ -45,13 +45,13 @@ class S2M_HEARTBEAT2_Packet
45
45
  #
46
46
  # @param [Hash<Symbol, Object>] data The data to send with the heartbeat. The
47
47
  # data contents are merge with the values from {DEFAULT_DATA}.
48
- # @raise [SteamCondenserException] when the required challenge number is
48
+ # @raise [SteamCondenserError] when the required challenge number is
49
49
  # missing
50
50
  def initialize(data = {})
51
51
  data = DEFAULT_DATA.merge data
52
52
 
53
53
  if data[:challenge].nil?
54
- raise SteamCondenserException.new 'You have to provide a challenge number when sending a heartbeat to a master server.'
54
+ raise SteamCondenserError, 'You have to provide a challenge number when sending a heartbeat to a master server.'
55
55
  end
56
56
 
57
57
  bytes = 0x0A.chr
@@ -3,7 +3,7 @@
3
3
  #
4
4
  # Copyright (c) 2008-2011, Sebastian Staudt
5
5
 
6
- require 'stringio_additions'
6
+ require 'core_ext/stringio'
7
7
 
8
8
  # This module implements the basic functionality used by most of the packets
9
9
  # used in communication with master, Source or GoldSrc servers.
@@ -3,7 +3,10 @@
3
3
  #
4
4
  # Copyright (c) 2008-2011, Sebastian Staudt
5
5
 
6
- require 'exceptions/steam_condenser_exception'
6
+ require 'bzip2-ruby'
7
+ require 'zlib'
8
+
9
+ require 'errors/packet_format_error'
7
10
  require 'steam/packets/s2a_info_detailed_packet'
8
11
  require 'steam/packets/a2s_info_packet'
9
12
  require 'steam/packets/s2a_info2_packet'
@@ -31,7 +34,7 @@ module SteamPacketFactory
31
34
  # Creates a new packet object based on the header byte of the given raw data
32
35
  #
33
36
  # @param [String] raw_data The raw data of the packet
34
- # @raise [SteamCondenserException] if the packet header is not recognized
37
+ # @raise [SteamCondenserError] if the packet header is not recognized
35
38
  # @return [SteamPacket] The packet object generated from the packet data
36
39
  def self.packet_from_data(raw_data)
37
40
  header = raw_data[0].ord
@@ -71,7 +74,7 @@ module SteamPacketFactory
71
74
  when SteamPacket::S2A_LOGSTRING_HEADER
72
75
  return S2A_LOGSTRING_Packet.new(data)
73
76
  else
74
- raise SteamCondenserException.new("Unknown packet with header 0x#{header.to_s(16)} received.")
77
+ raise PacketFormatError, "Unknown packet with header 0x#{header.to_s(16)} received."
75
78
  end
76
79
  end
77
80
 
@@ -79,30 +82,23 @@ module SteamPacketFactory
79
82
  # packet object
80
83
  #
81
84
  # @param [Array<String>] split_packets An array of packet data
82
- # @param [true, false] is_compressed whether the data of this packet is
85
+ # @param [Boolean] is_compressed whether the data of this packet is
83
86
  # compressed
84
87
  # @param [Fixnum] packet_checksum The CRC32 checksum of the decompressed
85
88
  # packet data
86
- # @raise [SteamCondenserException] if the bz2 gem is not installed
87
- # @raise [PacketFormatException] if the calculated CRC32 checksum does not
88
- # match the expected value
89
+ # @raise [SteamCondenserError] if the bz2 gem is not installed
90
+ # @raise [PacketFormatError] if the calculated CRC32 checksum does not match
91
+ # the expected value
89
92
  # @return [SteamPacket] The reassembled packet
90
93
  # @see packet_from_data
91
94
  def self.reassemble_packet(split_packets, is_compressed = false, packet_checksum = 0)
92
95
  packet_data = split_packets.join ''
93
96
 
94
97
  if is_compressed
95
- require 'zlib'
96
-
97
- begin
98
- require 'bz2'
99
- packet_data = BZ2.uncompress(packet_data)
100
- rescue LoadError
101
- raise SteamCondenserException.new('You need to install the libbzip2 interface for Ruby.')
102
- end
98
+ packet_data = Bzip2.decompress packet_data
103
99
 
104
100
  unless Zlib.crc32(packet_data) == packet_checksum
105
- raise PacketFormatException.new('CRC32 checksum mismatch of uncompressed packet data.')
101
+ raise PacketFormatError, 'CRC32 checksum mismatch of uncompressed packet data.'
106
102
  end
107
103
  end
108
104
 
@@ -3,7 +3,8 @@
3
3
  #
4
4
  # Copyright (c) 2008-2011, Sebastian Staudt
5
5
 
6
- require 'exceptions/steam_condenser_exception'
6
+ require 'errors/steam_condenser_error'
7
+ require 'errors/timeout_error'
7
8
  require 'steam/steam_player'
8
9
  require 'steam/packets/a2s_info_packet'
9
10
  require 'steam/packets/a2s_player_packet'
@@ -24,11 +25,6 @@ module GameServer
24
25
 
25
26
  include Server
26
27
 
27
- REQUEST_CHALLENGE = 0
28
- REQUEST_INFO = 1
29
- REQUEST_PLAYER = 2
30
- REQUEST_RULES = 3
31
-
32
28
  # Parses the player attribute names supplied by `rcon status`
33
29
  #
34
30
  # @param [String] status_header The header line provided by `rcon status`
@@ -87,9 +83,11 @@ module GameServer
87
83
  # combined with the port number. If a port number is given, e.g.
88
84
  # 'server.example.com:27016' it will override the second argument.
89
85
  # @param [Fixnum] port The port the server is listening on
90
- # @raise [SteamCondenserException] if an host name cannot be resolved
86
+ # @raise [SteamCondenserError] if an host name cannot be resolved
91
87
  def initialize(address, port = 27015)
92
88
  super
89
+
90
+ @rcon_authenticated = false
93
91
  end
94
92
 
95
93
  # Returns the last measured response time of this server
@@ -134,8 +132,13 @@ module GameServer
134
132
  # @return [Boolean] whether the authentication was successful
135
133
  # @see #rcon_exec
136
134
  def rcon_auth(password)
135
+ raise NotImplementedError
137
136
  end
138
137
 
138
+ # Returns whether the RCON connection to this server is already authenticated
139
+ #
140
+ # @return [Boolean] `true` if the RCON connection is authenticated
141
+ # @see #rcon_auth
139
142
  def rcon_authenticated?
140
143
  @rcon_authenticated
141
144
  end
@@ -148,6 +151,7 @@ module GameServer
148
151
  # @return [String] The output of the executed command
149
152
  # @see #rcon_auth
150
153
  def rcon_exec(command)
154
+ raise NotImplementedError
151
155
  end
152
156
 
153
157
  # Returns the settings applied on the server. These settings are also called
@@ -189,30 +193,30 @@ module GameServer
189
193
  # Depending on the given request type this will fill the various data
190
194
  # attributes of the server object.
191
195
  #
192
- # @param [Fixnum] request_type The type of request to send to the server
196
+ # @param [Symbol] request_type The type of request to send to the server
193
197
  # @param [Boolean] repeat_on_failure Whether the request should be repeated,
194
198
  # if the replied packet isn't expected. This is useful to handle
195
199
  # missing challenge numbers, which will be automatically filled in,
196
200
  # although not requested explicitly.
197
- # @raise [SteamCondenserException] if either the request type or the response
201
+ # @raise [SteamCondenserError] if either the request type or the response
198
202
  # packet is not known
199
203
  def handle_response_for_request(request_type, repeat_on_failure = true)
200
204
  begin
201
205
  case request_type
202
- when GameServer::REQUEST_CHALLENGE then
206
+ when :challenge then
203
207
  request_packet = A2S_SERVERQUERY_GETCHALLENGE_Packet.new
204
208
  expected_response = S2C_CHALLENGE_Packet
205
- when GameServer::REQUEST_INFO then
209
+ when :info then
206
210
  request_packet = A2S_INFO_Packet.new
207
211
  expected_response = S2A_INFO_BasePacket
208
- when GameServer::REQUEST_PLAYER then
212
+ when :players then
209
213
  request_packet = A2S_PLAYER_Packet.new(@challenge_number)
210
214
  expected_response = S2A_PLAYER_Packet
211
- when GameServer::REQUEST_RULES then
215
+ when :rules then
212
216
  request_packet = A2S_RULES_Packet.new(@challenge_number)
213
217
  expected_response = S2A_RULES_Packet
214
218
  else
215
- raise SteamCondenserException.new("Called with wrong request type.")
219
+ raise SteamCondenserError, 'Called with wrong request type.'
216
220
  end
217
221
 
218
222
  send_request request_packet
@@ -227,14 +231,14 @@ module GameServer
227
231
  elsif response_packet.kind_of? S2C_CHALLENGE_Packet
228
232
  @challenge_number = response_packet.challenge_number
229
233
  else
230
- raise SteamCondenserException.new("Response of type #{response_packet.class} cannot be handled by this method.")
234
+ raise SteamCondenserError, "Response of type #{response_packet.class} cannot be handled by this method."
231
235
  end
232
236
 
233
237
  unless response_packet.kind_of? expected_response
234
238
  puts "Expected #{expected_response}, got #{response_packet.class}." if $DEBUG
235
239
  handle_response_for_request(request_type, false) if repeat_on_failure
236
240
  end
237
- rescue TimeoutException
241
+ rescue SteamCondenser::TimeoutError
238
242
  puts "Expected #{expected_response}, but timed out." if $DEBUG
239
243
  end
240
244
  end
@@ -263,22 +267,24 @@ module GameServer
263
267
  # @see #handle_response_for_request
264
268
  # @see #players
265
269
  def update_players(rcon_password = nil)
266
- handle_response_for_request GameServer::REQUEST_PLAYER
270
+ handle_response_for_request :players
267
271
 
268
- unless rcon_password.nil? || @player_hash.nil? || @player_hash.empty?
272
+ unless @rcon_authenticated
273
+ return if rcon_password.nil?
269
274
  rcon_auth rcon_password
270
- players = rcon_exec('status').lines.select do |line|
271
- line.start_with?('#') && line != "#end\n"
272
- end.map do |line|
273
- line[1..-1].strip
274
- end
275
- attributes = GameServer.player_status_attributes players.shift
275
+ end
276
+
277
+ players = rcon_exec('status').lines.select do |line|
278
+ line.start_with?('#') && line != "#end\n"
279
+ end.map do |line|
280
+ line[1..-1].strip
281
+ end
282
+ attributes = GameServer.player_status_attributes players.shift
276
283
 
277
- players.each do |player|
278
- player_data = GameServer.split_player_status(attributes, player)
279
- if @player_hash.key? player_data[:name]
280
- @player_hash[player_data[:name]].add_info player_data
281
- end
284
+ players.each do |player|
285
+ player_data = GameServer.split_player_status(attributes, player)
286
+ if @player_hash.key? player_data[:name]
287
+ @player_hash[player_data[:name]].add_info player_data
282
288
  end
283
289
  end
284
290
  end
@@ -292,7 +298,7 @@ module GameServer
292
298
  # @see #handle_response_for_request
293
299
  # @see #rules
294
300
  def update_rules
295
- handle_response_for_request GameServer::REQUEST_RULES
301
+ handle_response_for_request :rules
296
302
  end
297
303
 
298
304
  # Sends a A2S_INFO request to the server and updates this server's basic
@@ -305,7 +311,7 @@ module GameServer
305
311
  # @see #handle_response_for_request
306
312
  # @see #server_info
307
313
  def update_server_info
308
- handle_response_for_request GameServer::REQUEST_INFO
314
+ handle_response_for_request :info
309
315
  end
310
316
 
311
317
  # Sends a A2S_SERVERQUERY_GETCHALLENGE request to the server and updates the
@@ -318,7 +324,7 @@ module GameServer
318
324
  # @see #handle_response_for_request
319
325
  # @see #init
320
326
  def update_challenge_number
321
- handle_response_for_request GameServer::REQUEST_CHALLENGE
327
+ handle_response_for_request :challenge
322
328
  end
323
329
 
324
330
  # Sends a A2S_INFO request to the server and measures the time needed for the