diff options
Diffstat (limited to 'services/docker/mail-server/relay/config.ts')
-rw-r--r-- | services/docker/mail-server/relay/config.ts | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/services/docker/mail-server/relay/config.ts b/services/docker/mail-server/relay/config.ts new file mode 100644 index 0000000..ec7e7d4 --- /dev/null +++ b/services/docker/mail-server/relay/config.ts @@ -0,0 +1,110 @@ +import { transformProperties } from "./util.ts"; + +export const APP_PREFIX = "crupest"; +export const APP_NAME = "mailserver"; + +interface ConfigItemDef { + env: string; + description: string; + default?: string; + secret?: boolean; +} + +export const CONFIG_DEFS = { + mailDomain: { + env: "MAIL_DOMAIN", + description: "the part after `@` of an address", + }, + dataPath: { + env: "DATA_PATH", + description: "path to save app persistent data", + }, + ldaPath: { + env: "LDA_PATH", + description: "full path of lda executable", + "default": "/dovecot/libexec/dovecot/dovecot-lda", + }, + inboundFallback: { + env: "INBOUND_FALLBACK", + description: "comma separated addresses used as fallback receipts", + "default": "", + }, + awsInboundPath: { + env: "AWS_INBOUND_PATH", + description: "(random set) path for aws sns", + }, + awsInboundKey: { + env: "AWS_INBOUND_KEY", + description: "(random set) http header Authorization for aws sns", + }, + awsRegion: { env: "AWS_REGION", description: "aws region" }, + awsAccessKeyId: { env: "AWS_USER", description: "aws access key id" }, + awsSecretAccessKey: { + env: "AWS_PASSWORD", + description: "aws secret access key", + secret: true, + }, + awsMailBucket: { + env: "AWS_MAIL_BUCKET", + description: "aws s3 bucket saving raw mails", + secret: true, + }, +} as const satisfies Record<string, ConfigItemDef>; + +type ConfigDefs = typeof CONFIG_DEFS; +type ConfigKey = keyof ConfigDefs; +type ConfigMap = { + [K in ConfigKey]: ConfigItemDef & { value: string }; +}; + +function getFullEnvKey(key: string): string { + return `${APP_PREFIX.toUpperCase()}_${APP_NAME.toUpperCase()}_${key}`; +} + +function resolveAppConfigItem(def: ConfigItemDef): string { + const envKey = getFullEnvKey(def.env); + const value = Deno.env.get(envKey); + if (value != null) return value; + if (def.default != null) return def.default; + throw new Error( + `Required env ${envKey} (${def.description}) is not set.`, + ); +} + +export class Config { + #config = transformProperties( + CONFIG_DEFS, + (def) => ({ ...def, value: resolveAppConfigItem(def) }), + ) as ConfigMap; + + readonly HTTP_HOST = "0.0.0.0"; + readonly HTTP_PORT = 2345; + readonly SMTP_HOST = "127.0.0.1"; + readonly SMTP_PORT = 2346; + + get<K extends ConfigKey>(key: K): ConfigMap[K] { + return this.#config[key]; + } + + getValue(key: ConfigKey): string { + return this.get(key).value; + } + + getValueList(key: ConfigKey, separator: string = ","): string[] { + const value = this.getValue(key); + if (value.length === 0) return []; + return value.split(separator); + } + + [Symbol.for("Deno.customInspect")]() { + return Object.entries(this.#config).map(([key, item]) => + `${key} [env: ${getFullEnvKey(item.env)}]: ${ + item.secret === true ? "***" : item.value + }` + ).join("\n"); + } +} + +const config = new Config(); +export default config; +export const getConfigValue = config.getValue.bind(config); |