restiny 0.5.0 → 0.6.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: b64ce91b4d100a18724e027008c5f22feaea7749e99ed3903f881cdf57dd514e
4
- data.tar.gz: 4494857bb6bcc684b92fa8215eebbaad2f1406d4236cb8be4e22f956eb98d8e6
3
+ metadata.gz: 865963597c492b37f7aedac0bcf200bf7e10cce108c1b14489cd21c2ccad4ece
4
+ data.tar.gz: fe4a007164b081c203c82082c169aa27e8e9764d5bfc6dfd1efe4fb66c05429e
5
5
  SHA512:
6
- metadata.gz: af7e65d052b3860b97fee42d8c38430e61aed8ab2e6e0435ff25ab74aa27433aebbf6e5267bd13b800d53559e9a6d99a3cc2e9e08972d1fbb8c5097d10bdc484
7
- data.tar.gz: 96d3dff6141def2d34948409525a9d66a80c3c4ed394c922fe44eb20b9026b59486eea93dec3962d94438fcb7ff641821ce091aeeebf3ef1bb9617569856de44
6
+ metadata.gz: 0ec8eb535c734d258806e3c990d175b7aa9a7706ff3cca36e5dca0d8f6647bc5bd4a0ef1fa97427b9fc83bca46445d70a03632e1fd5479e20f72647a3a252e0d
7
+ data.tar.gz: 83498d058cef2500cb75f43a0b14abdb8672c4f43a7c1a118c4ff5602c3d6f1bc705acc8df2e132d6bde9a8e342f1d942620747a6aa0e5c59052bae31aa0f6a9
@@ -10,10 +10,17 @@ module Restiny
10
10
  end
11
11
 
12
12
  module ComponentType
13
- PROFILES = "Profiles"
14
- PROFILE_INVENTORIES = "ProfileInventories"
15
13
  CHARACTERS = "Characters"
14
+ CHARACTER_EQUIPMENT = "CharacterEquipment"
16
15
  CHARACTER_INVENTORIES = "CharacterInventories"
16
+ CHARACTER_LOADOUTS = "CharacterLoadouts"
17
+ PROFILES = "Profiles"
18
+ PROFILE_INVENTORIES = "ProfileInventories"
19
+ ITEM_INSTANCES = "ItemInstances"
20
+ ITEM_SOCKETS = "ItemSockets"
21
+ ITEM_COMMON_DATA = "ItemCommonData"
22
+ ITEM_PLUG_STATES = "ItemPlugStates"
23
+ ITEM_REUSABLE_PLUGS = "ItemReusablePlugs"
17
24
  end
18
25
 
19
26
  module ItemLocation
@@ -34,8 +41,3 @@ module Restiny
34
41
  EXOTIC = 6
35
42
  end
36
43
  end
37
-
38
- COMPONENT_TYPE_PROFILES = "Profiles"
39
- COMPONENT_TYPE_PROFILE_INVENTORIES = "ProfileInventories"
40
- COMPONENT_TYPE_CHARACTERS = "Characters"
41
- COMPONENT_TYPE_CHARACTER_INVENTORIES = "CharacterInventories"
@@ -2,17 +2,21 @@
2
2
 
3
3
  module Restiny
4
4
  class Error < StandardError
5
- def initialize(message, details = nil)
6
- @details = details
5
+ def initialize(message, status = nil)
6
+ @status = status
7
7
  super(message)
8
8
  end
9
9
  end
10
10
 
11
- class RequestError < Error; end
11
+ class RequestError < Error
12
+ end
12
13
 
13
- class InvalidParamsError < RequestError; end
14
+ class InvalidParamsError < RequestError
15
+ end
14
16
 
15
- class RateLimitedError < RequestError; end
17
+ class RateLimitedError < RequestError
18
+ end
16
19
 
17
- class ResponseError < Error; end
20
+ class ResponseError < Error
21
+ end
18
22
  end
@@ -6,75 +6,84 @@ require "zip"
6
6
 
7
7
  module Restiny
8
8
  class Manifest
9
- TABLES = {
10
- Achievement: {item: "achievement", items: "achievements"},
11
- Activity: {item: "activity", items: "activities"},
12
- ActivityGraph: {item: "activity_graph", items: "activity_graphs"},
13
- ActivityMode: {item: "activity_mode", items: "activity_modes"},
14
- ActivityModifier: {item: "activity_modifier", items: "activity_modifiers"},
15
- ActivityType: {item: "activity_type", items: "activity_types"},
16
- Artifact: {item: "artifact", items: "artifacts"},
17
- Bond: {item: "bond", items: "bonds"},
18
- BreakerType: {item: "breaker_type", items: "breaker_types"},
19
- Checklist: {item: "checklist", items: "checklists"},
20
- Class: {item: "guardian_class", items: "guardian_classes"},
21
- Collectible: {item: "collectible", items: "collectibles"},
22
- DamageType: {item: "damage_type", items: "damage_types"},
23
- Destination: {item: "destination", items: "destinations"},
24
- EnergyType: {item: "energy_type", items: "energy_types"},
25
- EquipmentSlot: {item: "equipment_slot", items: "equipment_slots"},
26
- EventCard: {item: "event_card", items: "event_cards"},
27
- Faction: {item: "faction", items: "factions"},
28
- Gender: {item: "gender", items: "genders"},
29
- HistoricalStats: {item: "historical_stat", items: "historical_stats"},
30
- InventoryBucket: {item: "inventory_bucket", items: "inventory_buckets"},
31
- InventoryItem: {item: "inventory_item", items: "inventory_items"},
32
- ItemCategory: {item: "item_category", items: "item_categories"},
33
- ItemTierType: {item: "item_tier_type", items: "item_tier_types"},
34
- Location: {item: "location", items: "locations"},
35
- Lore: {item: "lore", items: "lore_entries"},
36
- MaterialRequirementSet: {item: "material_requirement_set", items: "material_requirement_sets"},
37
- MedalTier: {item: "medal_tier", items: "medal_tiers"},
38
- Metric: {item: "metric", items: "metrics"},
39
- Milestone: {item: "milestone", items: "milestones"},
40
- Objective: {item: "objective", items: "objectives"},
41
- Place: {item: "place", items: "places"},
42
- PlugSet: {item: "plug_set", items: "plug_sets"},
43
- PowerCap: {item: "power_cap", items: "power_caps"},
44
- PresentationNode: {item: "presentation_node", items: "presentation_nodes"},
45
- Progression: {item: "progression", items: "progression_data"},
46
- ProgressionLevelRequirement: {item: "progression_level_requirement", items: "progression_level_requirements"},
47
- Race: {item: "race", items: "races"},
48
- Record: {item: "record", items: "records"},
49
- ReportReasonCategory: {item: "report_reason_category", items: "report_reason_categories"},
50
- RewardSource: {item: "reward_source", items: "reward_sources"},
51
- SackRewardItemList: {item: "sack_reward_item_list", items: "sack_reward_item_lists"},
52
- SandboxPattern: {item: "sandbox_pattern", items: "sandbox_patterns"},
53
- SandboxPerk: {item: "sandbox_perk", items: "sandbox_perks"},
54
- Season: {item: "season", items: "seasons"},
55
- SeasonPass: {item: "season_pass", items: "season_passes"},
56
- SocketCategory: {item: "socket_category", items: "socket_categories"},
57
- SocketType: {item: "socket_type", items: "socket_types"},
58
- Stat: {item: "stat", items: "stats"},
59
- StatGroup: {item: "stat_group", items: "stat_groups"},
60
- TalentGrid: {item: "talent_grid", items: "talent_grids"},
61
- Trait: {item: "trait", items: "traits"},
62
- Unlock: {item: "unlock", items: "unlocks"},
63
- Vendor: {item: "vendor", items: "vendors"},
64
- VendorGroup: {item: "vendor_group", items: "vendor_groups"}
9
+ ENTITIES = {
10
+ Achievement: %w[achievement achievements],
11
+ Activity: %w[activity activities],
12
+ ActivityGraph: %w[activity_graph activity_graphs],
13
+ ActivityMode: %w[activity_mode activity_modes],
14
+ ActivityModifier: %w[activity_modifier activity_modifiers],
15
+ ActivityType: %w[activity_type activity_types],
16
+ Artifact: %w[artifact artifacts],
17
+ Bond: %w[bonds bonds],
18
+ BreakerType: %w[breaker_type breaker_types],
19
+ Checklist: %w[checklist checklists],
20
+ Class: %w[guardian_class guardian_classes],
21
+ Collectible: %w[collectible collectibles],
22
+ DamageType: %w[damage_type damage_types],
23
+ Destination: %w[destination destinations],
24
+ EnergyType: %w[energy_type energy_types],
25
+ EquipmentSlot: %w[equipment_slot equipment_slots],
26
+ EventCard: %w[event_card event_cards],
27
+ Faction: %w[faction factions],
28
+ Gender: %w[guardian_gender guardian_genders],
29
+ GuardianRank: %w[guardian_rank guardian_ranks],
30
+ GuardianRankConstants: %w[guardian_rank_constant guardian_rank_constants],
31
+ HistoricalStats: %w[historical_stat historical_stats],
32
+ InventoryBucket: %w[inventory_bucket inventory_buckets],
33
+ InventoryItem: %w[inventory_item inventory_items],
34
+ ItemCategory: %w[item_category item_categories],
35
+ ItemTierType: %w[item_tier_type item_tier_types],
36
+ LoadoutColor: %w[loadout_color loadout_colors],
37
+ LoadoutConstants: %w[loadout_constant loadout_constants],
38
+ LoadoutIcon: %w[loadout_icon loadout_icons],
39
+ LoadoutName: %w[loadout_name loadout_names],
40
+ Location: %w[location locations],
41
+ Lore: %w[lore_entry lore_entries],
42
+ MaterialRequirementSet: %w[material_requirement_set material_requirement_sets],
43
+ MedalTier: %w[medal_tier medal_tiers],
44
+ Metric: %w[metric metrics],
45
+ Milestone: %w[milestone milestones],
46
+ Objective: %w[objective objectives],
47
+ Place: %w[place places],
48
+ PlugSet: %w[plug_set plug_sets],
49
+ PowerCap: %w[power_cap power_caps],
50
+ PresentationNode: %w[presentation_node presentation_nodes],
51
+ Progression: %w[progression progressions],
52
+ ProgressionLevelRequirement: %w[progression_level_requirement progression_level_requirements],
53
+ Race: %w[guardian_race guardian_races],
54
+ Record: %w[record records],
55
+ ReportReasonCategory: %w[report_reason_category report_reason_categories],
56
+ RewardSource: %w[reward_source reward_sources],
57
+ SackRewardItemList: %w[sack_reward_item_list sack_reward_item_lists],
58
+ SandboxPattern: %w[sandbox_pattern sandbox_patterns],
59
+ SandboxPerk: %w[sandbox_perk sandbox_perks],
60
+ Season: %w[season seasons],
61
+ SeasonPass: %w[season_pass season_passes],
62
+ SocialCommendation: %w[commendation commendations],
63
+ SocialCommendationNode: %w[commendation_node commendation_nodes],
64
+ SocketCategory: %w[socket_category socket_categories],
65
+ SocketType: %w[socket_type socket_types],
66
+ Stat: %w[stat stats],
67
+ StatGroup: %w[stat_group stat_groups],
68
+ TalentGrid: %w[talent_grid talent_grids],
69
+ Trait: %w[trait traits],
70
+ Unlock: %w[unlock unlocks],
71
+ Vendor: %w[vendor vendors],
72
+ VendorGroup: %w[vendor_group vendor_groups]
65
73
  }
66
74
 
67
75
  attr_reader :file_path
68
76
 
69
- TABLES.each do |table_name, method_names|
70
- full_table_name = "Destiny#{table_name}Definition"
77
+ ENTITIES.each do |entity, method_names|
78
+ full_table_name = "Destiny#{entity}Definition"
79
+ single_method_name, plural_method_name = method_names
71
80
 
72
- define_method method_names[:item] do |hash|
73
- fetch_item(full_table_name, hash)
81
+ define_method single_method_name do |id|
82
+ fetch_item(full_table_name, id)
74
83
  end
75
84
 
76
- define_method method_names[:items] do |options = {}|
77
- fetch_items(full_table_name, options)
85
+ define_method plural_method_name do |limit = nil|
86
+ fetch_items(full_table_name, limit)
78
87
  end
79
88
  end
80
89
 
@@ -102,9 +111,14 @@ module Restiny
102
111
 
103
112
  private
104
113
 
105
- def fetch_item(table_name, hash)
114
+ def get_entity_names
115
+ query = "SELECT name from sqlite_schema WHERE name LIKE 'Destiny%'"
116
+ @database.execute(query).map { |row| row["name"].gsub(/(Destiny|Definition)/, "") }
117
+ end
118
+
119
+ def fetch_item(table_name, id)
106
120
  query = "SELECT json FROM #{table_name} WHERE json_extract(json, '$.hash')=?"
107
- result = @database.execute(query, hash)
121
+ result = @database.execute(query, id)
108
122
 
109
123
  return nil if result.nil? || result.count < 1 || !result[0].include?("json")
110
124
 
@@ -113,33 +127,28 @@ module Restiny
113
127
  raise Restiny::RequestError.new("Error while fetching item (#{e})")
114
128
  end
115
129
 
116
- def fetch_items(table_name, options = {})
130
+ def fetch_items(table_name, limit = nil)
117
131
  bindings = []
118
132
 
119
- query = "SELECT json FROM #{table_name} "
120
- query << "WHERE json_extract(json, '$.displayProperties.name') != '' " if options[:filter_empty]
121
- query << "ORDER BY json_extract(json, '$.index')"
133
+ query = "SELECT json FROM #{table_name} ORDER BY json_extract(json, '$.index')"
122
134
 
123
- if options[:limit]
135
+ if limit
124
136
  query << " LIMIT ?"
125
- bindings << options[:limit]
137
+ bindings << limit
126
138
  end
127
139
 
128
- result = []
140
+ items = []
129
141
 
130
142
  @database.execute(query, bindings) do |row|
131
143
  item = JSON.parse(row["json"])
144
+ yield item if block_given?
132
145
 
133
- if block_given?
134
- yield item
135
- else
136
- result << item
137
- end
146
+ items << item
138
147
  end
139
148
 
140
- result unless block_given?
149
+ items unless block_given?
141
150
  rescue SQLite3::Exception => e
142
- raise Restiny::RequestError.new("Error while fetching item (#{e})")
151
+ raise Restiny::RequestError.new("Error while fetching items (#{e})")
143
152
  end
144
153
  end
145
154
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Restiny
4
- VERSION = "0.5.0"
4
+ VERSION = "0.6.0"
5
5
  end
data/lib/restiny.rb CHANGED
@@ -26,12 +26,7 @@ module Restiny
26
26
 
27
27
  @oauth_state = state || SecureRandom.hex(15)
28
28
 
29
- params = {
30
- response_type: "code",
31
- client_id: @oauth_client_id,
32
- state: @oauth_state
33
- }
34
-
29
+ params = { response_type: "code", client_id: @oauth_client_id, state: @oauth_state }
35
30
  params[:redirect_url] = redirect_url unless redirect_url.nil?
36
31
 
37
32
  connection.build_url(BUNGIE_URL + "/en/oauth/authorize", params).to_s
@@ -40,23 +35,23 @@ module Restiny
40
35
  def request_access_token(code, redirect_url = nil)
41
36
  check_oauth_client_id
42
37
 
43
- params = {
44
- code: code,
45
- grant_type: "authorization_code",
46
- client_id: @oauth_client_id
47
- }
48
-
38
+ params = { code: code, grant_type: "authorization_code", client_id: @oauth_client_id }
49
39
  params[:redirect_url] = redirect_url unless redirect_url.nil?
50
40
 
51
- post("/platform/app/oauth/token/", params, "Content-Type" => "application/x-www-form-urlencoded")
41
+ make_api_request(
42
+ :post,
43
+ "app/oauth/token/",
44
+ params,
45
+ "Content-Type" => "application/x-www-form-urlencoded"
46
+ )
52
47
  end
53
48
 
54
49
  # Manifest methods
55
50
 
56
51
  def download_manifest(locale = "en")
57
- response = get("/platform/Destiny2/Manifest/")
52
+ response = get("Destiny2/Manifest/")
58
53
 
59
- manifest_path = response.dig("Response", "mobileWorldContentPaths", locale)
54
+ manifest_path = response.dig("mobileWorldContentPaths", locale)
60
55
  raise Restiny::ResponseError.new("Unable to determine manifest URL") if manifest_path.nil?
61
56
 
62
57
  Manifest.download(BUNGIE_URL + manifest_path)
@@ -65,92 +60,98 @@ module Restiny
65
60
  # Profile methods
66
61
 
67
62
  def get_profile(membership_id, membership_type, components = [])
68
- raise Restiny::InvalidParamsError.new("You must provide at least one component") if components.empty?
69
- get("/platform/Destiny2/#{membership_type}/Profile/#{membership_id}?components=#{components.join(",")}")
63
+ if components.empty?
64
+ raise Restiny::InvalidParamsError.new("Please provide at least one component")
65
+ end
66
+
67
+ get("Destiny2/#{membership_type}/Profile/#{membership_id}?components=#{components.join(",")}")
70
68
  end
71
69
 
72
70
  # Account methods
73
71
 
74
- def get_user_by_membership_id(membership_id, membership_type = PLATFORM_ALL)
75
- raise Restiny::InvalidParamsError.new("You must provide a valid membership ID") if membership_id.nil?
76
- get("/platform/User/GetMembershipsById/#{membership_id}/#{membership_type}/")
72
+ def get_user_by_membership_id(membership_id, membership_type = Platform::ALL)
73
+ raise Restiny::InvalidParamsError.new("Please provide a membership ID") if membership_id.nil?
74
+
75
+ get("User/GetMembershipsById/#{membership_id}/#{membership_type}/")
77
76
  end
78
77
 
79
- def get_user_by_bungie_name(full_display_name, membership_type = PLATFORM_ALL)
78
+ def get_user_by_bungie_name(full_display_name, membership_type = Platform::ALL)
80
79
  display_name, display_name_code = full_display_name.split("#")
81
- raise Restiny::InvalidParamsError.new("You must provide a valid Bungie name") if display_name.nil? || display_name_code.nil?
82
-
83
- params = {
84
- displayName: display_name,
85
- displayNameCode: display_name_code
86
- }
80
+ if display_name.nil? || display_name_code.nil?
81
+ raise Restiny::InvalidParamsError.new("You must provide a valid Bungie name")
82
+ end
87
83
 
88
- post("/platform/Destiny2/SearchDestinyPlayerByBungieName/#{membership_type}/", params)
84
+ post(
85
+ "Destiny2/SearchDestinyPlayerByBungieName/#{membership_type}/",
86
+ { displayName: display_name, displayNameCode: display_name_code }
87
+ )
89
88
  end
90
89
 
91
90
  def search_users(name, page = 0)
92
- post("/platform/User/Search/GlobalName/#{page}", displayNamePrefix: name)
91
+ post("User/Search/GlobalName/#{page}", displayNamePrefix: name)
93
92
  end
94
93
 
95
94
  private
96
95
 
97
96
  def get(endpoint_url, params = {}, headers = {})
98
- make_api_request(:get, endpoint_url, params, headers)
97
+ make_api_request(:get, endpoint_url, params, headers).dig("Response")
99
98
  end
100
99
 
101
100
  def post(endpoint_url, body, headers = {})
102
- make_api_request(:post, endpoint_url, body, headers)
101
+ make_api_request(:post, endpoint_url, body, headers).dig("Response")
103
102
  end
104
103
 
105
104
  def make_api_request(type, url, params, headers = {})
106
- raise Restiny::InvalidParamsError.new("You need to set an API key (Restiny.api_key = XXX)") unless @api_key
105
+ raise Restiny::InvalidParamsError.new("You need to set an API key") unless @api_key
107
106
 
108
107
  headers[:authorization] = "Bearer #{@oauth_token}" if @oauth_token
109
108
 
110
- response = case type
111
- when :get
112
- connection.get(url, params, headers)
113
- when :post
114
- connection.post(url, params, headers)
115
- end
109
+ response =
110
+ case type
111
+ when :get
112
+ connection.get(url, params, headers)
113
+ when :post
114
+ connection.post(url, params, headers)
115
+ end
116
116
 
117
- response.body&.dig("Response")
117
+ response.body
118
118
  rescue Faraday::Error => error
119
- message = if error.response_body && error.response_headers["content-type"] =~ /application\/json;/i
120
- error_response = JSON.parse(error.response_body)
121
- "#{error_response["error_description"]} (#{error_response["error"]})"
122
- else
123
- error.message
119
+ begin
120
+ error_body = JSON.parse(error.response_body)
121
+ status, message = error_body["ErrorStatus"], error_body["Message"]
122
+ rescue JSON::ParserError
123
+ status, message = error.response_status, error.message
124
124
  end
125
125
 
126
- case error
127
- when Faraday::ClientError
128
- raise Restiny::RequestError.new(message, error.response_status)
129
- when Faraday::ServerError
130
- raise Restiny::ResponseError.new(message, error.response_status)
131
- else
132
- raise Restiny::Error.new(message)
133
- end
126
+ klass =
127
+ case error
128
+ when Faraday::ClientError
129
+ Restiny::RequestError
130
+ when Faraday::ServerError
131
+ Restiny::ResponseError
132
+ else
133
+ Restiny::Error
134
+ end
135
+
136
+ raise klass.new(message, status)
134
137
  end
135
138
 
136
139
  def check_oauth_client_id
137
- raise Restiny::RequestError.new("You need to set an OAuth client ID (Restiny.oauth_client_id = XXX)") unless @oauth_client_id
140
+ raise Restiny::RequestError.new("You need to set an OAuth client ID") unless @oauth_client_id
138
141
  end
139
142
 
140
143
  def default_headers
141
- {
142
- "User-Agent": "restiny v#{Restiny::VERSION}",
143
- "X-API-KEY": @api_key
144
- }
144
+ { "User-Agent": "restiny v#{Restiny::VERSION}", "X-API-KEY": @api_key }
145
145
  end
146
146
 
147
147
  def connection
148
- @connection ||= Faraday.new(url: API_BASE_URL, headers: default_headers) do |faraday|
149
- faraday.request :json
150
- faraday.request :url_encoded
151
- faraday.response :json
152
- faraday.response :follow_redirects
153
- faraday.response :raise_error
154
- end
148
+ @connection ||=
149
+ Faraday.new(url: API_BASE_URL, headers: default_headers) do |faraday|
150
+ faraday.request :json
151
+ faraday.request :url_encoded
152
+ faraday.response :json
153
+ faraday.response :follow_redirects
154
+ faraday.response :raise_error
155
+ end
155
156
  end
156
157
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restiny
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.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-05-26 00:00:00.000000000 Z
11
+ date: 2023-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday