restiny 5.0.1 → 6.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19b9e9cb2183fde785169d457628f4f7517c74feed228aacee4d45cdfe901fff
4
- data.tar.gz: bebc650be6668d5a46a284a2aeb6912f2309cce7a7100ec4de57d3a95b11805e
3
+ metadata.gz: 7a11b1fe287424ab29d345e8598b810afd733d59f634e00badf837ac7f16ec3d
4
+ data.tar.gz: fb704f715f42ad34aa722435079e7aae31c9660d5b9e7b32e1f0d9e82efafabd
5
5
  SHA512:
6
- metadata.gz: c4fbe785ad70936712f351e1f3453f1915220af599ea9d89a09dc3c67713b208c6232e12d52d20fb25153c6a9b04b706b4bf1b367a2c8ded96a79da10f9764af
7
- data.tar.gz: ed736dce127c0c76cebec7051b89ba02505452a4f9d2aa6bce6beb836b8fc6169586a6970fea1db3387db7700e3cee2b032edcb9952abd7ba9f85940e1a320e4
6
+ metadata.gz: b32846afdb0a3f1d89c837064f2809d772b8eb1d74903ed449484c75c70975a82a367f591c958a217a616fd55066beef55db5fb6fbff8350787dc163ffe04b6b
7
+ data.tar.gz: 2b8b0b66fdaedcf77cb1b3b308ad54aafd92d5aaa175e9238b28d98ce4ad41da9bc6d6fb4e0c4fdd78dd7c23d6de247bdf7263e28ff4fec1723892866ddae596
@@ -9,24 +9,54 @@ module Restiny
9
9
  module Authentication
10
10
  include Base
11
11
 
12
+ CODE_RESPONSE_TYPE = 'code'
13
+ AUTH_CODE_GRANT_TYPE = 'authorization_code'
14
+
12
15
  def get_authorise_url(redirect_url: nil, state: nil)
13
16
  check_oauth_client_id
14
17
 
15
- @oauth_state = state || SecureRandom.hex(15)
18
+ params = {
19
+ response_type: CODE_RESPONSE_TYPE,
20
+ client_id: @oauth_client_id,
21
+ state: state || SecureRandom.hex(15)
22
+ }
16
23
 
17
- params = { response_type: 'code', client_id: @oauth_client_id, state: @oauth_state }
18
24
  params['redirect_url'] = redirect_url unless redirect_url.nil?
19
25
 
20
- auth_connection.build_url("#{BUNGIE_URL}/en/oauth/authorize/", params).to_s
26
+ query = params.map { |k, v| "#{k}=#{v}" }.join('&')
27
+
28
+ "#{BUNGIE_URL}/en/oauth/authorize/?#{query}"
21
29
  end
22
30
 
23
- def request_access_token(code:, redirect_url: nil)
31
+ def request_access_token(code, redirect_url: nil)
24
32
  check_oauth_client_id
25
33
 
26
- params = { code: code, grant_type: 'authorization_code', client_id: @oauth_client_id }
34
+ params = { code: code, grant_type: AUTH_CODE_GRANT_TYPE, client_id: @oauth_client_id }
27
35
  params['redirect_url'] = redirect_url unless redirect_url.nil?
28
36
 
29
- auth_connection.post('app/oauth/token/', params).body
37
+ response = http_client.post('/platform/app/oauth/token/', form: params)
38
+ response.raise_for_status
39
+
40
+ response.json
41
+ rescue HTTPX::Error => e
42
+ handle_authentication_error(e)
43
+ end
44
+
45
+ private
46
+
47
+ def handle_authentication_error(error)
48
+ raise Restiny::AuthenticationError,
49
+ "#{error.response.json['error_description']} (#{error.response.json['error']})"
50
+ rescue HTTPX::Error
51
+ raise Restiny::AuthenticationError,
52
+ "#{error.response.status}: #{error.response.headers['x-selfurl']}"
53
+ end
54
+
55
+ def check_oauth_client_id
56
+ return if @oauth_client_id
57
+
58
+ raise Restiny::RequestError,
59
+ 'You need to set an OAuth client ID (Restiny.oauth_client_id)'
30
60
  end
31
61
  end
32
62
  end
@@ -2,64 +2,71 @@
2
2
 
3
3
  require 'restiny/constants'
4
4
  require 'restiny/errors'
5
- require 'faraday'
6
- require 'faraday/follow_redirects'
7
- require 'faraday/destiny/api'
8
- require 'faraday/destiny/auth'
5
+ require 'httpx'
6
+ require 'json'
9
7
 
10
8
  module Restiny
11
9
  BUNGIE_URL = 'https://www.bungie.net'
12
- API_BASE_URL = "#{BUNGIE_URL}/platform".freeze
13
10
 
14
11
  attr_accessor :api_key, :oauth_state, :oauth_client_id, :access_token, :user_agent
15
12
 
16
13
  module Api
17
14
  module Base
18
- def api_get(endpoint:, params: {})
19
- api_connection.get(endpoint, params, token_header).body
15
+ def get(endpoint)
16
+ make_api_request(endpoint, method: :get)
20
17
  end
21
18
 
22
- def api_post(endpoint:, params: {})
23
- api_connection.post(endpoint, params, token_header).body
19
+ def post(endpoint, params: {})
20
+ make_api_request(endpoint, method: :post, params: params)
24
21
  end
25
22
 
26
23
  private
27
24
 
28
- def check_oauth_client_id
29
- raise Restiny::RequestError, 'You need to set an OAuth client ID' unless @oauth_client_id
25
+ def http_client
26
+ HTTPX.with(origin: BUNGIE_URL, headers: api_headers).plugin(:follow_redirects, follow_insecure_redirects: true)
30
27
  end
31
28
 
32
- def default_headers
33
- { 'User-Agent': @user_agent || "restiny v#{Restiny::VERSION}" }
29
+ def make_api_request(endpoint, method: :get, params: {})
30
+ raise Restiny::InvalidParamsError, 'You need to set an API key (Restiny.api_key)' if @api_key.nil?
31
+
32
+ response = http_client.with(base_path: '/platform/').request(method, endpoint, json: params)
33
+ response.raise_for_status
34
+
35
+ response.json['Response']
36
+ rescue HTTPX::TimeoutError, HTTPX::ResolveError => e
37
+ raise Restiny::RequestError, e.message
38
+ rescue HTTPX::HTTPError => e
39
+ handle_api_error(e)
34
40
  end
35
41
 
36
- def api_connection
37
- raise Restiny::InvalidParamsError, 'You need to set an API key' unless @api_key
42
+ def handle_api_error(error)
43
+ klass = case error.response.status
44
+ when 400..499 then ::Restiny::RequestError
45
+ when 500..599 then ::Restiny::ResponseError
46
+ else ::Restiny::Error
47
+ end
48
+
49
+ raise klass, if error.response.headers['content-type'].match?(%r{^application/json})
50
+ error_message_from_json(error.response.json)
51
+ else
52
+ error.status
53
+ end
54
+ end
38
55
 
39
- @api_connection ||=
40
- Faraday.new(
41
- url: API_BASE_URL,
42
- headers: default_headers.merge('X-API-KEY': @api_key)
43
- ) do |faraday|
44
- faraday.request :json
45
- faraday.response :follow_redirects
46
- faraday.response :destiny_api
47
- faraday.response :json
48
- end
56
+ def error_message_from_json(json)
57
+ "#{json['ErrorStatus']} (#{json['ErrorCode']}): #{json['Message']}"
49
58
  end
50
59
 
51
- def auth_connection
52
- @auth_connection ||=
53
- Faraday.new(url: API_BASE_URL, headers: default_headers) do |faraday|
54
- faraday.request :url_encoded
55
- faraday.response :follow_redirects
56
- faraday.response :destiny_auth
57
- faraday.response :json
58
- end
60
+ def api_headers
61
+ {}.tap do |headers|
62
+ headers['x-api-key'] = @api_key
63
+ headers['user-agent'] = @user_agent || "restiny v#{Restiny::VERSION}"
64
+ headers['authentication'] = "Bearer #{@access_token}" unless @access_token.nil?
65
+ end
59
66
  end
60
67
 
61
- def token_header
62
- {}.tap { |headers| headers['authorization'] = "Bearer #{@access_token}" if @access_token }
68
+ def valid_array_param?(param)
69
+ param.is_a?(Array) && !param.empty?
63
70
  end
64
71
  end
65
72
  end
@@ -2,52 +2,49 @@
2
2
 
3
3
  require_relative 'base'
4
4
 
5
- require 'restiny/manifest'
6
-
7
- require 'down'
8
5
  require 'tmpdir'
9
- require 'zip'
6
+ require 'uri'
10
7
 
11
8
  module Restiny
12
9
  module Api
13
10
  module Manifest
14
11
  include Base
15
12
 
16
- def download_manifest(locale: 'en', force_download: false)
17
- result = api_get(endpoint: 'Destiny2/Manifest/')
18
- raise Restiny::ResponseError, 'Unable to determine manifest details' if result.nil?
19
-
20
- return manifests[locale] if !force_download && manifest_version?(locale, result['version'])
13
+ def fetch_manifest
14
+ result = get('/Destiny2/Manifest/')
15
+ return result unless result.nil?
21
16
 
22
- manifests[locale] = download_manifest_by_url(result.dig('mobileWorldContentPaths', locale), result['version'])
17
+ raise Restiny::ResponseError, 'Unable to fetch manifest details'
23
18
  end
24
19
 
25
- def download_manifest_by_url(url, version)
26
- raise Restiny::RequestError, 'Unknown locale' if url.nil?
27
-
28
- database_file_path = extract_manifest_from_zip_file(Down.download(BUNGIE_URL + url), version)
20
+ def download_manifest_json(locale: 'en', definitions: [])
21
+ raise Restiny::InvalidParamsError, 'No definitions provided' unless valid_array_param?(definitions)
22
+ raise Restiny::InvalidParamsError, 'Unknown definitions provided' unless known_definitions?(definitions)
29
23
 
30
- Restiny::Manifest.new(database_file_path, version)
31
- rescue Down::Error => e
32
- raise Restiny::NetworkError.new('Unable to download the manifest file', e.response.code)
33
- end
24
+ paths = fetch_manifest.dig('jsonWorldComponentContentPaths', locale)
25
+ raise Restiny::ResponseError, "Unable to find manifest JSON for locale '#{locale}'" if paths.nil?
34
26
 
35
- def extract_manifest_from_zip_file(source_path, version)
36
- Zip::File.open(source_path) do |zip_file|
37
- File.join(Dir.tmpdir, "#{version}.en.content.db").tap do |path|
38
- zip_file.first.extract(path) unless File.exist?(path)
27
+ {}.tap do |files|
28
+ definitions.each do |definition|
29
+ files[definition] = download_manifest_json_by_url(BUNGIE_URL + paths[definition])
39
30
  end
40
31
  end
41
- rescue Zip::Error => e
42
- raise Restiny::Error, "Unable to unzip the manifest file (#{e})"
43
32
  end
44
33
 
45
- def manifests
46
- @manifests ||= {}
34
+ def known_definitions?(definitions)
35
+ definitions.difference(Restiny::ManifestDefinition.values).empty?
47
36
  end
48
37
 
49
- def manifest_version?(locale, version)
50
- manifests[locale] && manifests[locale].version == version
38
+ def download_manifest_json_by_url(url)
39
+ filename = URI(url).path.split('/').last
40
+ path = File.join(Dir.tmpdir, filename)
41
+
42
+ HTTPX.get(url).copy_to(path)
43
+ raise Restiny::Error, "Unable to download JSON from #{url}" unless File.exist?(path)
44
+
45
+ path
46
+ rescue HTTPX::Error
47
+ raise Restiny::ResponseError, "Unable to download #{definition} JSON file"
51
48
  end
52
49
  end
53
50
  end
@@ -7,18 +7,23 @@ module Restiny
7
7
  module Membership
8
8
  include Base
9
9
 
10
- def get_user_memberships_by_id(membership_id:, membership_type: Platform::ALL)
10
+ def get_user_memberships_by_id(membership_id, membership_type: Platform::ALL)
11
11
  raise Restiny::InvalidParamsError, 'Please provide a membership ID' if membership_id.nil?
12
+ raise Restiny::InvalidParamsError, 'Please provide a membership type' if membership_type.nil?
12
13
 
13
- api_get(endpoint: "User/GetMembershipsById/#{membership_id}/#{membership_type}/")
14
+ get("/User/GetMembershipsById/#{membership_id}/#{membership_type}/")
14
15
  end
15
16
 
16
- def get_primary_user_membership(membership_id:, use_fallback: true)
17
- result = get_user_memberships_by_id(membership_id: membership_id)
18
- return nil if result.nil? || result['primaryMembershipId'].nil?
17
+ def get_primary_user_membership(membership_id, use_fallback: true)
18
+ raise Restiny::InvalidParamsError, 'Please provide a membership ID' if membership_id.nil?
19
+
20
+ result = get_user_memberships_by_id(membership_id)
21
+ return nil if result.nil?
19
22
 
20
- result['destinyMemberships'].each do |membership|
21
- return membership if membership['membershipID'] == result['primaryMembershipId']
23
+ unless result['primaryMembershipId'].nil?
24
+ result['destinyMemberships'].each do |membership|
25
+ return membership if membership['membershipID'] == result['primaryMembershipId']
26
+ end
22
27
  end
23
28
 
24
29
  result['destinyMemberships'][0] if use_fallback
@@ -8,15 +8,13 @@ module Restiny
8
8
  include Base
9
9
 
10
10
  def get_profile(membership_id:, membership_type:, components:, type_url: nil)
11
- if !components.is_a?(Array) || components.empty?
12
- raise Restiny::InvalidParamsError, 'Please provide at least one component'
13
- end
11
+ raise Restiny::InvalidParamsError, 'No components provided' unless valid_array_param?(components)
14
12
 
15
- url = "Destiny2/#{membership_type}/Profile/#{membership_id}/"
13
+ url = "/Destiny2/#{membership_type}/Profile/#{membership_id}/"
16
14
  url += type_url if type_url
17
15
  url += "?components=#{components.join(',')}"
18
16
 
19
- api_get(endpoint: url)
17
+ get(url)
20
18
  end
21
19
 
22
20
  def get_character_profile(character_id:, membership_id:, membership_type:, components:)
@@ -7,24 +7,19 @@ module Restiny
7
7
  module Search
8
8
  include Base
9
9
 
10
- def search_player_by_bungie_name(name:, membership_type: Platform::ALL)
10
+ def search_player_by_bungie_name(name, membership_type: Platform::ALL)
11
11
  display_name, display_name_code = name.split('#')
12
12
  if display_name.nil? || display_name_code.nil?
13
- raise Restiny::InvalidParamsError,
14
- 'You must provide a valid Bungie name'
13
+ raise Restiny::InvalidParamsError, 'You must provide a valid Bungie name'
15
14
  end
16
15
 
17
- api_post(
18
- endpoint: "Destiny2/SearchDestinyPlayerByBungieName/#{membership_type}/",
19
- params: {
20
- displayName: display_name,
21
- displayNameCode: display_name_code
22
- }
23
- )
16
+ post("/Destiny2/SearchDestinyPlayerByBungieName/#{membership_type}/", params: {
17
+ displayName: display_name, displayNameCode: display_name_code
18
+ })
24
19
  end
25
20
 
26
21
  def search_users_by_global_name(name:, page: 0)
27
- api_post(endpoint: "User/Search/GlobalName/#{page}/", params: { displayNamePrefix: name })
22
+ post("/User/Search/GlobalName/#{page}/", params: { displayNamePrefix: name })
28
23
  end
29
24
  end
30
25
  end
@@ -10,9 +10,9 @@ module Restiny
10
10
  def get_post_game_carnage_report(activity_id:)
11
11
  raise Restiny::InvalidParamsError, 'Please provide an activity ID' if activity_id.nil?
12
12
 
13
- api_get(endpoint: "Destiny2/Stats/PostGameCarnageReport/#{activity_id}/")
14
- end
15
-
13
+ get("/Destiny2/Stats/PostGameCarnageReport/#{activity_id}/")
14
+ end
15
+
16
16
  alias get_pgcr get_post_game_carnage_report
17
17
  end
18
18
  end
@@ -111,7 +111,7 @@ module Restiny
111
111
  end
112
112
  end
113
113
 
114
- # Definitions for the various typos of ammunition in the game.
114
+ # Definitions for the various types of ammunition used in the game.
115
115
  module Ammunition
116
116
  NONE = 0
117
117
  PRIMARY = 1
@@ -132,16 +132,131 @@ module Restiny
132
132
 
133
133
  # Definitions for the various component types used when requesting a profile entry.
134
134
  module ComponentType
135
- CHARACTERS = 'Characters'
136
- CHARACTER_EQUIPMENT = 'CharacterEquipment'
137
- CHARACTER_INVENTORIES = 'CharacterInventories'
138
- CHARACTER_LOADOUTS = 'CharacterLoadouts'
139
- PROFILES = 'Profiles'
140
- PROFILE_INVENTORIES = 'ProfileInventories'
141
- ITEM_INSTANCES = 'ItemInstances'
142
- ITEM_SOCKETS = 'ItemSockets'
143
- ITEM_COMMON_DATA = 'ItemCommonData'
144
- ITEM_PLUG_STATES = 'ItemPlugStates'
145
- ITEM_REUSABLE_PLUGS = 'ItemReusablePlugs'
135
+ PROFILES = '100'
136
+ VENDOR_RECEIPTS = '101'
137
+ PROFILE_INVENTORIES = '102'
138
+ PROFILE_CURRENCIES = '103'
139
+ PROFILE_PROGRESSION = '104'
140
+ PLATFORM_SILVER = '105'
141
+ CHARACTERS = '200'
142
+ CHARACTER_INVENTORIES = '201'
143
+ CHARACTER_PROGRESSIONS = '202'
144
+ CHARACTER_RENDERDATA = '203'
145
+ CHARACTER_ACTIVITIES = '204'
146
+ CHARACTER_EQUIPMENT = '205'
147
+ CHARACTER_LOADOUTS = '206'
148
+ ITEM_INSTANCES = '300'
149
+ ITEM_OBJECTIVES = '301'
150
+ ITEM_PERKS = '302'
151
+ ITEM_RENDER_DATA = '303'
152
+ ITEM_STATS = '304'
153
+ ITEM_SOCKETS = '305'
154
+ ITEM_TALENT_GRIDS = '306'
155
+ ITEM_COMMON_DATA = '307'
156
+ ITEM_PLUG_STATES = '308'
157
+ ITEM_PLUG_OBJECTIVES = '309'
158
+ ITEM_REUSABLE_PLUGS = '310'
159
+ VENDORS = '400'
160
+ VENDOR_CATEGORIES = '401'
161
+ VENDOR_SALES = '402'
162
+ KIOSKS = '500'
163
+ CURRENCY_LOOKUPS = '600'
164
+ PRESENTATION_NODES = '700'
165
+ COLLECTIBLES = '800'
166
+ RECORDS = '900'
167
+ TRANSITORY = '1000'
168
+ METRICS = '1100'
169
+ STRING_VARIABLES = '1200'
170
+ CRAFTABLES = '1300'
171
+ SOCIAL_COMMENDATIONS = '1400'
172
+ end
173
+
174
+ # The categories of data stored in the manifest.
175
+ module ManifestDefinition
176
+ def self.values
177
+ constants.map { |c| const_get(c) }
178
+ end
179
+
180
+ ACHIEVEMENT = 'DestinyAchievementDefinition'
181
+ ACTIVITY = 'DestinyActivityDefinition'
182
+ ACTIVITY_GRAPH = 'DestinyActivityGraphDefinition'
183
+ ACTIVITY_INTERACTABLE = 'DestinyActivityInteractableDefinition'
184
+ ACTIVITY_MODE = 'DestinyActivityModeDefinition'
185
+ ACTIVITY_MODIFIER = 'DestinyActivityModifierDefinition'
186
+ ACTIVITY_TYPE = 'DestinyActivityTypeDefinition'
187
+ ART_DYE_CHANNEL = 'DestinyArtDyeChannelDefinition'
188
+ ART_DYE_REFERENCE = 'DestinyArtDyeReferenceDefinition'
189
+ ARTIFACT = 'DestinyArtifactDefinition'
190
+ BOND = 'DestinyBondDefinition'
191
+ BREAKER_TYPE = 'DestinyBreakerTypeDefinition'
192
+ CHARACTER_CUSTOMIZATION_CATEGORY = 'DestinyCharacterCustomizationCategoryDefinition'
193
+ CHARACTER_CUSTOMIZATION_OPTION = 'DestinyCharacterCustomizationOptionDefinition'
194
+ CHECKLIST = 'DestinyChecklistDefinition'
195
+ CLASS = 'DestinyClassDefinition'
196
+ COLLECTIBLE = 'DestinyCollectibleDefinition'
197
+ DAMAGE_TYPE = 'DestinyDamageTypeDefinition'
198
+ DESTINATION = 'DestinyDestinationDefinition'
199
+ ENERGY_TYPE = 'DestinyEnergyTypeDefinition'
200
+ ENTITLEMENT_OFFER = 'DestinyEntitlementOfferDefinition'
201
+ EQUIPMENT_SLOT = 'DestinyEquipmentSlotDefinition'
202
+ EVENT_CARD = 'DestinyEventCardDefinition'
203
+ FACTION = 'DestinyFactionDefinition'
204
+ GENDER = 'DestinyGenderDefinition'
205
+ GUARDIAN_RANK_CONSTANTS = 'DestinyGuardianRankConstantsDefinition'
206
+ GUARDIAN_RANK = 'DestinyGuardianRankDefinition'
207
+ INVENTORY_BUCKET = 'DestinyInventoryBucketDefinition'
208
+ INVENTORY_ITEM = 'DestinyInventoryItemDefinition'
209
+ INVENTORY_ITEM_LITE = 'DestinyInventoryItemLiteDefinition'
210
+ ITEM_CATEGORY = 'DestinyItemCategoryDefinition'
211
+ ITEM_TIER_TYPE = 'DestinyItemTierTypeDefinition'
212
+ LOADOUT_COLOR = 'DestinyLoadoutColorDefinition'
213
+ LOADOUT_CONSTANTS = 'DestinyLoadoutConstantsDefinition'
214
+ LOADOUT_ICON = 'DestinyLoadoutIconDefinition'
215
+ LOADOUT_NAME = 'DestinyLoadoutNameDefinition'
216
+ LOCATION = 'DestinyLocationDefinition'
217
+ LORE = 'DestinyLoreDefinition'
218
+ MATERIAL_REQUIREMENT_SET = 'DestinyMaterialRequirementSetDefinition'
219
+ MEDAL_TIER = 'DestinyMedalTierDefinition'
220
+ METRIC = 'DestinyMetricDefinition'
221
+ MILESTONE = 'DestinyMilestoneDefinition'
222
+ NODE_STEP_SUMMARY = 'DestinyNodeStepSummaryDefinition'
223
+ OBJECTIVE = 'DestinyObjectiveDefinition'
224
+ PLACE = 'DestinyPlaceDefinition'
225
+ PLATFORM_BUCKET_MAPPING = 'DestinyPlatformBucketMappingDefinition'
226
+ PLUG_SET = 'DestinyPlugSetDefinition'
227
+ POWER_CAP = 'DestinyPowerCapDefinition'
228
+ PRESENTATION_NODE = 'DestinyPresentationNodeDefinition'
229
+ PROGRESSION = 'DestinyProgressionDefinition'
230
+ PROGRESSION_LEVEL_REQUIREMENT = 'DestinyProgressionLevelRequirementDefinition'
231
+ PROGRESSION_MAPPING = 'DestinyProgressionMappingDefinition'
232
+ RACE = 'DestinyRaceDefinition'
233
+ RECORD = 'DestinyRecordDefinition'
234
+ REPORT_REASON_CATEGORY = 'DestinyReportReasonCategoryDefinition'
235
+ REWARD_ADJUSTER_POINTER = 'DestinyRewardAdjusterPointerDefinition'
236
+ REWARD_ADJUSTER_PROGRESSION_MAP = 'DestinyRewardAdjusterProgressionMapDefinition'
237
+ REWARD_ITEM_LIST = 'DestinyRewardItemListDefinition'
238
+ REWARD_MAPPING = 'DestinyRewardMappingDefinition'
239
+ REWARD_SHEET = 'DestinyRewardSheetDefinition'
240
+ REWARD_SOURCE = 'DestinyRewardSourceDefinition'
241
+ SACK_REWARD_ITEM_LIST = 'DestinySackRewardItemListDefinition'
242
+ SANDBOX_PATTERN = 'DestinySandboxPatternDefinition'
243
+ SANDBOX_PERK = 'DestinySandboxPerkDefinition'
244
+ SEASON = 'DestinySeasonDefinition'
245
+ SEASON_PASS = 'DestinySeasonPassDefinition'
246
+ SOCIAL_COMMENDATION = 'DestinySocialCommendationDefinition'
247
+ SOCIAL_COMMENDATION_NODE = 'DestinySocialCommendationNodeDefinition'
248
+ SOCKET_CATEGORY = 'DestinySocketCategoryDefinition'
249
+ SOCKET_TYPE = 'DestinySocketTypeDefinition'
250
+ STAT = 'DestinyStatDefinition'
251
+ STAT_GROUP = 'DestinyStatGroupDefinition'
252
+ TALENT_GRID = 'DestinyTalentGridDefinition'
253
+ TRAIT = 'DestinyTraitDefinition'
254
+ UNLOCK_COUNT_MAPPING = 'DestinyUnlockCountMappingDefinition'
255
+ UNLOCK = 'DestinyUnlockDefinition'
256
+ UNLOCK_EVENT = 'DestinyUnlockEventDefinition'
257
+ UNLOCK_EXPRESSION_MAPPING = 'DestinyUnlockExpressionMappingDefinition'
258
+ UNLOCK_VALUE = 'DestinyUnlockValueDefinition'
259
+ VENDOR = 'DestinyVendorDefinition'
260
+ VENDOR_GROUP = 'DestinyVendorGroupDefinition'
146
261
  end
147
262
  end
@@ -1,28 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Restiny
4
- class Error < StandardError
5
- def initialize(message, status = nil)
6
- @status = status
7
- super(message)
8
- end
9
- end
10
-
11
- class NetworkError < Error
12
- end
13
-
14
- class RequestError < Error
15
- end
16
-
17
- class InvalidParamsError < RequestError
18
- end
19
-
20
- class RateLimitedError < RequestError
21
- end
22
-
23
- class AuthenticationError < RequestError
24
- end
25
-
26
- class ResponseError < Error
27
- end
4
+ class Error < StandardError; end
5
+ class NetworkError < Error; end
6
+ class RequestError < Error; end
7
+ class InvalidParamsError < RequestError; end
8
+ class RateLimitedError < RequestError; end
9
+ class AuthenticationError < RequestError; end
10
+ class ResponseError < Error; end
28
11
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Restiny
4
- VERSION = '5.0.1'
4
+ VERSION = '6.0.0'
5
5
  end
metadata CHANGED
@@ -1,85 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restiny
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.1
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Bogan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-14 00:00:00.000000000 Z
11
+ date: 2023-12-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: down
14
+ name: httpx
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.4'
19
+ version: '1.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '5.4'
27
- - !ruby/object:Gem::Dependency
28
- name: faraday
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '2.0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '2.0'
41
- - !ruby/object:Gem::Dependency
42
- name: faraday-follow_redirects
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.3'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.3'
55
- - !ruby/object:Gem::Dependency
56
- name: rubyzip
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '2.3'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '2.3'
69
- - !ruby/object:Gem::Dependency
70
- name: sqlite3
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '1.3'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: '1.3'
26
+ version: '1.1'
83
27
  description: A gem for interacting with Bungie's Destiny API.
84
28
  email:
85
29
  - d+restiny@waferbaby.com
@@ -87,8 +31,6 @@ executables: []
87
31
  extensions: []
88
32
  extra_rdoc_files: []
89
33
  files:
90
- - lib/faraday/destiny/api.rb
91
- - lib/faraday/destiny/auth.rb
92
34
  - lib/restiny.rb
93
35
  - lib/restiny/api/authentication.rb
94
36
  - lib/restiny/api/base.rb
@@ -99,7 +41,6 @@ files:
99
41
  - lib/restiny/api/stats.rb
100
42
  - lib/restiny/constants.rb
101
43
  - lib/restiny/errors.rb
102
- - lib/restiny/manifest.rb
103
44
  - lib/restiny/version.rb
104
45
  homepage: http://github.com/waferbaby/restiny
105
46
  licenses:
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'faraday'
4
- require 'restiny/errors'
5
-
6
- module Faraday
7
- module Restiny
8
- Faraday::Response.register_middleware(destiny_api: 'Faraday::Restiny::Api')
9
-
10
- class Api < Middleware
11
- def on_complete(env)
12
- return if env['response_body'].empty? || !env['response_body']['ErrorCode']
13
-
14
- if env['response_body']['ErrorCode'] == 1
15
- env[:body] = env['response_body']['Response']
16
- return
17
- end
18
-
19
- klass =
20
- case env['status']
21
- when 400..499
22
- ::Restiny::RequestError
23
- when 500..599
24
- ::Restiny::ResponseError
25
- else
26
- ::Restiny::Error
27
- end
28
-
29
- raise klass.new(env['response_body']['Message'], env['response_body']['ErrorStatus'])
30
- end
31
- end
32
- end
33
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'faraday'
4
- require 'restiny/errors'
5
-
6
- module Faraday
7
- module Restiny
8
- Faraday::Response.register_middleware(destiny_auth: 'Faraday::Restiny::Auth')
9
-
10
- class Auth < Middleware
11
- def on_complete(env)
12
- return if env['response_body'].empty? || env['url'].to_s !~ /oauth/
13
-
14
- return unless env['response_body']['error']
15
-
16
- raise ::Restiny::AuthenticationError.new(
17
- env['response_body']['error_description'],
18
- env['response_body']['error']
19
- )
20
- end
21
- end
22
- end
23
- end
@@ -1,127 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'sqlite3'
4
-
5
- module Restiny
6
- class Manifest
7
- ENTITIES = {
8
- Achievement: %w[achievement achievements],
9
- Activity: %w[activity activities],
10
- ActivityGraph: %w[activity_graph activity_graphs],
11
- ActivityMode: %w[activity_mode activity_modes],
12
- ActivityModifier: %w[activity_modifier activity_modifiers],
13
- ActivityType: %w[activity_type activity_types],
14
- Artifact: %w[artifact artifacts],
15
- Bond: %w[bonds bonds],
16
- BreakerType: %w[breaker_type breaker_types],
17
- Checklist: %w[checklist checklists],
18
- Class: %w[guardian_class guardian_classes],
19
- Collectible: %w[collectible collectibles],
20
- DamageType: %w[damage_type damage_types],
21
- Destination: %w[destination destinations],
22
- EnergyType: %w[energy_type energy_types],
23
- EquipmentSlot: %w[equipment_slot equipment_slots],
24
- EventCard: %w[event_card event_cards],
25
- Faction: %w[faction factions],
26
- Gender: %w[guardian_gender guardian_genders],
27
- GuardianRank: %w[guardian_rank guardian_ranks],
28
- GuardianRankConstants: %w[guardian_rank_constant guardian_rank_constants],
29
- HistoricalStats: %w[historical_stat historical_stats],
30
- InventoryBucket: %w[inventory_bucket inventory_buckets],
31
- InventoryItem: %w[inventory_item inventory_items],
32
- ItemCategory: %w[item_category item_categories],
33
- ItemTierType: %w[item_tier_type item_tier_types],
34
- LoadoutColor: %w[loadout_color loadout_colors],
35
- LoadoutConstants: %w[loadout_constant loadout_constants],
36
- LoadoutIcon: %w[loadout_icon loadout_icons],
37
- LoadoutName: %w[loadout_name loadout_names],
38
- Location: %w[location locations],
39
- Lore: %w[lore_entry lore_entries],
40
- MaterialRequirementSet: %w[material_requirement_set material_requirement_sets],
41
- MedalTier: %w[medal_tier medal_tiers],
42
- Metric: %w[metric metrics],
43
- Milestone: %w[milestone milestones],
44
- Objective: %w[objective objectives],
45
- Place: %w[place places],
46
- PlugSet: %w[plug_set plug_sets],
47
- PowerCap: %w[power_cap power_caps],
48
- PresentationNode: %w[presentation_node presentation_nodes],
49
- Progression: %w[progression progressions],
50
- ProgressionLevelRequirement: %w[progression_level_requirement progression_level_requirements],
51
- Race: %w[guardian_race guardian_races],
52
- Record: %w[record records],
53
- ReportReasonCategory: %w[report_reason_category report_reason_categories],
54
- RewardSource: %w[reward_source reward_sources],
55
- SackRewardItemList: %w[sack_reward_item_list sack_reward_item_lists],
56
- SandboxPattern: %w[sandbox_pattern sandbox_patterns],
57
- SandboxPerk: %w[sandbox_perk sandbox_perks],
58
- Season: %w[season seasons],
59
- SeasonPass: %w[season_pass season_passes],
60
- SocialCommendation: %w[commendation commendations],
61
- SocialCommendationNode: %w[commendation_node commendation_nodes],
62
- SocketCategory: %w[socket_category socket_categories],
63
- SocketType: %w[socket_type socket_types],
64
- Stat: %w[stat stats],
65
- StatGroup: %w[stat_group stat_groups],
66
- TalentGrid: %w[talent_grid talent_grids],
67
- Trait: %w[trait traits],
68
- Unlock: %w[unlock unlocks],
69
- Vendor: %w[vendor vendors],
70
- VendorGroup: %w[vendor_group vendor_groups]
71
- }.freeze
72
-
73
- attr_reader :version
74
-
75
- ENTITIES.each do |entity, method_names|
76
- full_table_name = "Destiny#{entity}Definition"
77
- single_method_name, plural_method_name = method_names
78
-
79
- define_method(single_method_name) { |id| fetch_item(table_name: full_table_name, id: id) }
80
- define_method(plural_method_name) { |limit: nil| fetch_items(table_name: full_table_name, limit: limit) }
81
- end
82
-
83
- def initialize(file_path, version)
84
- if file_path.empty? || !File.exist?(file_path) || !File.file?(file_path)
85
- raise Restiny::InvalidParamsError, 'You must provide a valid path for the manifest file'
86
- end
87
-
88
- @database = SQLite3::Database.new(file_path, results_as_hash: true)
89
- @version = version
90
- end
91
-
92
- private
93
-
94
- def fetch_item(table_name:, id:)
95
- query = "SELECT json FROM #{table_name} WHERE json_extract(json, '$.hash')=?"
96
- result = @database.execute(query, id)
97
-
98
- JSON.parse(result[0]['json']) unless result.nil? || result.count < 1 || !result[0].include?('json')
99
- rescue SQLite3::Exception => e
100
- raise Restiny::RequestError, "Error while fetching item (#{e})"
101
- end
102
-
103
- def fetch_items(table_name:, limit: nil)
104
- bindings = []
105
-
106
- query = "SELECT json FROM #{table_name} ORDER BY json_extract(json, '$.index')"
107
-
108
- if limit
109
- query << ' LIMIT ?'
110
- bindings << limit
111
- end
112
-
113
- items = []
114
-
115
- @database.execute(query, bindings) do |row|
116
- item = JSON.parse(row['json'])
117
- yield item if block_given?
118
-
119
- items << item
120
- end
121
-
122
- items unless block_given?
123
- rescue SQLite3::Exception => e
124
- raise Restiny::RequestError, "Error while fetching items (#{e})"
125
- end
126
- end
127
- end