swgoh_comlink 0.1.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c9c4144173f292a053e64ace25b86b5f3937db8cd4de91c95420414f7edb942b
4
+ data.tar.gz: 3f194112a1082053ff9cea729522efca2ee1c7e0fc770d4666964eaaec6360b2
5
+ SHA512:
6
+ metadata.gz: 261e30c5d1efbd7732d9d1c63495850611a1e53e1a1cf104b5f259b9784d64086edb6290c86fdd6d7fcbc7c3f54d2b00bd0997f9afdb8aea2c5e711a029e63e6
7
+ data.tar.gz: 334865c1ac341fdaea813ae8071ba92cf94f31a9eca900471f4352f6f0163e5d9e9a59df8c9a80d2db504f110d0394e183dba4e3b785abd77a73969222310ad1
@@ -0,0 +1,62 @@
1
+ require 'openssl'
2
+ require 'digest'
3
+ require 'json'
4
+ require 'net/http'
5
+ require 'uri'
6
+ require 'active_support/core_ext/hash/indifferent_access'
7
+
8
+ class ComlinkApiRequest
9
+ attr_accessor :hmac_enabled, :comlink_url
10
+
11
+ def initialize(comlink_url, keys)
12
+ @comlink_url = comlink_url.start_with?('http') ? comlink_url : "https://#{comlink_url}"
13
+ @hmac_enabled = false
14
+ return if keys.empty?
15
+
16
+ keys = keys.with_indifferent_access
17
+ @secret_key = keys['secret_key']
18
+ @access_key = keys['access_key']
19
+
20
+ raise ArgumentError, 'Secret key missing' unless @secret_key
21
+ raise ArgumentError, 'Access key missing' unless @access_key
22
+
23
+ @hmac_enabled = true
24
+ end
25
+
26
+ def get(path)
27
+ uri = URI.parse("#{@comlink_url}#{path}")
28
+ http = Net::HTTP.new(uri.host, uri.port)
29
+ http.use_ssl = true
30
+ request = Net::HTTP::Get.new(uri.request_uri)
31
+
32
+ http.request(request).body
33
+ end
34
+
35
+ def post(path, body)
36
+ uri = URI.parse("#{@comlink_url}#{path}")
37
+ http = Net::HTTP.new(uri.host, uri.port)
38
+ http.use_ssl = true
39
+
40
+ request = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json')
41
+ add_hmac_headers(request, 'POST', path, body)
42
+ request.body = body
43
+
44
+ http.request(request).body
45
+ end
46
+
47
+ private
48
+
49
+ def add_hmac_headers(request, type, endpoint, payload = '')
50
+ return unless @hmac_enabled
51
+
52
+ req_time = (Time.now.to_i * 1000).to_s
53
+
54
+ payload_hash_digest = Digest::MD5.hexdigest(payload)
55
+
56
+ hmac_obj = OpenSSL::HMAC.new(@secret_key, OpenSSL::Digest.new('sha256'))
57
+ hmac_obj.update(req_time + type + endpoint + payload_hash_digest)
58
+
59
+ request['X-Date'] = req_time
60
+ request['Authorization'] = "HMAC-SHA256 Credential=#{@access_key},Signature=#{hmac_obj.hexdigest}"
61
+ end
62
+ end
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/hash'
4
+ require 'active_support/core_ext/string'
5
+ require_relative 'comlink_api_request'
6
+
7
+ # Base class for the gem, a wrapper for Comlink
8
+ # See https://github.com/swgoh-utils/swgoh-comlink for more info on Comlink
9
+ class SwgohComlink
10
+ def initialize(comlink_url, keys = {})
11
+ @api_requester = ComlinkApiRequest.new(comlink_url, keys)
12
+ end
13
+
14
+ def enums
15
+ JSON.parse(@api_requester.get('/enums'))
16
+ end
17
+
18
+ def localization(id, unzip = false, enums = false)
19
+ body = {
20
+ payload: {
21
+ id: id
22
+ },
23
+ unzip: unzip,
24
+ enums: enums
25
+ }
26
+
27
+ JSON.parse(@api_requester.post('/localization', body.to_json))
28
+ end
29
+
30
+ def metadata(client_specs = {}, enums = false)
31
+ body = {}
32
+ body['payload'] = { "clientSpecs" => verify_parameters(client_specs, ['platform', 'bundleId', 'externalVersion', 'internalVersion', 'region']) } unless client_specs.empty?
33
+ body['enums'] = false
34
+
35
+ JSON.parse(@api_requester.post('/metadata', body.to_json))
36
+ end
37
+
38
+ def data(version, include_pve_units = true, request_segment = 0, enums = false)
39
+ body = {
40
+ payload: {
41
+ version: version,
42
+ includePveUnits: include_pve_units,
43
+ requestSegment: request_segment
44
+ },
45
+ enums: enums
46
+ }
47
+
48
+ body_validation(body, [ { validation: (0..4), error_message: 'Request segment must be between 0 and 4', path: [:payload, :requestSegment] } ])
49
+
50
+ JSON.parse(@api_requester.post('/data', body.to_json))
51
+ end
52
+
53
+ def player(player_id, enums = false)
54
+ body = {
55
+ payload: format_player_id_hash(player_id),
56
+ enums: enums
57
+ }
58
+
59
+ JSON.parse(@api_requester.post('/player', body.to_json))
60
+ end
61
+
62
+ def player_arena(player_id, enums = false)
63
+ body = {
64
+ payload: format_player_id_hash(player_id),
65
+ enums: enums
66
+ }
67
+
68
+ JSON.parse(@api_requester.post('/playerArena', body.to_json))
69
+ end
70
+
71
+ def guild(guild_id, include_recent_guild_activity = false, enums = false)
72
+ body = {
73
+ payload: {
74
+ guildId: guild_id,
75
+ includeRecentGuildActivityInfo: include_recent_guild_activity
76
+ },
77
+ enums: enums
78
+ }
79
+
80
+ JSON.parse(@api_requester.post('/guild', body.to_json))
81
+ end
82
+
83
+ def get_guilds(filter_type, name = nil, search_criteria = nil, count = 10, enums = false)
84
+ body = {
85
+ payload: {
86
+ filterType: filter_type,
87
+ count: count,
88
+ enums: enums
89
+ }
90
+ }
91
+
92
+ validations = [ { validation: [4, 5], error_message: 'filterType must be 4 or 5', path: [:payload, :filterType], required: true } ]
93
+
94
+ if filter_type == 4
95
+ body[:payload][:name] = name
96
+ validations << { error_message: 'Name is required when filterType is 4', path: [:payload, :name], required: true }
97
+ elsif filter_type == 5
98
+ body[:payload][:searchCriteria] = search_criteria && verify_parameters(search_criteria, ['minMemberCount', 'maxMemberCount', 'includeInviteOnly', 'minGuildGalacticPower', 'maxGuildGalacticPower', 'recentTbParticipatedIn'])
99
+ validations << { error_message: 'searchCriteria is required when filterType is 5', path: [:payload, :searchCriteria], required: true }
100
+ end
101
+
102
+ body_validation(body, validations)
103
+
104
+ JSON.parse(@api_requester.post('/getGuilds', body.to_json))
105
+ end
106
+
107
+ def get_events(enums = false)
108
+ body = {
109
+ enums: enums
110
+ }
111
+
112
+ JSON.parse(@api_requester.post('/getEvents', body.to_json))
113
+ end
114
+
115
+ def get_leaderboard(payload, enums = false)
116
+ body_validation(payload, [ { validation: [4, 6], error_message: 'leaderboardType must be 4 or 6', path: [:leaderboardType] } ])
117
+
118
+ if payload[:leaderboardType] == 4 || payload[:leaderboard_type] == 4
119
+ payload = verify_parameters(payload, ['leaderboardType', 'eventInstanceId', 'groupId'])
120
+ body_validation(payload, [
121
+ { error_message: 'eventInstanceId must be present', path: [:eventInstanceId], required: true },
122
+ { error_message: 'groupId must be present', path: [:groupId], required: true }
123
+ ])
124
+ else
125
+ payload = verify_parameters(payload, ['leaderboardType', 'league', 'division'])
126
+ body_validation(payload, [
127
+ { validation: [20, 40, 60, 80, 100], error_message: 'league must be in [20, 40, 60, 80, 100]', path: [:league], required: true },
128
+ { validation: [5, 10, 15, 20, 25], error_message: 'division must be in [5, 10, 15, 20, 25]', path: [:division], required: true }
129
+ ])
130
+ end
131
+
132
+ body = {
133
+ payload: payload,
134
+ enums: false
135
+ }
136
+
137
+ JSON.parse(@api_requester.post('/getLeaderboard', body.to_json))
138
+ end
139
+
140
+ def get_guild_leaderboard(leaderboards, count, enums = false)
141
+ def_ids = [
142
+ 'sith_raid',
143
+ 'rancor',
144
+ 'aat',
145
+ 'kraytdragon',
146
+ 'speederbike',
147
+ 't01D',
148
+ 't02D',
149
+ 't03D',
150
+ 't04D',
151
+ 't05D',
152
+ 'TERRITORY_WAR_LEADERBOARD',
153
+ 'GUILD:RAIDS:NORMAL_DIFF:RANCOR:DIFF06',
154
+ 'GUILD:RAIDS:NORMAL_DIFF:RANCOR:HEROIC80',
155
+ 'GUILD:RAIDS:NORMAL_DIFF:AAT:DIFF06',
156
+ 'GUILD:RAIDS:NORMAL_DIFF:AAT:HEROIC85',
157
+ 'GUILD:RAIDS:NORMAL_DIFF:SITH_RAID:DIFF06',
158
+ 'GUILD:RAIDS:NORMAL_DIFF:SITH_RAID:HEROIC85',
159
+ 'GUILD:RAIDS:NORMAL_DIFF:KRAYTDRAGON:DIFF01',
160
+ 'GUILD:RAIDS:NORMAL_DIFF:ROTJ:SPEEDERBIKE'
161
+ ]
162
+
163
+ leaderboards.each do |leaderboard|
164
+ payload = verify_parameters(leaderboard, ['leaderboardType', 'defId', 'monthOffset'])
165
+ body_validation(leaderboard, [
166
+ { validation: [0, 2, 3, 4, 5, 6], error_message: 'leaderboardType must in [0, 2, 3, 4, 5, 6]', path: [:leaderboardType], required: true },
167
+ { validation: def_ids, error_message: 'defId must be certain values, see docs', path: [:defId], required: [2, 4, 5, 6].include?(leaderboard.with_indifferent_access[:leaderboardType]) },
168
+ { validation: [0, 1], error_message: 'monthOffset must 0 or 1', path: [:monthOffset] }
169
+ ])
170
+ end
171
+
172
+ body = {
173
+ payload: {
174
+ leaderboardId: leaderboards,
175
+ count: count
176
+ },
177
+ enums: enums
178
+ }
179
+
180
+ JSON.parse(@api_requester.post('/getGuildLeaderboard', body.to_json))
181
+ end
182
+
183
+ private
184
+
185
+ def format_player_id_hash(player_id_original)
186
+ # This can accept the 9 digit ally code (ex: 123-456-789)
187
+ # OR it can accept the full playerId (ex: HFuvf-OURK202WASUgpayw)
188
+ player_id = player_id_original.dup
189
+ player_id.gsub!('-', '') if player_id.length == 11
190
+ player_id.length == 9 ? { allyCode: player_id } : { playerID: player_id }
191
+ end
192
+
193
+ def verify_parameters(original_hash, permitted_keys)
194
+ original_hash = original_hash.with_indifferent_access
195
+
196
+ original_hash.transform_keys! { |key| key.to_s.camelize(:lower) }
197
+ original_hash.slice!(*permitted_keys)
198
+
199
+ original_hash
200
+ end
201
+
202
+ def body_validation(body, requirements)
203
+ requirements.each do |req_set|
204
+ value = body.dig(*req_set[:path])
205
+ next if !value && !req_set[:required]
206
+ next if value && (!req_set[:validation] || req_set[:validation].include?(value))
207
+
208
+ raise ArgumentError, req_set[:error_message]
209
+ end
210
+
211
+ true
212
+ end
213
+ end
metadata ADDED
@@ -0,0 +1,87 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: swgoh_comlink
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Zach Moses
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2024-10-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: sinatra
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: webmock
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: A wrapper to connect to SWGOH Comlink APIs
56
+ email: zmoses93@gmail.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - lib/comlink_api_request.rb
62
+ - lib/swgoh_comlink.rb
63
+ homepage: https://github.com/zmoses/SwgohComlink
64
+ licenses:
65
+ - MIT
66
+ metadata: {}
67
+ post_install_message:
68
+ rdoc_options: []
69
+ require_paths:
70
+ - lib
71
+ required_ruby_version: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: 2.7.0
76
+ required_rubygems_version: !ruby/object:Gem::Requirement
77
+ requirements:
78
+ - - ">="
79
+ - !ruby/object:Gem::Version
80
+ version: '0'
81
+ requirements: []
82
+ rubygems_version: 3.5.18
83
+ signing_key:
84
+ specification_version: 4
85
+ summary: 'Created to connect with deployed Star Wars: Galaxy of Heroes Comlink APIs.
86
+ For more information on Comlink, see their Github page: https://github.com/swgoh-utils/swgoh-comlink'
87
+ test_files: []