Scratch space for learning atproto app development
1import events from 'node:events'
2import type http from 'node:http'
3import express, { type Express } from 'express'
4import { pino } from 'pino'
5
6import { createDb, migrateToLatest } from '#/db'
7import { env } from '#/env'
8import { Ingester } from '#/firehose/ingester'
9import errorHandler from '#/middleware/errorHandler'
10import requestLogger from '#/middleware/requestLogger'
11import { createRouter } from '#/routes'
12import { createClient } from '#/auth/client'
13import { createResolver } from '#/ident/resolver'
14import type { AppContext } from '#/config'
15
16export class Server {
17 constructor(
18 public app: express.Application,
19 public server: http.Server,
20 public ctx: AppContext
21 ) {}
22
23 static async create() {
24 const { NODE_ENV, HOST, PORT, DB_PATH } = env
25
26 const logger = pino({ name: 'server start' })
27 const db = createDb(DB_PATH)
28 await migrateToLatest(db)
29 const ingester = new Ingester(db)
30 const oauthClient = await createClient(db)
31 const resolver = createResolver()
32 ingester.start()
33 const ctx = {
34 db,
35 ingester,
36 logger,
37 oauthClient,
38 resolver,
39 }
40
41 const app: Express = express()
42
43 // Set the application to trust the reverse proxy
44 app.set('trust proxy', true)
45
46 // TODO: middleware for sqlite server
47 // TODO: middleware for OAuth
48
49 // Middlewares
50 app.use(express.json())
51 app.use(express.urlencoded({ extended: true }))
52
53 // Request logging
54 app.use(requestLogger)
55
56 // Routes
57 const router = createRouter(ctx)
58 app.use(router)
59
60 // Error handlers
61 app.use(errorHandler())
62
63 const server = app.listen(env.PORT)
64 await events.once(server, 'listening')
65 logger.info(`Server (${NODE_ENV}) running on port http://${HOST}:${PORT}`)
66
67 return new Server(app, server, ctx)
68 }
69
70 async close() {
71 this.ctx.logger.info('sigint received, shutting down')
72 this.ctx.ingester.destroy()
73 return new Promise<void>((resolve) => {
74 this.server.close(() => {
75 this.ctx.logger.info('server closed')
76 resolve()
77 })
78 })
79 }
80}