diff options
Diffstat (limited to 'services/docker/mail-server/relay/app.ts')
-rw-r--r-- | services/docker/mail-server/relay/app.ts | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/services/docker/mail-server/relay/app.ts b/services/docker/mail-server/relay/app.ts new file mode 100644 index 0000000..3a85996 --- /dev/null +++ b/services/docker/mail-server/relay/app.ts @@ -0,0 +1,78 @@ +import { join } from "@std/path"; +import { Hono } from "hono"; +import { logger as honoLogger } from "hono/logger"; + +import logger, { error } from "./logger.ts"; +import config from "./config.ts"; +import { DbService } from "./db.ts"; +import { + AliasFileMailHook, + FallbackReceiptsHook, + MailDeliverer, +} from "./mail.ts"; +import { DovecotMailDeliverer } from "./dovecot.ts"; +import { CronTask, CronTaskConfig } from "./cron.ts"; +import { DumbSMTPServer as DumbSmtpServer } from "./dumb-smtp-server.ts"; + +export abstract class AppBase { + protected readonly db: DbService; + protected readonly crons: CronTask[] = []; + protected readonly routes: Hono[] = []; + protected readonly inboundDeliverer: MailDeliverer; + protected readonly hono = new Hono(); + + protected abstract readonly outboundDeliverer: MailDeliverer; + + constructor() { + const dataPath = config.getValue("dataPath"); + Deno.mkdirSync(dataPath, { recursive: true }); + logger.path = join(dataPath, "log"); + logger.log(config); + + this.db = new DbService(join(dataPath, "db.sqlite")); + this.inboundDeliverer = new DovecotMailDeliverer(); + this.inboundDeliverer.preHooks.push( + new FallbackReceiptsHook(new Set(config.getValueList("inboundFallback"))), + new AliasFileMailHook(join(dataPath, "aliases.csv")), + ); + + this.hono.onError((err, c) => { + error(err); + return c.json({ msg: "Server error." }, 500); + }); + + this.hono.use(honoLogger()); + this.hono.post("/send/raw", async (context) => { + const body = await context.req.text(); + if (body.trim().length === 0) { + return context.json({ msg: "Can't send an empty mail" }, 400); + } else { + const mail = await this.outboundDeliverer.deliverRaw(body); + return context.json({ + messageId: mail.messageId, + awsMessageId: mail.awsMessageId, + }); + } + }); + this.hono.post("/receive/raw", async (context) => { + await this.inboundDeliverer.deliverRaw(await context.req.text()); + return context.json({}); + }); + } + + createCron(config: CronTaskConfig): CronTask { + const cron = new CronTask(config); + this.crons.push(cron); + return cron; + } + + serve(): { smtp: DumbSmtpServer; http: Deno.HttpServer } { + const smtp = new DumbSmtpServer(this.outboundDeliverer); + smtp.serve(); + const http = Deno.serve({ + hostname: config.HTTP_HOST, + port: config.HTTP_PORT, + }, this.hono.fetch); + return { smtp, http }; + } +} |