@interopio/gateway-server
Version:
## `@glue42/gateway-ent` compatibility
87 lines (81 loc) • 3.6 kB
text/typescript
import {Metrics} from '@interopio/gateway-metrics-api';
import {Middleware, WebExchange} from '../server/types.js';
import getLogger from '../logger.js';
import {FilePublisherConfig} from '@interopio/gateway/metrics/publisher/file';
import {HttpServerRequest, HttpServerResponse} from '../server/exchange.ts';
const logger = getLogger('metrics');
const COOKIE_NAME = 'GW_LOGIN';
function loggedIn(auth, ctx: WebExchange) {
if (auth) {
const cookieHeaderValue = ctx.request.headers.list('cookie');
const cookie = cookieHeaderValue?.join('; ').split('; ').find(value => value.startsWith(`${COOKIE_NAME}=`));
return cookie && (parseInt(cookie?.substring(COOKIE_NAME.length + 1)) > Date.now());
}
return true;
}
async function routes(config: {file?: FilePublisherConfig, auth?}): Promise<Middleware<HttpServerRequest, HttpServerResponse>> {
const {jsonFileAppender} = await import('@interopio/gateway/metrics/publisher/file');
const appender = jsonFileAppender(logger);
await appender.open(config.file?.location ?? 'metrics.ndjson', config.file?.append ?? true);
return [
async (ctx, next: () => Promise<void>) => {
if (ctx.method === 'GET' && ctx.path === '/api/metrics') {
if (loggedIn(config.auth, ctx)) {
ctx.response.statusCode = 200;
} else {
ctx.response.statusCode = 302;
ctx.response.headers.set('location', '/api/login?redirectTo=/api/metrics');
}
ctx.response._res.end();
}
else {
await next();
}
},
async (ctx, next: () => Promise<void>) => {
if (ctx.method === 'GET' && ctx.path === '/api/login') {
const redirectTo = new URLSearchParams(ctx.request.query ?? undefined).get('redirectTo');
const expires = Date.now() + 180 * 1000;
ctx.response.headers.add('set-cookie', `${COOKIE_NAME}=${expires}; Path=/api; SameSite=strict`)
if (redirectTo) {
ctx.response.statusCode = 302;
ctx.response.headers.set('location', redirectTo);
}
else {
ctx.response.statusCode = 200;
}
ctx.response._res.end();
} else {
await next();
}
},
async (ctx, next: () => Promise<void>) => {
if (ctx.method === 'POST' && ctx.path === '/api/metrics') {
if (loggedIn(config.auth, ctx)) {
ctx.response.statusCode = 202;
ctx.response._res.end();
try {
const json = await ctx.request.json;
const update = json as Metrics.Update;
if (logger.enabledFor('debug')) {
logger.debug(`${JSON.stringify(update)}`);
}
if ((config.file?.status ?? false) || (update.status === undefined)) {
await appender.write(update);
}
} catch (e) {
logger.error(`error processing metrics`, e);
}
}
else {
ctx.response.statusCode = 401;
ctx.response._res.end();
}
}
else {
await next();
}
},
];
}
export default routes;