import { BaseRequest, Either, IEither, LogMetricTraceable, Metric, PenguenoRequest, Server, Signals, TraceUtil, } from '@emprespresso/pengueno'; import type { ServerType } from '@hono/node-server'; import type { Hono } from 'hono'; const AppLifetimeMetric = Metric.fromName('HonoAppLifetime').asResult(); const AppRequestMetric = Metric.fromName('HonoAppRequest'); export class HonoProxy { private app?: LogMetricTraceable; constructor(private readonly server: Server) {} private async initializeApp() { if (this.app) return this.app; const { Hono } = await import('hono'); this.app = LogMetricTraceable.of(new Hono()) .flatMap(TraceUtil.withTrace(`AppId = ${crypto.randomUUID()}`)) .flatMap(TraceUtil.withMetricTrace(AppLifetimeMetric)) as LogMetricTraceable; return this.app; } public async serve(port: number, hostname: string): Promise> { const { serve } = await import('@hono/node-server'); const app = await this.initializeApp(); return app .map((tApp) => Either.fromFailable(() => { const app = tApp.get(); app.all('*', async (c) => tApp .flatMap(TraceUtil.withMetricTrace(AppRequestMetric)) .move(c.req) .flatMap((tRequest) => PenguenoRequest.from(tRequest)) .map((req) => this.server.serve(req)) .map( TraceUtil.promiseify((tResponse) => { tResponse.trace.trace(AppRequestMetric.count.withValue(1.0)); return new Response(tResponse.get().body(), tResponse.get()); }), ) .get(), ); return serve({ fetch: (_r) => app.fetch(_r), port, hostname, }); }), ) .peek(TraceUtil.traceResultingEither()) .peek((tServe) => tServe .get() .mapRight(() => tServe.trace.trace( `haii im still listening at http://${hostname}:${port} ~uwu dont think i forgot`, ), ), ) .map((tEitherServer) => tEitherServer .get() .mapRight((server) => tEitherServer.move(server)) .flatMapAsync((tServer) => Signals.awaitClose(tServer)), ) .peek(TraceUtil.promiseify(TraceUtil.traceResultingEither(AppLifetimeMetric))) .get(); } }