-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Create a token manager library for MapBox #23511
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
c9b8494
b0fed71
5449a64
c8bb64b
416b970
53fd9f9
c53d822
2ffe94a
1083804
f1dd506
09b09e5
cdcd828
957f01c
4df7fed
073fbe6
49a8a74
d8479d0
09e4f5c
e7b930b
37c4017
f807f7b
646da93
9d89624
3193c56
e07ede3
98336ec
de6f49a
db9bc9f
29c6f35
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,89 @@ | ||||||
import _ from 'underscore'; | ||||||
import moment from 'moment'; | ||||||
import Onyx from 'react-native-onyx'; | ||||||
import {AppState} from 'react-native'; | ||||||
import ONYXKEYS from '../../ONYXKEYS'; | ||||||
import * as API from '../API'; | ||||||
import CONST from '../../CONST'; | ||||||
|
||||||
let connectionID; | ||||||
let currentToken; | ||||||
let refreshTimeoutID; | ||||||
const refreshInterval = 1000 * 60 * 25; | ||||||
neil-marcellini marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
const refreshToken = () => { | ||||||
console.debug('[MapboxTokens] refreshing token every 25 minutes', refreshInterval); | ||||||
|
||||||
// Cancel any previous timeouts so that there is only one request to get a token at a time. | ||||||
clearTimeout(refreshTimeoutID); | ||||||
|
||||||
// Refresh the token every 25 minutes | ||||||
refreshTimeoutID = setTimeout(() => { | ||||||
console.debug('[MapboxTokens] Fetching a new token after waiting 25 minutes'); | ||||||
neil-marcellini marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
API.read('GetMapboxAccessToken'); | ||||||
}, refreshInterval); | ||||||
}; | ||||||
|
||||||
const hasTokenExpired = () => { | ||||||
const now = moment(); | ||||||
const expiration = moment(currentToken.expiration); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will most likely not happen but there might be case when AppState change callback is called before Onyx connect callback, which will cause crash because of undefined currentToken. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes, you're right. I'll add a check for that. Updated! |
||||||
const minutesUntilTokenExpires = expiration.diff(now, 'minutes'); | ||||||
return minutesUntilTokenExpires < 0; | ||||||
neil-marcellini marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
}; | ||||||
|
||||||
const clearToken = () => { | ||||||
console.debug('[MapboxTokens] Deleting the token stored in Onyx'); | ||||||
|
||||||
// Use Onyx.set() to delete the key from Onyx, which will trigger a new token to be retrieved from the API. | ||||||
Onyx.set(ONYXKEYS.MAPBOX_ACCESS_TOKEN, null); | ||||||
}; | ||||||
|
||||||
const init = () => { | ||||||
if (connectionID) { | ||||||
console.debug(`[MapboxTokens] init() is already listening to Onyx so returning early`); | ||||||
luacmartins marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
return; | ||||||
} | ||||||
|
||||||
// When the token changes in Onyx, the expiration needs to be checked so a new token can be retrieved. | ||||||
connectionID = Onyx.connect({ | ||||||
key: ONYXKEYS.MAPBOX_ACCESS_TOKEN, | ||||||
/** | ||||||
* @param {Object} token | ||||||
* @param {String} token.token | ||||||
* @param {String} token.expiration | ||||||
* @param {String[]} [token.errors] | ||||||
*/ | ||||||
callback: (token) => { | ||||||
// token is an object with. If it is falsy or an empty object, the token needs to be retrieved from the API. | ||||||
neil-marcellini marked this conversation as resolved.
Show resolved
Hide resolved
luacmartins marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
// The API sets a token in Onyx with a 30 minute expiration. | ||||||
if (!token || _.size(token) === 0) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
console.debug('[MapboxTokens] Token does not exist so fetching one'); | ||||||
API.read('GetMapboxAccessToken'); | ||||||
return; | ||||||
} | ||||||
|
||||||
// Store the token in a place where the AppState callback can also access it. | ||||||
currentToken = token; | ||||||
|
||||||
if (hasTokenExpired()) { | ||||||
console.debug('[MapboxTokens] Token has expired after reading from Onyx'); | ||||||
clearToken(); | ||||||
return; | ||||||
} | ||||||
|
||||||
console.debug('[MapboxTokens] Token is valid, setting up refresh'); | ||||||
refreshToken(); | ||||||
neil-marcellini marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
}, | ||||||
}); | ||||||
|
||||||
// When the app becomes active (eg. after being in the background), check if the token has expired. | ||||||
AppState.addEventListener('change', (nextAppState) => { | ||||||
if (nextAppState !== CONST.APP_STATE.ACTIVE || !hasTokenExpired()) { | ||||||
return; | ||||||
} | ||||||
console.debug('[MapboxTokens] Token is expired after app became active'); | ||||||
clearToken(); | ||||||
}); | ||||||
}; | ||||||
|
||||||
export default init; |
Uh oh!
There was an error while loading. Please reload this page.