mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-15 01:52:42 +03:00
interface: extract GcpManager
Now the API is just an API. (I did still have it produce an expiry time, since it makes the refresh loop easier to do.) Not yet storing the token now.
This commit is contained in:
parent
3c2ce636e7
commit
9fa086e0d3
@ -4,40 +4,20 @@ import {GcpToken} from '../types/gcp-state';
|
||||
|
||||
|
||||
export default class GcpApi extends BaseApi<StoreState> {
|
||||
#running = false;
|
||||
// Return value resolves to the token's expiry time if successful.
|
||||
refreshToken() {
|
||||
return this.spider('noun', 'gcp-token', 'get-gcp-token', {})
|
||||
.then((token) => {
|
||||
this.store.handleEvent({
|
||||
data: token
|
||||
});
|
||||
|
||||
startRefreshLoop() {
|
||||
if (this.#running) {
|
||||
console.error('GcpApi startRefreshLoop: already running');
|
||||
} else {
|
||||
this.#running = true;
|
||||
this.refreshLoop();
|
||||
if (token['gcp-token'] !== undefined &&
|
||||
token['gcp-token']['expiresIn'] !== undefined &&
|
||||
typeof(token['gcp-token']['expiresIn']) === 'number') {
|
||||
return Promise.resolve(token['gcp-token']['expiresIn']);
|
||||
}
|
||||
}
|
||||
|
||||
private refreshLoop() {
|
||||
console.log("GcpApi refreshLoop");
|
||||
this.refreshToken().then(({accessKey, expiresIn}: GcpToken) => {
|
||||
console.log("GcpApi new token");
|
||||
// XX maybe bad?
|
||||
this.store.state.gcp.accessKey = accessKey;
|
||||
const timeout = this.refreshInterval(expiresIn);
|
||||
console.log("GcpApi refreshing in", timeout);
|
||||
setTimeout(() => {
|
||||
this.refreshLoop();
|
||||
}, timeout);
|
||||
return Promise.reject({reason: 'invalid token'});
|
||||
});
|
||||
}
|
||||
|
||||
private refreshInterval(expiresIn: number) {
|
||||
// Give ourselves 30 seconds for processing delays, but never refresh
|
||||
// sooner than 10 minute from now. (The expiry window should be about an
|
||||
// hour.)
|
||||
return Math.max(600_000, expiresIn - 30_000);
|
||||
}
|
||||
|
||||
private async refreshToken() {
|
||||
const token = await this.spider('noun', 'gcp-token', 'get-gcp-token', {});
|
||||
return token['gcp-token'];
|
||||
}
|
||||
};
|
||||
|
94
pkg/interface/src/logic/lib/gcpManager.ts
Normal file
94
pkg/interface/src/logic/lib/gcpManager.ts
Normal file
@ -0,0 +1,94 @@
|
||||
// Singleton that manages GCP token state.
|
||||
//
|
||||
// To use:
|
||||
//
|
||||
// 1. call setApi with a GlobalApi.
|
||||
// 2. call start() to start the token refresh loop.
|
||||
//
|
||||
//
|
||||
import GlobalApi from '../api/global';
|
||||
|
||||
|
||||
class GcpManager {
|
||||
#api: GlobalApi | null = null;
|
||||
|
||||
setApi(api: GlobalApi) {
|
||||
this.#api = api;
|
||||
}
|
||||
|
||||
#running = false;
|
||||
#timeoutId: number | null = null;
|
||||
|
||||
start() {
|
||||
if (this.#running) {
|
||||
console.warn('GcpManager already running');
|
||||
return;
|
||||
}
|
||||
if (!this.#api) {
|
||||
console.error('GcpManager must have api set');
|
||||
return;
|
||||
}
|
||||
this.#running = true;
|
||||
this.refreshLoop();
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (!this.#running) {
|
||||
console.warn('GcpManager already stopped');
|
||||
console.assert(this.#timeoutId === null);
|
||||
return;
|
||||
}
|
||||
this.#running = false;
|
||||
if (this.#timeoutId !== null) {
|
||||
clearTimeout(this.#timeoutId);
|
||||
this.#timeoutId = null;
|
||||
}
|
||||
}
|
||||
|
||||
restart() {
|
||||
if (this.#running)
|
||||
this.stop();
|
||||
this.start();
|
||||
}
|
||||
|
||||
private refreshLoop() {
|
||||
console.log('GcpManager refreshing token');
|
||||
this.#api.gcp.refreshToken()
|
||||
.then(
|
||||
(expiresIn: number) => {
|
||||
const interval = this.refreshInterval(expiresIn);
|
||||
this.refreshAfter(interval);
|
||||
})
|
||||
.catch(
|
||||
({reason}) => {
|
||||
console.error('GcpManager token refresh failed', reason);
|
||||
this.refreshAfter(10_000); // XX backoff?
|
||||
});
|
||||
}
|
||||
|
||||
private refreshAfter(durationMs) {
|
||||
if (!this.#running)
|
||||
return;
|
||||
if (this.#timeoutId !== null) {
|
||||
console.warn('GcpManager already has a timeout set');
|
||||
return;
|
||||
}
|
||||
console.log('GcpManager refreshing after', durationMs, 'ms');
|
||||
this.#timeoutId = setTimeout(() => {
|
||||
this.#timeoutId = null;
|
||||
this.refreshLoop();
|
||||
}, durationMs);
|
||||
}
|
||||
|
||||
private refreshInterval(expiresIn: number) {
|
||||
// Give ourselves 30 seconds for processing delays, but never refresh
|
||||
// sooner than 30 minutes from now. (The expiry window should be about an
|
||||
// hour.)
|
||||
return Math.max(30 * 60_000, expiresIn - 30_000);
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new GcpManager();
|
||||
Object.freeze(instance);
|
||||
|
||||
export default instance;
|
@ -27,6 +27,7 @@ import GlobalSubscription from '~/logic/subscription/global';
|
||||
import GlobalApi from '~/logic/api/global';
|
||||
import { uxToHex } from '~/logic/lib/util';
|
||||
import { foregroundFromBackground } from '~/logic/lib/sigil';
|
||||
import gcpManager from '~/logic/lib/gcpManager';
|
||||
import { withLocalState } from '~/logic/state/local';
|
||||
|
||||
|
||||
@ -78,6 +79,7 @@ class App extends React.Component {
|
||||
|
||||
this.appChannel = new window.channel();
|
||||
this.api = new GlobalApi(this.ship, this.appChannel, this.store);
|
||||
gcpManager.setApi(this.api);
|
||||
this.subscription =
|
||||
new GlobalSubscription(this.store, this.api, this.appChannel);
|
||||
|
||||
@ -94,7 +96,7 @@ class App extends React.Component {
|
||||
// before the app has actually rendered, hence the timeout.
|
||||
this.updateTheme(this.themeWatcher);
|
||||
}, 500);
|
||||
this.api.gcp.startRefreshLoop();
|
||||
gcpManager.start();
|
||||
this.api.local.getBaseHash();
|
||||
this.api.settings.getAll();
|
||||
this.store.rehydrate();
|
||||
|
Loading…
Reference in New Issue
Block a user