import Koa from 'koa'; import Router from 'koa-router'; import { StravaApi, StravaCode } from './strava-api'; import { LogFunctions, LogOpts } from './util'; export type OpenUrlFunction = (target: string) => Promise; export type ServerOpts = LogOpts & { open: OpenUrlFunction; }; export class Server { strava: any; server: any; result: { resolve?: string; reject?: string; } = {}; private _log: LogFunctions; private _openUrl: OpenUrlFunction; constructor(strava: StravaApi, opts: ServerOpts) { this.strava = strava; this._log = opts.log; this._openUrl = opts.open; } public async run() { return new Promise((resolve, reject) => { const app = new Koa(); const router = new Router(); let authOpts = { redirectUri: 'http://localhost:3000/token', }; const authUrl = this.strava.getAuthorizationUrl(authOpts); router.get('/token', async (ctx) => { const code: StravaCode = ctx.query.code as string; const err: string = ctx.query.error as string; let s = '

Credential Exchange

'; return Promise.resolve() .then((resp) => { if (err === 'access_denied') { s += '

Error, access denied

'; } else { s += `

Authorization code: ${code}

`; return this.strava .getTokens(code) .then((resp) => { s += '

Tokens retrieved. Please return to command line.

'; s += ''; ctx.body = s; this.result = { resolve: 'Tokens retrieved and saved to file' }; }) .catch((err) => { s += `

Error retrieving tokens: ${err.message}

`; s += ''; ctx.body = s; this.result = { reject: 'Could not retrieve tokens: ' + err.message }; }); } }) .then((resp) => { s += ''; ctx.body = s; }); }); // This code was causing a problem when I updated koa, and is not needed, // so I am commenting it out. router.get('/*', ctx => { ctx.body = // `Click to // authenticate`; // }); app.use(router.routes()); let server = app.listen(3000); this._log.info('Server running on port 3000'); this._openUrl(authUrl).then((resp) => { this._log.info('browser is open'); }); let timer = setInterval(() => { this._log.info('Waiting ...'); if (this.result.resolve) { clearInterval(timer); timer = undefined; this._log.info('Closing server ' + this.result.resolve); this.close(); resolve(this.result.resolve); } else if (this.result.reject) { clearInterval(timer); timer = undefined; this._log.info('Closing server ' + this.result.reject); this.close(); reject(new Error(this.result.reject)); } }, 1000); }); } close() { if (this.server) { this.server.close(); } this.server = undefined; } }