import fastify, { FastifyInstance } from 'fastify'; import etags from '@fastify/etag'; import compress, { FastifyCompressOptions } from '@fastify/compress'; import formbody from '@fastify/formbody'; import { pino } from 'pino'; export type ServerStatus = 'unstarted' | 'starting' | 'ready' | 'closing' | 'closed'; export interface HttpConfig { address: string; port: number; tls: false | { key: string; cert: string; }; exposed_url?: string; etag?: boolean; compress?: false | FastifyCompressOptions['encodings']; cache_control?: { static_assets: string; }; } export interface BaseHttpDependencies { logger: pino.Logger; } export interface RegisterHttpEndpoint { (server: FastifyInstance, conf: HttpConfig, deps: Deps): void; } export interface ContentParser { (server: FastifyInstance, media_types: string[]): void; } export interface HttpParams { content_parsers: Record; endpoints: RegisterHttpEndpoint[]; } export function create_http_server(conf: HttpConfig, deps: Deps, params: HttpParams) { const server = fastify({ logger: deps.logger }); // Register error handlers // todo: register error handlers... // Register endpoints for (const endpoint of params.endpoints) { endpoint(server, conf, deps); } let resolve: () => void; let status: ServerStatus = 'unstarted'; const ready = new Promise((onResolve) => { resolve = onResolve; }); return { server, ready, get status() { return status; }, // async setup_plugins() { await Promise.all([ server.register(formbody), conf.etag ? server.register(etags) : null, conf.compress ? server.register(compress, { encodings: conf.compress }) : null, ]); }, async listen() { status = 'starting'; try { await server.listen({ port: conf.port, host: conf.address }); } catch (error) { server.log.error(error); process.exit(1); } await server.ready(); status = 'ready'; resolve(); }, async close() { status = 'closing'; await server.close(); status = 'closed'; }, }; }