Initialize deploy/docker-compose

This commit is contained in:
Lucid Kobold
2025-02-19 10:12:52 -05:00
committed by GitHub
commit 621f177653
42 changed files with 8193 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
import type { Logger } from '#root/logger.js'
export interface Env {
Variables: {
requestId: string
logger: Logger
}
}

102
src/server/index.ts Normal file
View File

@@ -0,0 +1,102 @@
import type { Bot } from '#root/bot/index.js'
import type { Config } from '#root/config.js'
import type { Logger } from '#root/logger.js'
import type { Env } from '#root/server/environment.js'
import { setLogger } from '#root/server/middlewares/logger.js'
import { requestId } from '#root/server/middlewares/request-id.js'
import { requestLogger } from '#root/server/middlewares/request-logger.js'
import { serve } from '@hono/node-server'
import { webhookCallback } from 'grammy'
import { Hono } from 'hono'
import { HTTPException } from 'hono/http-exception'
import { getPath } from 'hono/utils/url'
interface Dependencies {
bot: Bot
config: Config
logger: Logger
}
export function createServer(dependencies: Dependencies) {
const {
bot,
config,
logger,
} = dependencies
const server = new Hono<Env>()
server.use(requestId())
server.use(setLogger(logger))
if (config.isDebug)
server.use(requestLogger())
server.onError(async (error, c) => {
if (error instanceof HTTPException) {
if (error.status < 500)
c.var.logger.info(error)
else
c.var.logger.error(error)
return error.getResponse()
}
// unexpected error
c.var.logger.error({
err: error,
method: c.req.raw.method,
path: getPath(c.req.raw),
})
return c.json(
{
error: 'Oops! Something went wrong.',
},
500,
)
})
server.get('/', c => c.json({ status: true }))
if (config.isWebhookMode) {
server.post(
'/webhook',
webhookCallback(bot, 'hono', {
secretToken: config.botWebhookSecret,
}),
)
}
return server
}
export type Server = Awaited<ReturnType<typeof createServer>>
export function createServerManager(server: Server, options: { host: string, port: number }) {
let handle: undefined | ReturnType<typeof serve>
return {
start() {
return new Promise<{ url: string }>((resolve) => {
handle = serve(
{
fetch: server.fetch,
hostname: options.host,
port: options.port,
},
info => resolve({
url: info.family === 'IPv6'
? `http://[${info.address}]:${info.port}`
: `http://${info.address}:${info.port}`,
}),
)
})
},
stop() {
return new Promise<void>((resolve) => {
if (handle)
handle.close(() => resolve())
else
resolve()
})
},
}
}

View File

@@ -0,0 +1,15 @@
import type { Logger } from '#root/logger.js'
import type { MiddlewareHandler } from 'hono'
export function setLogger(logger: Logger): MiddlewareHandler {
return async (c, next) => {
c.set(
'logger',
logger.child({
requestId: c.get('requestId'),
}),
)
await next()
}
}

View File

@@ -0,0 +1,10 @@
import type { MiddlewareHandler } from 'hono'
import { randomUUID } from 'node:crypto'
export function requestId(): MiddlewareHandler {
return async (c, next) => {
c.set('requestId', randomUUID())
await next()
}
}

View File

@@ -0,0 +1,27 @@
import type { MiddlewareHandler } from 'hono'
import { getPath } from 'hono/utils/url'
export function requestLogger(): MiddlewareHandler {
return async (c, next) => {
const { method } = c.req
const path = getPath(c.req.raw)
c.var.logger.debug({
msg: 'Incoming request',
method,
path,
})
const startTime = performance.now()
await next()
const endTime = performance.now()
c.var.logger.debug({
msg: 'Request completed',
method,
path,
status: c.res.status,
elapsed: endTime - startTime,
})
}
}