restiny 5.0.1 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
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