1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 | 1×
1×
1×
4×
4×
4×
4×
4×
4×
1×
3×
3×
3×
3×
1×
1×
1×
1×
1×
1×
1×
1×
1×
1×
| import URLHelper from '../Utils/URLHelper'
import RegionHelper from '../Utils/RegionHelper'
function Request(
config,
serviceName,
endpoint,
methodName,
httpMethodType,
limiter,
body, // POST/PUT
isTournament = false,
version = 3,
) {
this.payload = {
method: httpMethodType || 'GET',
serviceName,
endpoint,
query: [],
region: '',
body,
isTournament,
version,
}
if (Ethis.payload.method === 'GET') delete this.payload.body
this.config = config
this.retriesLeft = this.config.requestOptions.numberOfRetriesBeforeAbort
this.methodName = methodName
this.limiter = limiter
}
Request.prototype.region = function(region) {
if (Ithis.payload.region)
throw new Error('Do not call Request.region twice.')
if (I!RegionHelper.isValidRegion(region))
throw new Error('Bad region value in Request.region.')
if (Eregion) this.payload.region = region
return this
}
Request.prototype.regionNoThrow = function(region) {
try {
return this.region(region)
} catch (invalidRegionException) {
this.payload.region = '' // reset region to avoid `Do not call Request.region twice error`
return this.region(this.config.region)
}
}
Request.prototype.query = function(obj) {
if (typeof obj !== 'object')
throw new Error('Request.query takes in an object.')
if (obj) this.payload.query.push(obj)
return this
}
Request.prototype.then = function then(resolve, reject) {
const self = this
return new Promise((innerResolve, innerReject) =>
self.callback(
(err, res) => (err ? innerReject(err) : innerResolve(res)),
),
).then(resolve, reject)
}
Request.prototype.catch = callback => this.then(null, callback)
Request.prototype.callback = function(cb) {
if (!this.payload.region) this.payload.region = this.config.region
const {
endpoint,
query,
region,
serviceName,
body,
isTournament,
version,
} = this.payload
const url = URLHelper.getURLWithQuery(
RegionHelper.asPlatformID(region),
serviceName,
endpoint,
query,
isTournament,
version,
)
const { key: token } = this.config
this.execute(url, body, token, this.retriesLeft, cb)
}
Request.prototype.execute = async function(url, body, token, retriesLeft, cb) {
const { cacheOptions, debugOptions, requestOptions } = this.config
const fn = async (err, data) => {
const debugURL = `${url}${
debugOptions.showKey ? URLHelper.getAPIKey(url, token) : ''
}`
try {
if (data) {
if (debugOptions.isEnabled) {
debugOptions.loggers.cache.get(debugURL)
}
ok(data)(cb)
} else {
if (debugOptions.isEnabled) {
const { method } = this.payload
let debugString = `[${method}] => ${debugURL}`
if (method !== 'GET') debugString += ' with body: %O'
if (body)
debugOptions.loggers.request.outgoing(debugString, body)
else debugOptions.loggers.request.outgoing(debugString)
}
const res = await this.limiter.executing({
url,
method: this.payload.method,
body,
token,
})
if (debugOptions.isEnabled) {
debugOptions.loggers.request.incoming.success(debugURL)
}
try {
const blob = JSON.parse(res)
if (
cacheOptions.cache &&
cacheOptions.ttls[this.methodName] > 0
) {
cacheOptions.cache.set(
{
key: url,
ttl: cacheOptions.ttls[this.methodName],
},
blob,
)
if (debugOptions.isEnabled) {
debugOptions.loggers.cache.set(`${url}`)
}
}
ok(blob)(cb)
} catch (ex) {
console.log(ex)
}
}
} catch ({ statusCode, ...rest }) {
// ...rest is usually populated when there is a bigger error such
// as socket hang ups.
// It also occurs with 404's.
if (debugOptions.isEnabled) {
debugOptions.loggers.request.incoming.failure(
`[${statusCode}] ${debugURL}`,
)
}
if (statusCode === 403) {
const errorMessage =
'[kayn] Your key is either invalid or you are magically blacklisted. You should not be getting blacklisted with this rate limiter, so something is wrong with this library, the rate limiter, your network, and/or the LoL API! Perhaps the rate limiter is getting out of sync because you are making a ton (emphasis on a ton) of requests in parallel. Try to split your requests into chunks!'
if (requestOptions.shouldExitOn403) {
console.log(errorMessage + ' Exiting program...')
process.exit(1)
}
console.log(errorMessage)
}
if (requestOptions.shouldRetry && shouldRetry(statusCode)) {
if (retriesLeft > 0) {
return setTimeout(
() =>
this.execute(url, body, token, retriesLeft - 1, cb),
requestOptions.delayBeforeRetry,
)
}
}
error({
statusCode, // null/undefined if not a simple request error
url: debugURL,
error: rest, // the rest of the error object
})(cb)
}
}
if (cacheOptions.cache) {
cacheOptions.cache.get({ key: url }, fn)
} else {
fn()
}
}
const shouldRetry = statusCode => statusCode === 500 || statusCode === 503
const ok = blob => cb => cb(null, blob)
const error = blob => cb => cb(blob, null)
export default Request
|