main.ts

2.3 KB · raw

1import { join } from "node:path";2import type { Hono } from "hono";3import { createSetupApp } from "./admin/setup.ts";4import { startStorageLoop } from "./admin/storage.ts";5import { openBucket } from "./bucket/reader.ts";6import { startSyncWorker } from "./bucket/sync.ts";7import { openMirrors } from "./mirror/store.ts";8import { warmAtlas } from "./pages/atlas.ts";9import { createApp } from "./server/app.ts";10import { startBackupLoop } from "./server/backup.ts";11import { CONFIG_FILE, type Config, ConfigError, loadConfig } from "./server/config.ts";12import { oneTimeCode } from "./server/connect.ts";13import { openKeprDb } from "./server/db.ts";14import { startMailLoop } from "./server/mail.ts";1516// Where a first-run setup puts Kepr's data, beside kepr.toml.17const DATA_DIR = "data";1819/** Starts the loops for a config and returns the app that serves it. */20function start(config: Config): Hono["fetch"] {21	const kepr = openKeprDb(config.dataDir);22	// One bucket for the sync loop and the app, so settings saved in the console reach both.23	const bucket = openBucket(config.bucket);24	startBackupLoop(kepr, config);25	startMailLoop(kepr, config);26	const mirrorDir = join(config.dataDir, "mirror");27	openMirrors(mirrorDir);28	// The first visitor after a new save would otherwise wait a second or two on a big repo.29	const syncer = startSyncWorker(config.dataDir, config.bucket, (repo) =>30		warmAtlas({ kepr, mirrorDir }, repo),31	);32	startStorageLoop({ bucket, kepr, mirrorDir });33	return createApp(config, kepr, bucket, CONFIG_FILE, syncer).fetch;34}3536try {37	let fetch: Hono["fetch"];38	if (await Bun.file(CONFIG_FILE).exists()) {39		fetch = start(await loadConfig(CONFIG_FILE));40	} else {41		const code = oneTimeCode();42		fetch = createSetupApp({43			code,44			configPath: CONFIG_FILE,45			dataDir: DATA_DIR,46			done: (config) => {47				fetch = start(config);48			},49		}).fetch;50		console.log(51			`kepr: no ${CONFIG_FILE} yet. Open /setup in a browser and enter the code ${code.slice(0, 4)}-${code.slice(4)}`,52		);53	}54	// Bun.serve reads the port from $PORT (default 3000).55	const server = Bun.serve({ fetch: (request, bun) => fetch(request, bun) });56	console.log(`kepr listening on ${server.url}`);57} catch (error) {58	if (!(error instanceof ConfigError)) throw error;59	console.error(`kepr: ${error.message}`);60	process.exit(1);61}