@@ -16,6 +16,7 @@ class Auth {
16
16
* @param {Object } [options={}] Additional options
17
17
* @param {Function | Object | Boolean } [options.logger] Debug, info, and error logger to use
18
18
* @param {Boolean } [options.isOffline=true] Provides a session that can be used indefinitely by refreshing
19
+ * @param {ICache } [options.cache] Optional cache instantiated class
19
20
*/
20
21
constructor ( clientId , clientSecret , authorizationUrl , options = { } ) {
21
22
/**
@@ -41,6 +42,17 @@ class Auth {
41
42
this . logger = options . logger ;
42
43
this . isOffline = options . isOffline ;
43
44
45
+ this . isCacheEnabled = ! ! options . cache ;
46
+ this . cache = {
47
+ interface : options . cache ,
48
+ actions : {
49
+ drop : 'drop' ,
50
+ get : 'get' ,
51
+ set : 'set'
52
+ } ,
53
+ status : 'cached'
54
+ } ;
55
+
44
56
/** @type CoreError */
45
57
this . invalidCredentials ;
46
58
this . access = new Token ( ) ;
@@ -131,6 +143,10 @@ class Auth {
131
143
* @param {Object } [opts.query] Query to send
132
144
* @param {Object } [opts.payload] Payload to send
133
145
* @param {boolean } [opts.isPublic=false] If this request should include authorization
146
+ * @param {Object } [opts.cache=false]
147
+ * @param {String } opts.cache.key
148
+ * @param {String } opts.cache.action
149
+ * @param {Boolean } opts.cache.onNotFound
134
150
* @param {Number } retry Allow retries in case of expired token
135
151
*
136
152
* @returns {Promise<{} | Array<{}>> }
@@ -142,7 +158,7 @@ class Auth {
142
158
throw this . invalidCredentials ;
143
159
}
144
160
145
- opts = Object . assign ( { headers : { } , isPublic : false } , opts ) ;
161
+ opts = Object . assign ( { headers : { } , isPublic : false , cache : false } , opts ) ;
146
162
147
163
if ( ! retry ) {
148
164
service = `[${ service } ]` ;
@@ -157,25 +173,70 @@ class Auth {
157
173
throw CoreError . MaxAuthenticatedRequestsReached ( ) ;
158
174
}
159
175
160
- if ( ! opts . isPublic ) {
161
- const clientToken = await this . getApplicationToken ( ) ;
162
- opts . headers . authorization = `Bearer ${ clientToken } ` ;
176
+ let status ;
177
+ let body ;
178
+ if ( this . isCacheEnabled && opts . cache ) {
179
+ if ( opts . cache . action === this . cache . actions . drop ) {
180
+ await this . executeCacheOp ( opts . cache ) ;
181
+ }
182
+ if ( opts . cache . action === this . cache . actions . get ) {
183
+ body = await this . executeCacheOp ( opts . cache ) ;
184
+ status = body || body === false ? this . cache . status : null ;
185
+ }
163
186
}
164
187
165
- begin = new Date ( ) . getTime ( ) ;
166
- const response = await superagent ( method , url )
167
- . set ( opts . headers )
168
- . query ( opts . query )
169
- . send ( opts . payload ) ;
188
+ if ( ! body && body !== false ) {
189
+ if ( ! opts . isPublic ) {
190
+ const clientToken = await this . getApplicationToken ( ) ;
191
+ opts . headers . authorization = `Bearer ${ clientToken } ` ;
192
+ }
193
+
194
+ begin = new Date ( ) . getTime ( ) ;
195
+ ( { status, body } = await superagent ( method , url )
196
+ . set ( opts . headers )
197
+ . query ( opts . query )
198
+ . send ( opts . payload ) ) ;
199
+
200
+ if (
201
+ this . isCacheEnabled &&
202
+ opts . cache &&
203
+ opts . cache . action === this . cache . actions . get
204
+ ) {
205
+ await this . executeCacheOp ( {
206
+ value : body ,
207
+ ...opts . cache ,
208
+ ...{ action : this . cache . actions . set }
209
+ } ) ;
210
+ }
211
+ }
212
+
213
+ if ( this . isCacheEnabled && body === false ) {
214
+ throw CoreError . CachedNotFound ( ) ;
215
+ }
170
216
171
217
this . log (
172
- `${ service } ${ method } , code: ${ response . status } , t: ${ this . timeDelta (
218
+ `${ service } ${ method } , code: ${ status } , t: ${ this . timeDelta (
173
219
begin
174
220
) } ms -> url: ${ url } , query: ${ JSON . stringify ( opts . query || { } ) } `
175
221
) ;
176
222
177
- return response . body ;
223
+ return body ;
178
224
} catch ( error ) {
225
+ if (
226
+ this . isCacheEnabled &&
227
+ opts . cache &&
228
+ opts . cache . action === this . cache . actions . get &&
229
+ opts . cache . onNotFound &&
230
+ error . status === 404 &&
231
+ error . typeof !== CoreError . CachedNotFound
232
+ ) {
233
+ await this . executeCacheOp ( {
234
+ value : false ,
235
+ ...opts . cache ,
236
+ ...{ action : this . cache . actions . set }
237
+ } ) ;
238
+ }
239
+
179
240
if (
180
241
! opts . isPublic &&
181
242
error . status === 401 &&
@@ -211,28 +272,24 @@ class Auth {
211
272
* @returns {CoreError }
212
273
*/
213
274
getError ( error , url , service , method , tDelta , query ) {
214
- const log = ( ) => {
215
- const errorText =
216
- ! ! error . response && ! ! error . response . text
217
- ? error . response . text
218
- : error . stack ;
219
- this . log (
220
- `${ service } ${ method } , code: ${
221
- error . status
222
- } , t: ${ tDelta } ms -> url: ${ url } , query: ${ JSON . stringify (
223
- query || { }
224
- ) } -> error response ${ errorText } `,
225
- 'error'
226
- ) ;
227
- } ;
275
+ const errorText =
276
+ ! ! error . response && ! ! error . response . text
277
+ ? error . response . text
278
+ : error . stack ;
279
+ this . log (
280
+ `${ service } ${ method } , code: ${
281
+ error . status
282
+ } , t: ${ tDelta } ms -> url: ${ url } , query: ${ JSON . stringify (
283
+ query || { }
284
+ ) } -> error response ${ errorText } `,
285
+ 'error'
286
+ ) ;
228
287
229
288
if ( error instanceof CoreError ) {
230
- log ( ) ;
231
289
return error ;
232
290
}
233
291
234
292
error = new CoreError ( error , { statusCode : error . status } ) ;
235
- log ( ) ;
236
293
return error ;
237
294
}
238
295
@@ -277,6 +334,54 @@ class Auth {
277
334
return ;
278
335
}
279
336
}
337
+
338
+ /**
339
+ * Executes a cache operations
340
+ *
341
+ * @param {Object } [opts]
342
+ * @param {String } opts.key
343
+ * @param {{} } opts.value
344
+ * @param {String } opts.action
345
+ * @param {Array } rest
346
+ */
347
+ executeCacheOp ( opts , ...rest ) {
348
+ if ( ! this . isCacheEnabled ) {
349
+ return ;
350
+ }
351
+
352
+ switch ( opts . action ) {
353
+ case this . cache . actions . get :
354
+ return this . cache . interface . get ( opts . key , ...rest ) ;
355
+ case this . cache . actions . set :
356
+ return this . cache . interface . set ( opts . key , opts . value , ...rest ) ;
357
+ case this . cache . actions . drop :
358
+ return this . cache . interface . drop ( opts . key , ...rest ) ;
359
+ default :
360
+ throw new CoreError ( 'Unknown cache operation' ) ;
361
+ }
362
+ }
363
+
364
+ /**
365
+ * Generates a cache key
366
+ *
367
+ * @param {String } service Service prefix to add
368
+ * @param {String } prefix Additoinal prefix to add
369
+ * @param {Array.<Number | String> } rest Rest of values to add to keys, only number or strings
370
+ *
371
+ * @returns {String }
372
+ */
373
+ genCacheKey ( service , prefix , ...rest ) {
374
+ let key = rest
375
+ . map ( arg => {
376
+ if ( typeof arg === 'string' || typeof arg === 'number' ) {
377
+ return `${ arg } ` ;
378
+ }
379
+ return '' ;
380
+ } )
381
+ . join ( '...' ) ;
382
+
383
+ return [ this . clientId , service , prefix , key ] . join ( '.' ) ;
384
+ }
280
385
}
281
386
282
387
module . exports = Auth ;
0 commit comments