restiny 0.5.0 → 0.6.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 +4 -4
- data/lib/restiny/constants.rb +9 -7
- data/lib/restiny/errors.rb +10 -6
- data/lib/restiny/manifest.rb +87 -78
- data/lib/restiny/version.rb +1 -1
- data/lib/restiny.rb +65 -64
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 865963597c492b37f7aedac0bcf200bf7e10cce108c1b14489cd21c2ccad4ece
|
4
|
+
data.tar.gz: fe4a007164b081c203c82082c169aa27e8e9764d5bfc6dfd1efe4fb66c05429e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0ec8eb535c734d258806e3c990d175b7aa9a7706ff3cca36e5dca0d8f6647bc5bd4a0ef1fa97427b9fc83bca46445d70a03632e1fd5479e20f72647a3a252e0d
|
7
|
+
data.tar.gz: 83498d058cef2500cb75f43a0b14abdb8672c4f43a7c1a118c4ff5602c3d6f1bc705acc8df2e132d6bde9a8e342f1d942620747a6aa0e5c59052bae31aa0f6a9
|
data/lib/restiny/constants.rb
CHANGED
@@ -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"
|
data/lib/restiny/errors.rb
CHANGED
@@ -2,17 +2,21 @@
|
|
2
2
|
|
3
3
|
module Restiny
|
4
4
|
class Error < StandardError
|
5
|
-
def initialize(message,
|
6
|
-
@
|
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
|
11
|
+
class RequestError < Error
|
12
|
+
end
|
12
13
|
|
13
|
-
class InvalidParamsError < RequestError
|
14
|
+
class InvalidParamsError < RequestError
|
15
|
+
end
|
14
16
|
|
15
|
-
class RateLimitedError < RequestError
|
17
|
+
class RateLimitedError < RequestError
|
18
|
+
end
|
16
19
|
|
17
|
-
class ResponseError < Error
|
20
|
+
class ResponseError < Error
|
21
|
+
end
|
18
22
|
end
|
data/lib/restiny/manifest.rb
CHANGED
@@ -6,75 +6,84 @@ require "zip"
|
|
6
6
|
|
7
7
|
module Restiny
|
8
8
|
class Manifest
|
9
|
-
|
10
|
-
Achievement:
|
11
|
-
Activity:
|
12
|
-
ActivityGraph:
|
13
|
-
ActivityMode:
|
14
|
-
ActivityModifier:
|
15
|
-
ActivityType:
|
16
|
-
Artifact:
|
17
|
-
Bond:
|
18
|
-
BreakerType:
|
19
|
-
Checklist:
|
20
|
-
Class:
|
21
|
-
Collectible:
|
22
|
-
DamageType:
|
23
|
-
Destination:
|
24
|
-
EnergyType:
|
25
|
-
EquipmentSlot:
|
26
|
-
EventCard:
|
27
|
-
Faction:
|
28
|
-
Gender:
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
70
|
-
full_table_name = "Destiny#{
|
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
|
73
|
-
fetch_item(full_table_name,
|
81
|
+
define_method single_method_name do |id|
|
82
|
+
fetch_item(full_table_name, id)
|
74
83
|
end
|
75
84
|
|
76
|
-
define_method
|
77
|
-
fetch_items(full_table_name,
|
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
|
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,
|
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,
|
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
|
135
|
+
if limit
|
124
136
|
query << " LIMIT ?"
|
125
|
-
bindings <<
|
137
|
+
bindings << limit
|
126
138
|
end
|
127
139
|
|
128
|
-
|
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
|
-
|
134
|
-
yield item
|
135
|
-
else
|
136
|
-
result << item
|
137
|
-
end
|
146
|
+
items << item
|
138
147
|
end
|
139
148
|
|
140
|
-
|
149
|
+
items unless block_given?
|
141
150
|
rescue SQLite3::Exception => e
|
142
|
-
raise Restiny::RequestError.new("Error while fetching
|
151
|
+
raise Restiny::RequestError.new("Error while fetching items (#{e})")
|
143
152
|
end
|
144
153
|
end
|
145
154
|
end
|
data/lib/restiny/version.rb
CHANGED
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
|
-
|
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("
|
52
|
+
response = get("Destiny2/Manifest/")
|
58
53
|
|
59
|
-
manifest_path = response.dig("
|
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
|
-
|
69
|
-
|
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 =
|
75
|
-
raise Restiny::InvalidParamsError.new("
|
76
|
-
|
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 =
|
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
|
-
|
82
|
-
|
83
|
-
|
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(
|
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("
|
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
|
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 =
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
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
|
117
|
+
response.body
|
118
118
|
rescue Faraday::Error => error
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
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
|
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 ||=
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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.
|
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-
|
11
|
+
date: 2023-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|