blizzard-community-api 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. data/Gemfile +15 -0
  2. data/Gemfile.lock +33 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.rdoc +40 -0
  5. data/Rakefile +46 -0
  6. data/VERSION +1 -0
  7. data/lib/api_enums.rb +65 -0
  8. data/lib/api_request.rb +133 -0
  9. data/lib/api_requestor.rb +5 -0
  10. data/lib/arena_team_request.rb +23 -0
  11. data/lib/authorized_api_request.rb +62 -0
  12. data/lib/blizzard-community-api.rb +101 -0
  13. data/lib/character_classes_request.rb +11 -0
  14. data/lib/character_profile_request.rb +33 -0
  15. data/lib/character_races_request.rb +11 -0
  16. data/lib/configuration.rb +67 -0
  17. data/lib/current_auctions_request.rb +21 -0
  18. data/lib/guild_perks_request.rb +11 -0
  19. data/lib/guild_profile_request.rb +33 -0
  20. data/lib/guild_rewards_request.rb +11 -0
  21. data/lib/item_classes_request.rb +11 -0
  22. data/lib/item_request.rb +21 -0
  23. data/lib/realm_status_request.rb +28 -0
  24. data/spec/api_request_spec.rb +99 -0
  25. data/spec/api_spec.rb +84 -0
  26. data/spec/arena_team_request_spec.rb +46 -0
  27. data/spec/authorized_api_request_spec.rb +78 -0
  28. data/spec/authorized_spec.rb +89 -0
  29. data/spec/character_classes_request_spec.rb +38 -0
  30. data/spec/character_profile_request_spec.rb +92 -0
  31. data/spec/character_races_spec.rb +38 -0
  32. data/spec/current_auctions_request_spec.rb +41 -0
  33. data/spec/guild_perks_request_spec.rb +33 -0
  34. data/spec/guild_profile_request_spec.rb +59 -0
  35. data/spec/guild_rewards_request_spec.rb +54 -0
  36. data/spec/item_classes_request_spec.rb +36 -0
  37. data/spec/item_request_spec.rb +74 -0
  38. data/spec/realm_status_request_spec.rb +57 -0
  39. data/spec/rspec_helper.rb +8 -0
  40. data/spec/rspec_matchers.rb +18 -0
  41. metadata +92 -0
data/Gemfile ADDED
@@ -0,0 +1,15 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+ gem "json", "~> 1.6.3"
6
+
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.6.4"
12
+ gem "rcov", "~> 0.9.11"
13
+ gem "rspec", "~> 2.7.0"
14
+ gem "rdoc", "~> 3.11"
15
+ end
@@ -0,0 +1,33 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.3)
5
+ git (1.2.5)
6
+ jeweler (1.6.4)
7
+ bundler (~> 1.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ json (1.6.3)
11
+ rake (0.9.2.2)
12
+ rcov (0.9.11)
13
+ rdoc (3.11)
14
+ json (~> 1.4)
15
+ rspec (2.7.0)
16
+ rspec-core (~> 2.7.0)
17
+ rspec-expectations (~> 2.7.0)
18
+ rspec-mocks (~> 2.7.0)
19
+ rspec-core (2.7.1)
20
+ rspec-expectations (2.7.0)
21
+ diff-lcs (~> 1.1.2)
22
+ rspec-mocks (2.7.0)
23
+
24
+ PLATFORMS
25
+ ruby
26
+
27
+ DEPENDENCIES
28
+ bundler (~> 1.0.0)
29
+ jeweler (~> 1.6.4)
30
+ json (~> 1.6.3)
31
+ rcov (~> 0.9.11)
32
+ rdoc (~> 3.11)
33
+ rspec (~> 2.7.0)
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Eric Scholz
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,40 @@
1
+ = Blizzard Community API RubyGem (blizzard-community-api-rubygem)
2
+
3
+ This is a ruby client library to proxy requests to the Blizzard Community API. It has been built in a way to allow request creation and execution to happen asynchronously so you can queue up requests and load balance the execution to get around per-ip-address call limits.
4
+
5
+ == Installing
6
+
7
+ This is currently in pre-release. My test coverage is terrible and there may be a few architectural changes before I consider it complete. That being said, you're welcome to download it and use it as it is a functional work.
8
+
9
+ Once I deem the release stable it will be available on popular rubygem distribution sites.
10
+
11
+ == Usage
12
+
13
+ There are requests based off of resources and actions in the API.
14
+ For instance, to access a character's profile you would create a CharacterProfileRequest:
15
+
16
+ # Request a character profile for Aven on Draenor
17
+ request = CharacterProfileRequest.new("Aven","Draenor")
18
+ # Execute the API call (subsequent calls to read on this object will return a stored object)
19
+ request.read
20
+
21
+ # Authorized requests
22
+ auth_request = AuthorizedApiRequest.new(request, "public_key", "private_key")
23
+ auth_request.read
24
+
25
+
26
+ == Contributing to blizzard-community-api-rubygem
27
+
28
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
29
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
30
+ * Fork the project
31
+ * Start a feature/bugfix branch
32
+ * Commit and push until you are happy with your contribution
33
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
34
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
35
+
36
+ == Copyright
37
+
38
+ Copyright (c) 2011 Eric Scholz. See LICENSE.txt for
39
+ further details.
40
+
@@ -0,0 +1,46 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "blizzard-community-api"
18
+ gem.homepage = "http://github.com/escholz/blizzard-community-api-rubygem"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Blizzard Community API Client Library}
21
+ gem.description = %Q{Ruby Implementation of Blizzard's Community API}
22
+ gem.email = "eric.scholz@gmail.com"
23
+ gem.authors = ["Eric Scholz"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::GemcutterTasks.new
27
+
28
+ require 'rspec/core/rake_task'
29
+ RSpec::Core::RakeTask.new(:spec)
30
+ RSpec::Core::RakeTask.new(:rcov) do |rcov|
31
+ rcov.rcov = true
32
+ rcov.rcov_opts = ['--exclude', 'spec']
33
+ rcov.rspec_opts = ["-c"]
34
+ end
35
+
36
+ task :default => :spec
37
+
38
+ require 'rdoc/task'
39
+ RDoc::Task.new do |rdoc|
40
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
41
+
42
+ rdoc.rdoc_dir = 'rdoc'
43
+ rdoc.title = "battle.net #{version}"
44
+ rdoc.rdoc_files.include('README*')
45
+ rdoc.rdoc_files.include('lib/**/*.rb')
46
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,65 @@
1
+ module WOW
2
+ API_ROOT_PATH = "/api/wow"
3
+
4
+ API_LOCALES = [
5
+ :en_US,
6
+ :es_MX,
7
+ :en_GB,
8
+ :es_ES,
9
+ :fr_FR,
10
+ :ru_RU,
11
+ :de_DE,
12
+ :ko_KR,
13
+ :zh_TW,
14
+ :zh_CN,
15
+ ].freeze()
16
+
17
+ API_HOST_NAMES = {
18
+ :en_US => "us.battle.net",
19
+ :es_MX => "us.battle.net",
20
+ :en_GB => "eu.battle.net",
21
+ :es_ES => "eu.battle.net",
22
+ :fr_FR => "eu.battle.net",
23
+ :ru_RU => "eu.battle.net",
24
+ :de_DE => "eu.battle.net",
25
+ :ko_KR => "kr.battle.net",
26
+ :zh_TW => "tw.battle.net",
27
+ :zh_CN => "battlenet.com.cn",
28
+ }.freeze()
29
+
30
+ CHARACTER_PROFILE_FIELDS = {
31
+ :guild => "guild",
32
+ :items => "items",
33
+ :professions => "professions",
34
+ :reputation => "reputation",
35
+ :stats => "stats",
36
+ :talents => "talents",
37
+ :titles => "titles",
38
+ :appearance => "appearance",
39
+ :companions => "companions",
40
+ :mounts => "mounts",
41
+ :pets => "pets",
42
+ :achievements => "achievements",
43
+ :progression => "progression",
44
+ :pvp => "pvp",
45
+ :quests => "quests",
46
+ }.freeze()
47
+
48
+ GUILD_PROFILE_FIELDS = {
49
+ :members => "members",
50
+ :achievements => "achievements",
51
+ }.freeze()
52
+
53
+ ARENA_TEAM_SIZES = [
54
+ "2v2",
55
+ "3v3",
56
+ "4v4",
57
+ "5v5",
58
+ ].freeze()
59
+
60
+ class HttpClientError < RuntimeError
61
+ end
62
+
63
+ class HttpServerError < RuntimeError
64
+ end
65
+ end
@@ -0,0 +1,133 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require 'openssl'
4
+ require "json"
5
+ require "api_enums"
6
+ require "configuration"
7
+
8
+ module WOW
9
+ class ApiRequest
10
+ def invoke(options={})
11
+ if(options[:force_refresh] || @json_response.nil?)
12
+ raw_response = get_response(options)
13
+ return nil if(raw_response.nil?)
14
+ @json_response = JSON.parse(raw_response)
15
+ if (@json_response.has_key?('Error'))
16
+ raise(RuntimeError, "JsonParsingError: #{@json_response['Error']}")
17
+ end
18
+ end
19
+ @json_response
20
+ end
21
+
22
+ def initialize(options={})
23
+ @options = options
24
+ end
25
+
26
+ def locale
27
+ @options[:locale] ||= WOW::Configuration.default_locale
28
+ end
29
+
30
+ def last_modified
31
+ @options[:last_modified] ||= Time.at(0)
32
+ end
33
+
34
+ def uri
35
+ URI.parse("#{scheme}://#{hostname}#{path}#{hash_to_query_string(query)}")
36
+ end
37
+
38
+ def scheme
39
+ "http"
40
+ end
41
+
42
+ def hostname
43
+ API_HOST_NAMES[locale]
44
+ end
45
+
46
+ def path
47
+ API_ROOT_PATH
48
+ end
49
+
50
+ def query
51
+ {}
52
+ end
53
+
54
+ def headers
55
+ { "Date" => time_to_http_time(Time.now), "If-Modified-Since" => time_to_http_time(last_modified) }
56
+ end
57
+
58
+ protected
59
+
60
+ def use_ssl
61
+ false
62
+ end
63
+
64
+ def get_request
65
+ Net::HTTP::Get.new(uri.request_uri, headers)
66
+ end
67
+
68
+ def get_response(options={})
69
+ begin
70
+ http_response = nil
71
+ Net::HTTP::Proxy(get_proxy_host(options),
72
+ get_proxy_port(options),
73
+ get_proxy_username(options),
74
+ get_proxy_password(options)).start(uri.host,
75
+ uri.port,
76
+ {
77
+ :use_ssl => use_ssl,
78
+ :verify_mode => OpenSSL::SSL::VERIFY_NONE
79
+ }) do |http|
80
+ http_response = http.request(get_request)
81
+ end
82
+ if (http_response.kind_of?(Net::HTTPSuccess)) # 2XX
83
+ return http_response.body
84
+ elsif (http_response.kind_of?(Net::HTTPNotModified)) # 304
85
+ return nil # No Data
86
+ elsif (http_response.kind_of?(Net::HTTPClientError)) # 4XX
87
+ raise(HttpClientError, http_response.body)
88
+ elsif (http_response.kind_of?(Net::HTTPServerError)) # 5XX
89
+ raise(HttpServerError, http_response.body)
90
+ end
91
+ raise(RuntimeError, "Unknown Error")
92
+ rescue Timeout::Error => e
93
+ raise(e)
94
+ end
95
+ end
96
+
97
+ def get_proxy_host(options)
98
+ options[:proxy_host] ||= WOW::Configuration.default_proxy_host
99
+ end
100
+
101
+ def get_proxy_port(options)
102
+ options[:proxy_port] ||= WOW::Configuration.default_proxy_port
103
+ end
104
+
105
+ def get_proxy_username(options)
106
+ options[:proxy_username] ||= WOW::Configuration.default_proxy_username
107
+ end
108
+
109
+ def get_proxy_password(options)
110
+ options[:proxy_password] ||= WOW::Configuration.default_proxy_password
111
+ end
112
+
113
+ def time_to_http_time(time)
114
+ time.utc.strftime("%a, %d %b %Y %R:%S GMT")
115
+ end
116
+
117
+ def hash_to_query_string(hash)
118
+ "?" + hash.collect { |k,v| "#{uri_encode(k)}=#{uri_encode(v)}" }.join("&") unless(hash.empty?)
119
+ end
120
+
121
+ def uri_encode(raw)
122
+ if (raw.is_a?(Symbol))
123
+ return uri_encode(raw.to_s)
124
+ end
125
+ if (raw.is_a?(String))
126
+ return URI.escape(raw, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
127
+ end
128
+ if (raw.is_a?(Array))
129
+ return raw.collect { |v| uri_encode(v) }.join(",")
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,5 @@
1
+ module WOW
2
+ class ApiRequestor
3
+
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ require 'api_request'
2
+
3
+ module WOW
4
+ class ArenaTeamRequest < ApiRequest
5
+
6
+ def initialize(realm, team_size, team_name, options={})
7
+ super(options)
8
+ if(!realm.is_a?(String) || realm.empty? || !team_size.is_a?(String) || team_size.empty? || !team_name.is_a?(String) || team_name.empty?)
9
+ raise(SyntaxError, "Realm, TeamSize and TeamName must be non-empty string values")
10
+ end
11
+ @realm = realm
12
+ @team_size = team_size
13
+ @team_name = team_name
14
+ end
15
+
16
+ attr_reader :realm, :team_size, :team_name
17
+
18
+ def path
19
+ "#{super}/arena/#{uri_encode(realm)}/#{uri_encode(team_size)}/#{uri_encode(team_name)}"
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,62 @@
1
+ require "api_request"
2
+ require "base64"
3
+ require "openssl"
4
+
5
+ module WOW
6
+ ### Example of Authenticated Api Use:
7
+ ### character_api_request = BattleNet::Character.profile("Aven","Draenor",:fields => [:stats, :talents])
8
+ ### character_api_request_with_auth = AuthorizedApiRequest.new(character_api_request, "public_key", "private_key")
9
+ ### character_hash = character_api_request_with_auth.read
10
+ class AuthorizedApiRequest < ApiRequest
11
+
12
+ def initialize(api_request, public_key, private_key)
13
+ @api_request = api_request
14
+ @public_key = public_key
15
+ @private_key = private_key
16
+ end
17
+
18
+ def scheme
19
+ "https"
20
+ end
21
+
22
+ def locale
23
+ @api_request.locale
24
+ end
25
+
26
+ def hostname
27
+ @api_request.hostname
28
+ end
29
+
30
+ def path
31
+ @api_request.path
32
+ end
33
+
34
+ def query
35
+ @api_request.query
36
+ end
37
+
38
+ def last_modified
39
+ @api_request.last_modified
40
+ end
41
+
42
+ def headers
43
+ @api_request.headers.merge({ "Authorization" => authorization_header })
44
+ end
45
+
46
+ protected
47
+
48
+ def use_ssl
49
+ true
50
+ end
51
+
52
+ private
53
+
54
+ def authorization_header
55
+ "BNET #{@public_key}:#{signature}"
56
+ end
57
+
58
+ def signature
59
+ Base64.encode64((OpenSSL::HMAC.new(@private_key,"sha1") << "GET\n#{@api_request.headers["Date"]}\n#{uri.path}\n").digest)
60
+ end
61
+ end
62
+ end