import { HTTPStatus } from 'deps'; import { isSuccessfulStatus } from 'deps'; import { Logger, logger as defaultLogger } from 'infra/logger.ts'; export interface ControllerOptions { status?: HTTPStatus; json?: boolean; } export type ControllerHandler = ( req: Request, error?: string, headers?: Record, ) => Response | Promise; export type ControllerHandlers = Record; export default class Controller { constructor( private handlers: ControllerHandlers = {}, private logger: Logger = defaultLogger, ) {} public setHandlers(handlers: ControllerHandlers): void { this.handlers = handlers; } public setHandler( path: string, method: string, handler: ControllerHandler, ): void { this.handlers[`${path}_${method}`] = handler; } public getHandlers(): ControllerHandlers { return this.handlers; } public getHandler(path: string, method: string): ControllerHandler { return this.handlers[`${path}_${method}`]; } public hasHandler(path: string, method: string): boolean { return `${path}_${method}` in this.handlers; } public response = ( req: Request, body: string, options: ControllerOptions = {}, ) => { const url = new URL(req.url); const output = new TextEncoder().encode(body); const response = new Response(output, { status: options.status ?? HTTPStatus.OK, }); const userName = Controller.getUser(req); if (options.json) { response.headers.set('Content-Type', 'application/json'); } const userAgent = req.headers.get('User-Agent') ?? '-'; const logMessage = Controller.getLogMessage( req.method, url.pathname, response.status, output.byteLength, userAgent, userName, ); if (isSuccessfulStatus(response.status)) { if (Controller.isHealthCheck(userAgent)) { this.logger.debug(logMessage); } else { this.logger.info(logMessage); } } else { this.logger.error(logMessage); } return response; }; public responseJSON = ( req: Request, body: Record, options: ControllerOptions = {}, ) => { options.json = true; return this.response(req, JSON.stringify(body), options); }; private static getUser = (req: Request): string | undefined => { const authHeader = req.headers.get('Authorization'); if (authHeader && authHeader.startsWith('Basic ')) { const base64Credentials = authHeader.slice(6); const credentials = atob(base64Credentials); const [userName] = credentials.split(':'); return userName; } return; }; private static getLogMessage( method: string, path: string, status: number, length: number, userAgent: string, userName?: string, ) { const user = userName ? userName + ' ' : ''; return `${method} ${path} ${user}${status} ${length} (${userAgent})`; } private static isHealthCheck(userAgent: string): boolean { return userAgent === Deno.env.get('DOCKER_USER_AGENT'); } }