summaryrefslogtreecommitdiff
path: root/lib/server/hono/proxy.ts
blob: 7f93804aecd4611f01d9f3973a51bab4751cf636 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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<Hono>;

    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<Hono>;

        return this.app;
    }

    public async serve(port: number, hostname: string): Promise<IEither<Error, void>> {
        const { serve } = await import('@hono/node-server');

        const app = await this.initializeApp();
        return app
            .map((tApp) =>
                Either.fromFailable<Error, ServerType>(() => {
                    const app = tApp.get();
                    app.all('*', async (c) =>
                        tApp
                            .flatMap(TraceUtil.withMetricTrace(AppRequestMetric))
                            .move(<BaseRequest>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();
    }
}