diff --git a/keyserver/src/keyserver.js b/keyserver/src/keyserver.js --- a/keyserver/src/keyserver.js +++ b/keyserver/src/keyserver.js @@ -31,22 +31,25 @@ uploadDownloadResponder, } from './uploads/uploads'; import { + prefetchAllURLFacts, getSquadCalURLFacts, getLandingURLFacts, getCommAppURLFacts, } from './utils/urls'; -const squadCalBaseRoutePath = getSquadCalURLFacts().baseRoutePath; -const landingBaseRoutePath = getLandingURLFacts().baseRoutePath; -const commAppBaseRoutePath = getCommAppURLFacts().baseRoutePath; +(async () => { + await prefetchAllURLFacts(); -const compiledFolderOptions = - process.env.NODE_ENV === 'development' - ? undefined - : { maxAge: '1y', immutable: true }; + const squadCalBaseRoutePath = getSquadCalURLFacts().baseRoutePath; + const landingBaseRoutePath = getLandingURLFacts().baseRoutePath; + const commAppBaseRoutePath = getCommAppURLFacts().baseRoutePath; -if (cluster.isMaster) { - (async () => { + const compiledFolderOptions = + process.env.NODE_ENV === 'development' + ? undefined + : { maxAge: '1y', immutable: true }; + + if (cluster.isMaster) { const didMigrationsSucceed: boolean = await migrate(); if (!didMigrationsSucceed) { // The following line uses exit code 2 to ensure nodemon exits @@ -58,98 +61,99 @@ for (let i = 0; i < cpuCount; i++) { cluster.fork(); } - })(); - cluster.on('exit', () => cluster.fork()); -} else { - const server = express(); - expressWs(server); - server.use(express.json({ limit: '50mb' })); - server.use(cookieParser()); - - const setupAppRouter = router => { - router.use('/images', express.static('images')); - router.use('/fonts', express.static('fonts')); - router.use('/misc', express.static('misc')); - router.use( - '/.well-known', - express.static( - '.well-known', - // Necessary for apple-app-site-association file - { - setHeaders: res => res.setHeader('Content-Type', 'application/json'), - }, - ), - ); - router.use( - '/compiled', - express.static('app_compiled', compiledFolderOptions), - ); - router.use('/', express.static('icons')); - - for (const endpoint in jsonEndpoints) { - // $FlowFixMe Flow thinks endpoint is string - const responder = jsonEndpoints[endpoint]; - const expectCookieInvalidation = endpoint === 'log_out'; - router.post( - `/${endpoint}`, - jsonHandler(responder, expectCookieInvalidation), + cluster.on('exit', () => cluster.fork()); + } else { + const server = express(); + expressWs(server); + server.use(express.json({ limit: '50mb' })); + server.use(cookieParser()); + + const setupAppRouter = router => { + router.use('/images', express.static('images')); + router.use('/fonts', express.static('fonts')); + router.use('/misc', express.static('misc')); + router.use( + '/.well-known', + express.static( + '.well-known', + // Necessary for apple-app-site-association file + { + setHeaders: res => + res.setHeader('Content-Type', 'application/json'), + }, + ), + ); + router.use( + '/compiled', + express.static('app_compiled', compiledFolderOptions), + ); + router.use('/', express.static('icons')); + + for (const endpoint in jsonEndpoints) { + // $FlowFixMe Flow thinks endpoint is string + const responder = jsonEndpoints[endpoint]; + const expectCookieInvalidation = endpoint === 'log_out'; + router.post( + `/${endpoint}`, + jsonHandler(responder, expectCookieInvalidation), + ); + } + + router.get( + '/create_version/:deviceType/:codeVersion', + httpGetHandler(createNewVersionResponder), + ); + router.get( + '/mark_version_deployed/:deviceType/:codeVersion', + httpGetHandler(markVersionDeployedResponder), ); - } - - router.get( - '/create_version/:deviceType/:codeVersion', - httpGetHandler(createNewVersionResponder), - ); - router.get( - '/mark_version_deployed/:deviceType/:codeVersion', - httpGetHandler(markVersionDeployedResponder), - ); - router.get( - '/download_error_report/:reportID', - downloadHandler(errorReportDownloadResponder), - ); - router.get( - '/upload/:uploadID/:secret', - downloadHandler(uploadDownloadResponder), - ); + router.get( + '/download_error_report/:reportID', + downloadHandler(errorReportDownloadResponder), + ); + router.get( + '/upload/:uploadID/:secret', + downloadHandler(uploadDownloadResponder), + ); - // $FlowFixMe express-ws has side effects that can't be typed - router.ws('/ws', onConnection); - router.get('*', htmlHandler(websiteResponder)); + // $FlowFixMe express-ws has side effects that can't be typed + router.ws('/ws', onConnection); + router.get('*', htmlHandler(websiteResponder)); - router.post( - '/upload_multimedia', - multerProcessor, - uploadHandler(multimediaUploadResponder), + router.post( + '/upload_multimedia', + multerProcessor, + uploadHandler(multimediaUploadResponder), + ); + }; + + // Note - the order of router declarations matters. On prod we have + // squadCalBaseRoutePath configured to '/', which means it's a catch-all. If + // we call server.use on squadCalRouter first, it will catch all requests + // and prevent commAppRouter and landingRouter from working correctly. So we + // make sure that squadCalRouter goes last + + const landingRouter = express.Router(); + landingRouter.use('/images', express.static('images')); + landingRouter.use('/fonts', express.static('fonts')); + landingRouter.use( + '/compiled', + express.static('landing_compiled', compiledFolderOptions), ); - }; - - // Note - the order of router declarations matters. On prod we have - // squadCalBaseRoutePath configured to '/', which means it's a catch-all. If - // we call server.use on squadCalRouter first, it will catch all requests and - // prevent commAppRouter and landingRouter from working correctly. So we make - // sure that squadCalRouter goes last - - const landingRouter = express.Router(); - landingRouter.use('/images', express.static('images')); - landingRouter.use('/fonts', express.static('fonts')); - landingRouter.use( - '/compiled', - express.static('landing_compiled', compiledFolderOptions), - ); - landingRouter.use('/', express.static('landing_icons')); - landingRouter.post('/subscribe_email', emailSubscriptionResponder); - landingRouter.get('*', landingHandler); - server.use(landingBaseRoutePath, landingRouter); - - const commAppRouter = express.Router(); - setupAppRouter(commAppRouter); - server.use(commAppBaseRoutePath, commAppRouter); - - const squadCalRouter = express.Router(); - setupAppRouter(squadCalRouter); - server.use(squadCalBaseRoutePath, squadCalRouter); - - server.listen(parseInt(process.env.PORT, 10) || 3000, 'localhost'); -} + landingRouter.use('/', express.static('landing_icons')); + landingRouter.post('/subscribe_email', emailSubscriptionResponder); + landingRouter.get('*', landingHandler); + server.use(landingBaseRoutePath, landingRouter); + + const commAppRouter = express.Router(); + setupAppRouter(commAppRouter); + server.use(commAppBaseRoutePath, commAppRouter); + + const squadCalRouter = express.Router(); + setupAppRouter(squadCalRouter); + server.use(squadCalBaseRoutePath, squadCalRouter); + + server.listen(parseInt(process.env.PORT, 10) || 3000, 'localhost'); + } +})(); diff --git a/keyserver/src/utils/urls.js b/keyserver/src/utils/urls.js --- a/keyserver/src/utils/urls.js +++ b/keyserver/src/utils/urls.js @@ -1,5 +1,7 @@ // @flow +import { values } from 'lib/utils/objects'; + import commAppURLFacts from '../../facts/commapp_url'; import landingURLFacts from '../../facts/landing_url'; import squadCalURLFacts from '../../facts/squadcal_url'; @@ -10,6 +12,37 @@ +https: boolean, +baseRoutePath: string, }; +const sitesObj = Object.freeze({ + a: 'landing', + b: 'commapp', + c: 'squadcal', +}); +export type Site = $Values; +const sites: $ReadOnlyArray = values(sitesObj); + +const cachedURLFacts = new Map(); +async function fetchURLFacts(site: Site): Promise { + const cached = cachedURLFacts.get(site); + if (cached !== undefined) { + return cached; + } + try { + // $FlowFixMe + const urlFacts = await import(`../../facts/${site}_url`); + if (!cachedURLFacts.has(site)) { + cachedURLFacts.set(site, urlFacts.default); + } + } catch { + if (!cachedURLFacts.has(site)) { + cachedURLFacts.set(site, null); + } + } + return cachedURLFacts.get(site); +} + +async function prefetchAllURLFacts() { + await Promise.all(sites.map(fetchURLFacts)); +} function getSquadCalURLFacts(): AppURLFacts { return squadCalURLFacts; @@ -39,6 +72,7 @@ } export { + prefetchAllURLFacts, getSquadCalURLFacts, getCommAppURLFacts, getLandingURLFacts,