diff --git a/app/client/models/ToggleEnterpriseModel.ts b/app/client/models/ToggleEnterpriseModel.ts new file mode 100644 index 00000000..3c23d248 --- /dev/null +++ b/app/client/models/ToggleEnterpriseModel.ts @@ -0,0 +1,44 @@ +import {getHomeUrl} from 'app/client/models/AppModel'; +import {Disposable, Observable} from "grainjs"; +import {ConfigAPI} from 'app/common/ConfigAPI'; +import {delay} from 'app/common/delay'; + +export class ToggleEnterpriseModel extends Disposable { + public readonly edition: Observable = Observable.create(this, null); + private readonly _configAPI: ConfigAPI = new ConfigAPI(getHomeUrl()); + + public async fetchEnterpriseToggle(): Promise { + const edition = await this._configAPI.getValue('edition'); + this.edition.set(edition); + } + + public async updateEnterpriseToggle(edition: string): Promise { + // We may be restarting the server, so these requests may well + // fail if done in quick succession. + await retryOnNetworkError(() => this._configAPI.setValue({edition})); + this.edition.set(edition); + await retryOnNetworkError(() => this._configAPI.restartServer()); + } +} + +// Copied from DocPageModel.ts +const reconnectIntervals = [1000, 1000, 2000, 5000, 10000]; +async function retryOnNetworkError(func: () => Promise): Promise { + for (let attempt = 0; ; attempt++) { + try { + return await func(); + } catch (err) { + // fetch() promises that network errors are reported as TypeError. We'll accept NetworkError too. + if (err.name !== "TypeError" && err.name !== "NetworkError") { + throw err; + } + // We really can't reach the server. Make it known. + if (attempt >= reconnectIntervals.length) { + throw err; + } + const reconnectTimeout = reconnectIntervals[attempt]; + console.warn(`Call to ${func.name} failed, will retry in ${reconnectTimeout} ms`, err); + await delay(reconnectTimeout); + } + } +}