From cfa50ea09bf434798d914c93b4c626ca3fddb51e Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Thu, 29 Jun 2023 14:52:18 +0200 Subject: [PATCH] feat: allow sapi endpoint to be configured at ... ...runtime --- common/constants.js | 3 + deploy/app.js | 73 ++++++++++-------------- docs/releases/v2.12.0.md | 3 +- src/atlasComponents/sapi/sapi.service.ts | 8 ++- src/atlasViewer/atlasViewer.component.ts | 4 +- 5 files changed, 44 insertions(+), 47 deletions(-) diff --git a/common/constants.js b/common/constants.js index d3fe2b2b3..d3f6f2454 100644 --- a/common/constants.js +++ b/common/constants.js @@ -148,6 +148,9 @@ If you do not accept the Terms & Conditions you are not permitted to access or u REMOVE_FRONTAL_OCTANT_HELPER_TEXT: `Hide the octant facing the user, and overlaying the slice views.`, AUXMESH_DESC: `Some templates contain auxiliary meshes, which compliment the appearance of the template in the perspective view.`, + + OVERWRITE_SAPI_ENDPOINT_ATTR: `x-sapi-base-url`, + DATA_ERROR_ATTR: `data-error` } exports.QUICKTOUR_DESC ={ diff --git a/deploy/app.js b/deploy/app.js index f4b3dcd07..bc3444df3 100644 --- a/deploy/app.js +++ b/deploy/app.js @@ -1,4 +1,3 @@ -const fs = require('fs') const path = require('path') const express = require('express') const app = express.Router() @@ -6,8 +5,7 @@ const session = require('express-session') const crypto = require('crypto') const cookieParser = require('cookie-parser') const bkwdMdl = require('./bkwdCompat')() - -const LOCAL_CDN_FLAG = !!process.env.LOCAL_CDN +const { CONST } = require("../common/constants") if (process.env.NODE_ENV !== 'production') { app.use(require('cors')()) @@ -123,36 +121,6 @@ const PUBLIC_PATH = process.env.NODE_ENV === 'production' */ app.use('/.well-known', express.static(path.join(__dirname, 'well-known'))) -if (LOCAL_CDN_FLAG) { - /* - * TODO setup local cdn for supported libraries map - */ - const LOCAL_CDN = process.env.LOCAL_CDN - const CDN_ARRAY = [ - 'https://stackpath.bootstrapcdn.com', - 'https://use.fontawesome.com', - 'https://unpkg.com' - ] - - let indexFile - fs.readFile(path.join(PUBLIC_PATH, 'index.html'), 'utf-8', (err, data) => { - if (err) throw err - if (!LOCAL_CDN) { - indexFile = data - return - } - const regexString = CDN_ARRAY.join('|').replace(/\/|\./g, s => `\\${s}`) - const regex = new RegExp(regexString, 'gm') - indexFile = data.replace(regex, LOCAL_CDN) - }) - - app.get('/', bkwdMdl, (_req, res) => { - if (!indexFile) return res.status(404).end() - res.setHeader('Content-Type', 'text/html; charset=utf-8') - return res.status(200).send(indexFile) - }) -} - app.use((_req, res, next) => { res.setHeader('Referrer-Policy', 'origin-when-cross-origin') next() @@ -182,23 +150,42 @@ app.get('/', (req, res, next) => { middelware(req, res, next) } -}, bkwdMdl, cookieParser(), (req, res) => { +}, bkwdMdl, cookieParser(), async (req, res) => { + res.setHeader('Content-Type', 'text/html') + + let returnIndex = indexTemplate + + if (!!process.env.LOCAL_CDN) { + const CDN_ARRAY = [ + 'https://stackpath.bootstrapcdn.com', + 'https://use.fontawesome.com', + 'https://unpkg.com' + ] + + const regexString = CDN_ARRAY.join('|').replace(/\/|\./g, s => `\\${s}`) + const regex = new RegExp(regexString, 'gm') + returnIndex = returnIndex.replace(regex, process.env.LOCAL_CDN) + } const iavError = req.cookies && req.cookies['iav-error'] - res.setHeader('Content-Type', 'text/html') + const attributeToAppend = {} if (iavError) { res.clearCookie('iav-error', { httpOnly: true, sameSite: 'strict' }) + attributeToAppend[CONST.DATA_ERROR_ATTR] = iavError + } - const returnTemplate = indexTemplate - .replace(/\$\$NONCE\$\$/g, res.locals.nonce) - .replace('<atlas-viewer>', `<atlas-viewer data-error="${iavError.replace(/"/g, '"')}">`) - res.status(200).send(returnTemplate) - } else { - const returnTemplate = indexTemplate - .replace(/\$\$NONCE\$\$/g, res.locals.nonce) - res.status(200).send(returnTemplate) + if (!!process.env.OVERWRITE_API_ENDPOING) { + attributeToAppend[CONST.OVERWRITE_SAPI_ENDPOINT_ATTR] = process.env.OVERWRITE_API_ENDPOING } + + const attr = Object.entries(attributeToAppend).map(([key, value]) => `${key}="${value.replace(/"/g, '"')}"`).join(" ") + + const returnTemplate = returnIndex + .replace(/\$\$NONCE\$\$/g, res.locals.nonce) + .replace('<atlas-viewer>', `<atlas-viewer ${attr}>`) + + res.status(200).send(returnTemplate) }) app.get('/ready', async (req, res) => { diff --git a/docs/releases/v2.12.0.md b/docs/releases/v2.12.0.md index ba23e2fa1..99ad15e06 100644 --- a/docs/releases/v2.12.0.md +++ b/docs/releases/v2.12.0.md @@ -13,4 +13,5 @@ ## Behind the scene - update spotlight mechanics from in-house to angular CDK -- Updated neuroglancer/nehuba dependency. This allows volumes with non-rigid affine to be displayed properly. +- updated neuroglancer/nehuba dependency. This allows volumes with non-rigid affine to be displayed properly. +- allow siibra-api endpoint to be configured at runtime diff --git a/src/atlasComponents/sapi/sapi.service.ts b/src/atlasComponents/sapi/sapi.service.ts index b5aaf5bc4..0fec93688 100644 --- a/src/atlasComponents/sapi/sapi.service.ts +++ b/src/atlasComponents/sapi/sapi.service.ts @@ -13,6 +13,7 @@ import { import { FeatureType, PathReturn, RouteParam, SapiRoute } from "./typeV3"; import { BoundingBox, SxplrAtlas, SxplrParcellation, SxplrRegion, SxplrTemplate, VoiFeature, Feature } from "./sxplrTypes"; import { parcBanList, speciesOrder } from "src/util/constants"; +import { CONST } from "common/constants" export const useViewer = { THREESURFER: "THREESURFER", @@ -94,7 +95,12 @@ export class SAPI{ */ static get BsEndpoint$(): Observable<string> { if (!!BS_ENDPOINT_CACHED_VALUE) return BS_ENDPOINT_CACHED_VALUE - const endpoints = environment.SIIBRA_API_ENDPOINTS.split(',') + const rootEl = document.querySelector('atlas-viewer') + const overwriteSapiUrl = rootEl.getAttribute(CONST.OVERWRITE_SAPI_ENDPOINT_ATTR) + + const endpoints = overwriteSapiUrl + ? [ overwriteSapiUrl ] + : environment.SIIBRA_API_ENDPOINTS.split(',') if (endpoints.length === 0) { SAPI.ErrorMessage = `No siibra-api endpoint defined!` return NEVER diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts index c28d15f9a..b80a7c4de 100644 --- a/src/atlasViewer/atlasViewer.component.ts +++ b/src/atlasViewer/atlasViewer.component.ts @@ -76,11 +76,11 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { @Inject(DARKTHEME) private darktheme$: Observable<boolean> ) { - const error = this.el.nativeElement.getAttribute('data-error') + const error = this.el.nativeElement.getAttribute(CONST.DATA_ERROR_ATTR) if (error) { this.snackbar.open(error, 'Dismiss', { duration: 5000 }) - this.el.nativeElement.removeAttribute('data-error') + this.el.nativeElement.removeAttribute(CONST.DATA_ERROR_ATTR) } } -- GitLab