blizzard_api 0.2.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.
Files changed (64) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.gitlab-ci.yml +28 -0
  4. data/.rubocop.yml +13 -0
  5. data/.rubocop_todo.yml +7 -0
  6. data/.travis.yml +7 -0
  7. data/CHANGELOG.md +4 -0
  8. data/Gemfile +8 -0
  9. data/Gemfile.lock +44 -0
  10. data/LICENSE.txt +21 -0
  11. data/README.md +208 -0
  12. data/Rakefile +12 -0
  13. data/bin/console +14 -0
  14. data/bin/setup +8 -0
  15. data/blizzard_api.gemspec +42 -0
  16. data/lib/blizzard_api.rb +14 -0
  17. data/lib/blizzard_api/configuration.rb +82 -0
  18. data/lib/blizzard_api/diablo.rb +76 -0
  19. data/lib/blizzard_api/diablo/community/act.rb +35 -0
  20. data/lib/blizzard_api/diablo/community/artisan.rb +38 -0
  21. data/lib/blizzard_api/diablo/community/character.rb +38 -0
  22. data/lib/blizzard_api/diablo/community/follower.rb +25 -0
  23. data/lib/blizzard_api/diablo/community/item.rb +26 -0
  24. data/lib/blizzard_api/diablo/community/item_type.rb +35 -0
  25. data/lib/blizzard_api/diablo/community/profile.rb +77 -0
  26. data/lib/blizzard_api/diablo/game_data/era.rb +21 -0
  27. data/lib/blizzard_api/diablo/game_data/generic_data_endpoint.rb +58 -0
  28. data/lib/blizzard_api/diablo/game_data/season.rb +21 -0
  29. data/lib/blizzard_api/diablo/request.rb +15 -0
  30. data/lib/blizzard_api/exception.rb +12 -0
  31. data/lib/blizzard_api/request.rb +182 -0
  32. data/lib/blizzard_api/starcraft.rb +40 -0
  33. data/lib/blizzard_api/starcraft/community/account.rb +23 -0
  34. data/lib/blizzard_api/starcraft/community/ladder.rb +34 -0
  35. data/lib/blizzard_api/starcraft/community/profile.rb +76 -0
  36. data/lib/blizzard_api/starcraft/game_data/league.rb +27 -0
  37. data/lib/blizzard_api/starcraft/request.rb +36 -0
  38. data/lib/blizzard_api/version.rb +6 -0
  39. data/lib/blizzard_api/wow.rb +167 -0
  40. data/lib/blizzard_api/wow/community/achievements.rb +45 -0
  41. data/lib/blizzard_api/wow/community/auction.rb +25 -0
  42. data/lib/blizzard_api/wow/community/boss.rb +35 -0
  43. data/lib/blizzard_api/wow/community/challenge.rb +35 -0
  44. data/lib/blizzard_api/wow/community/character.rb +103 -0
  45. data/lib/blizzard_api/wow/community/guild.rb +67 -0
  46. data/lib/blizzard_api/wow/community/item.rb +46 -0
  47. data/lib/blizzard_api/wow/community/mount.rb +24 -0
  48. data/lib/blizzard_api/wow/community/pets.rb +85 -0
  49. data/lib/blizzard_api/wow/community/pvp.rb +34 -0
  50. data/lib/blizzard_api/wow/community/quest.rb +25 -0
  51. data/lib/blizzard_api/wow/community/recipe.rb +25 -0
  52. data/lib/blizzard_api/wow/community/spell.rb +25 -0
  53. data/lib/blizzard_api/wow/community/zone.rb +35 -0
  54. data/lib/blizzard_api/wow/game_data/connected_realm.rb +37 -0
  55. data/lib/blizzard_api/wow/game_data/generic_data_endpoint.rb +58 -0
  56. data/lib/blizzard_api/wow/game_data/mythic_keystone_affix.rb +23 -0
  57. data/lib/blizzard_api/wow/game_data/playable_class.rb +62 -0
  58. data/lib/blizzard_api/wow/game_data/playable_specialization.rb +70 -0
  59. data/lib/blizzard_api/wow/game_data/power_type.rb +23 -0
  60. data/lib/blizzard_api/wow/game_data/race.rb +51 -0
  61. data/lib/blizzard_api/wow/game_data/realm.rb +48 -0
  62. data/lib/blizzard_api/wow/game_data/region.rb +49 -0
  63. data/lib/blizzard_api/wow/request.rb +16 -0
  64. metadata +198 -0
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlizzardApi
4
+ module Diablo
5
+ ##
6
+ # This class allows access to Diablo III era data
7
+ #
8
+ # @see https://develop.battle.net/documentation/api-reference/diablo-3-game-data-api
9
+ #
10
+ # You can get an instance of this class using the default region as follows:
11
+ # api_instance = BlizzardApi::Diablo.era
12
+ class Era < Diablo::GenericDataEndpoint
13
+ protected
14
+
15
+ def endpoint_setup
16
+ @endpoint = 'era'
17
+ @ttl = CACHE_TRIMESTER
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlizzardApi
4
+ module Diablo
5
+ # Generic endpoint to support most data requests with minor configurations
6
+ class GenericDataEndpoint < Diablo::Request
7
+ def initialize(region = nil)
8
+ super region
9
+ endpoint_setup
10
+ @ttl ||= CACHE_DAY
11
+ end
12
+
13
+ ##
14
+ # Get information about the resource
15
+ #
16
+ # @!macro request_options
17
+ #
18
+ # @!macro response
19
+ def index(options = {})
20
+ api_request "#{base_url(:game_data)}/#{@endpoint}/", default_options.merge(options)
21
+ end
22
+
23
+ ##
24
+ # Fetch all possible data for one of items listed by the {#index} using its *id*
25
+ #
26
+ # @param [Integer] id One of the IDs returned by the {#index}
27
+ # @!macro request_options
28
+ #
29
+ # @!macro response
30
+ def get(id, options = {})
31
+ api_request "#{base_url(:game_data)}/#{@endpoint}/#{id}", default_options.merge(options)
32
+ end
33
+
34
+ ##
35
+ # Fetch leaderboard data for the current endpoint
36
+ #
37
+ # @param [Integer] id One of the IDs returned by the {index}
38
+ # @param [Integer] leaderboard_id Leaderboard id
39
+ # @!macro request_options
40
+ #
41
+ # @!macro response
42
+ def leaderboard(id, leaderboard_id, options = {})
43
+ opts = default_options.merge(options)
44
+ api_request "#{base_url(:game_data)}/#{@endpoint}/#{id}/leaderboard/#{leaderboard_id}", opts
45
+ end
46
+
47
+ protected
48
+
49
+ def endpoint_setup
50
+ raise NotImplementedError
51
+ end
52
+
53
+ def default_options
54
+ { ttl: @ttl }
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlizzardApi
4
+ module Diablo
5
+ ##
6
+ # This class allows access to Diablo III season data
7
+ #
8
+ # @see https://develop.battle.net/documentation/api-reference/diablo-3-game-data-api
9
+ #
10
+ # You can get an instance of this class using the default region as follows:
11
+ # api_instance = BlizzardApi::Diablo.season
12
+ class Season < Diablo::GenericDataEndpoint
13
+ protected
14
+
15
+ def endpoint_setup
16
+ @endpoint = 'season'
17
+ @ttl = CACHE_TRIMESTER
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlizzardApi
4
+ module Diablo
5
+ # World of Warcraft requests
6
+ class Request < BlizzardApi::Request
7
+ ##
8
+ # @!macro regions
9
+ def initialize(region = nil)
10
+ super region
11
+ @game = 'd3'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # API Exception
5
+ class ApiException < RuntimeError
6
+ attr_reader :code
7
+
8
+ def initialize(msg = '', code = nil)
9
+ @code = code
10
+ super msg
11
+ end
12
+ end
@@ -0,0 +1,182 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @!macro [new] request_options
5
+ # @param {Hash} options You can specify some options
6
+ # @option options [String] :region Overrides the default region for a single call
7
+ # @option options [String] :locale Overrides the default locale for a single call
8
+ # @option options [String] :namespace Overrides the default namespace for a single call
9
+ # @option options [String] :access_token Overrides the access_token for a single call
10
+ # @option options [Boolean] :ignore_cache If set to true the request will not use the cache
11
+ # @option options [Integer] :ttl Override the default time (in seconds) a request should be cached
12
+
13
+ ##
14
+ # @!macro [new] regions
15
+ # @param {Symbol} region One of the valid API regions *:us*, *:eu*, *:ko*, and *:tw*
16
+ # @note This gem do not support nor will support China endpoints
17
+
18
+ ##
19
+ # @!macro [new] response
20
+ # @return [OpenStruct,Array] API Response. The actual type of the returned object depends on the *format* option
21
+ # in the configuration module
22
+
23
+ ##
24
+ # @!macro [new] complete
25
+ # Iterates through the {index} response data and fetch additional information using {get}, it results in a more
26
+ # complete set of data
27
+ # @note IT MAY PERFORM MANY REQUESTS TO FETCH ALL DATA
28
+ # @!macro request_options
29
+ # @!macro response
30
+
31
+ module BlizzardApi
32
+ ##
33
+ # Simplifies the requests to Blizzard APIS
34
+ class Request
35
+ # One minute cache
36
+ CACHE_MINUTE = 60
37
+ # One hour cache
38
+ CACHE_HOUR = 60 * CACHE_MINUTE
39
+ # One day cache
40
+ CACHE_DAY = 24 * CACHE_HOUR
41
+ # One week cache
42
+ CACHE_WEEK = CACHE_DAY * 7
43
+ # One (commercial) month cache
44
+ CACHE_MONTH = CACHE_DAY * 30
45
+ # Three (commercial) months cache
46
+ CACHE_TRIMESTER = CACHE_MONTH * 3
47
+
48
+ ##
49
+ # @!attribute region
50
+ # @return [String] Api region
51
+ attr_accessor :region
52
+
53
+ ##
54
+ # @!macro regions
55
+ def initialize(region = nil)
56
+ self.region = region || BlizzardApi.region
57
+ @redis = Redis.new(host: BlizzardApi.redis_host, port: BlizzardApi.redis_port) if BlizzardApi.use_cache
58
+ # Use the shared access_token, or create one if it doesn't exists. This avoids unnecessary calls to create tokens.
59
+ @access_token = BlizzardApi.access_token || create_access_token
60
+ end
61
+
62
+ require 'net/http'
63
+ require 'uri'
64
+ require 'json'
65
+ require 'redis'
66
+
67
+ protected
68
+
69
+ def base_url(scope)
70
+ case scope
71
+ when :game_data
72
+ "https://#{region}.api.blizzard.com/data/#{@game}"
73
+ when :community
74
+ "https://#{region}.api.blizzard.com/#{@game}"
75
+ when :profile
76
+ "https://#{region}.api.blizzard.com/profile/#{@game}"
77
+ else
78
+ raise ArgumentError
79
+ end
80
+ end
81
+
82
+ ##
83
+ # Returns a valid namespace string for consuming the api endpoints
84
+ #
85
+ # @param [Symbol] scope Scope of the namespace to be used. *:dynamic* or *:static*
86
+ def endpoint_namespace(scope)
87
+ case scope
88
+ when :dynamic
89
+ "dynamic-#{region}"
90
+ when :static
91
+ "static-#{region}"
92
+ else
93
+ raise ArgumentError, 'Invalid namespace scope'
94
+ end
95
+ end
96
+
97
+ def create_access_token
98
+ uri = URI.parse("https://#{BlizzardApi.region}.battle.net/oauth/token")
99
+
100
+ http = Net::HTTP.new(uri.host, uri.port)
101
+ http.use_ssl = true
102
+
103
+ request = Net::HTTP::Post.new(uri.path)
104
+ request.basic_auth(BlizzardApi.app_id, BlizzardApi.app_secret)
105
+ request['Content-Type'] = 'application/x-www-form-urlencoded'
106
+ request.set_form_data grant_type: 'client_credentials'
107
+
108
+ response = http.request(request)
109
+ BlizzardApi.access_token = JSON.parse(response.body)['access_token']
110
+ end
111
+
112
+ def request(url, options = {})
113
+ # Creates the whole url for request
114
+ parsed_url = URI.parse(url)
115
+
116
+ data = options[:ignore_cache] ? nil : find_in_cache(parsed_url.to_s)
117
+ # If data was found that means cache is enabled and valid
118
+ return format_response data if data
119
+
120
+ # Override access_token
121
+ @access_token = options[:access_token] if options.include? :access_token
122
+
123
+ response = consume_api parsed_url
124
+
125
+ unless options[:ignore_cache]
126
+ ttl = options[:ttl] || CACHE_DAY
127
+ save_in_cache parsed_url.to_s, response.body, ttl
128
+ end
129
+
130
+ format_response response.body
131
+ end
132
+
133
+ def api_request(uri, query_string = {})
134
+ # List of request options
135
+ options_key = %i[ignore_cache ttl format access_token]
136
+
137
+ # Separates request options from api fields and options. Any user-defined option will be treated as api field.
138
+ options = query_string.select { |k, _v| query_string.delete(k) || true if options_key.include? k }
139
+
140
+ # In case uri already have query string parameters joins them with &
141
+ if query_string.size.positive?
142
+ query_string = URI.encode_www_form(query_string, false)
143
+ uri = uri.include?('?') ? "#{uri}&#{query_string}" : "#{uri}?#{query_string}"
144
+ end
145
+
146
+ request uri, options
147
+ end
148
+
149
+ private
150
+
151
+ def consume_api(url)
152
+ # Creates a HTTP connection and request to ensure thread safety
153
+ http = Net::HTTP.new(url.host, url.port)
154
+ http.use_ssl = true
155
+ request = Net::HTTP::Get.new(url)
156
+
157
+ # Blizzard API documentation states the preferred way to send the access_token is using Bearer token on header
158
+ request['Authorization'] = "Bearer #{@access_token}"
159
+
160
+ # Executes the request
161
+ http.request(request).tap do |response|
162
+ raise ApiException.new 'Request failed', response.code unless response.code.to_i == 200
163
+ end
164
+ end
165
+
166
+ def save_in_cache(resource_url, data, ttl)
167
+ return nil unless BlizzardApi.use_cache
168
+
169
+ @redis.setex resource_url, ttl, data
170
+ end
171
+
172
+ def find_in_cache(resource_url)
173
+ return false unless BlizzardApi.use_cache
174
+
175
+ @redis.get resource_url if @redis.exists resource_url
176
+ end
177
+
178
+ def format_response(data)
179
+ JSON.parse(data, symbolize_names: true)
180
+ end
181
+ end
182
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlizzardApi
4
+ # Starcraft II related classes
5
+ module Starcraft
6
+ require_relative 'starcraft/request'
7
+
8
+ # Starcraft II data api
9
+ require_relative 'starcraft/game_data/league'
10
+
11
+ ##
12
+ # @return {League}
13
+ def league
14
+ BlizzardApi::Starcraft::League.new
15
+ end
16
+
17
+ # Starcraft community api
18
+ require_relative 'starcraft/community/profile'
19
+ require_relative 'starcraft/community/ladder'
20
+ require_relative 'starcraft/community/account'
21
+
22
+ ##
23
+ # @return {Profile}
24
+ def profile
25
+ BlizzardApi::Starcraft::Profile.new
26
+ end
27
+
28
+ ##
29
+ # @return {Ladder}
30
+ def ladder
31
+ BlizzardApi::Starcraft::Ladder.new
32
+ end
33
+
34
+ ##
35
+ # @return {Account}
36
+ def account
37
+ BlizzardApi::Starcraft::Account.new
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlizzardApi
4
+ module Starcraft
5
+ ##
6
+ # This class allows access to Starcraft II league data
7
+ #
8
+ # @see https://develop.battle.net/documentation/api-reference/starcraft-2-game-data-api
9
+ #
10
+ # You can get an instance of this class using the default region as follows:
11
+ # api_instance = BlizzardApi::Starcraft.account
12
+ class Account < Starcraft::Request
13
+ ##
14
+ # Returns information about a player account
15
+ #
16
+ # @param [Integer] account_id Account ID
17
+ # @!macro request_options
18
+ def player(account_id, options = {})
19
+ api_request "#{base_url(:community)}/player/#{account_id}", { ttl: CACHE_DAY }.merge(options)
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlizzardApi
4
+ module Starcraft
5
+ ##
6
+ # This class allows access to Starcraft II ladder data
7
+ #
8
+ # @see https://develop.battle.net/documentation/api-reference/starcraft-2-game-data-api
9
+ #
10
+ # You can get an instance of this class using the default region as follows:
11
+ # api_instance = BlizzardApi::Starcraft.ladder
12
+ class Ladder < Starcraft::Request
13
+ ##
14
+ # Grandmaster endpoint
15
+ #
16
+ # @!macro sc2_regions
17
+ # @!macro request_options
18
+ def grandmaster(region_id, options = {})
19
+ reg = resolve_region(region_id)
20
+ api_request "#{base_url(:community)}/ladder/grandmaster/#{reg}", { ttl: CACHE_DAY }.merge(options)
21
+ end
22
+
23
+ ##
24
+ # Season endpoint
25
+ #
26
+ # @!macro sc2_regions
27
+ # @!macro request_options
28
+ def season(region_id, options = {})
29
+ reg = resolve_region(region_id)
30
+ api_request "#{base_url(:community)}/ladder/season/#{reg}", { ttl: CACHE_DAY }.merge(options)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BlizzardApi
4
+ module Starcraft
5
+ ##
6
+ # This class allows access to Starcraft II profile data
7
+ #
8
+ # @see https://develop.battle.net/documentation/api-reference/starcraft-2-game-data-api
9
+ #
10
+ # You can get an instance of this class using the default region as follows:
11
+ # api_instance = BlizzardApi::Starcraft.profile
12
+ class Profile < Starcraft::Request
13
+ ##
14
+ # Static profile data
15
+ #
16
+ # @!macro sc2_regions
17
+ # @!macro request_options
18
+ def static(region_id, options = {})
19
+ reg = resolve_region(region_id)
20
+ api_request "#{base_url(:community)}/static/profile/#{reg}", { ttl: CACHE_DAY }.merge(options)
21
+ end
22
+
23
+ ##
24
+ # Metadata
25
+ #
26
+ # @!macro sc2_regions
27
+ # @param [Integer] realm_id Realm ID
28
+ # @param [Integer] profile_id Profile ID
29
+ # @!macro request_options
30
+ def metadata(region_id, realm_id, profile_id, options = {})
31
+ reg = resolve_region(region_id)
32
+ opts = { ttl: CACHE_DAY }.merge(options)
33
+ api_request "#{base_url(:community)}/metadata/profile/#{reg}/#{realm_id}/#{profile_id}", opts
34
+ end
35
+
36
+ ##
37
+ # Profile data
38
+ #
39
+ # @!macro sc2_regions
40
+ # @param [Integer] realm_id Realm ID
41
+ # @param [Integer] profile_id Profile ID
42
+ # @!macro request_options
43
+ def profile(region_id, realm_id, profile_id, options = {})
44
+ reg = resolve_region(region_id)
45
+ opts = { ttl: CACHE_DAY }.merge(options)
46
+ api_request "#{base_url(:community)}/profile/#{reg}/#{realm_id}/#{profile_id}", opts
47
+ end
48
+
49
+ ##
50
+ # Ladder summary
51
+ #
52
+ # @!macro sc2_regions
53
+ # @param [Integer] realm_id Realm ID
54
+ # @param [Integer] profile_id Profile ID
55
+ # @!macro request_options
56
+ def ladder_summary(region_id, realm_id, profile_id, options = {})
57
+ reg = resolve_region(region_id)
58
+ opts = { ttl: CACHE_DAY }.merge(options)
59
+ api_request "#{base_url(:community)}profile/#{reg}/#{realm_id}/#{profile_id}/ladder/summary ", opts
60
+ end
61
+
62
+ ##
63
+ # Ladder data
64
+ #
65
+ # @!macro sc2_regions
66
+ # @param [Integer] realm_id Realm ID
67
+ # @param [Integer] profile_id Profile ID
68
+ # @!macro request_options
69
+ def ladder(region_id, realm_id, profile_id, ladder_id, options = {})
70
+ reg = resolve_region(region_id)
71
+ opts = { ttl: CACHE_DAY }.merge(options)
72
+ api_request "#{base_url(:community)}/profile/#{reg}/#{realm_id}/#{profile_id}/ladder/#{ladder_id}", opts
73
+ end
74
+ end
75
+ end
76
+ end