diff --git a/cli/commands/start.ts b/cli/commands/start.ts new file mode 100644 index 00000000..027a6d68 --- /dev/null +++ b/cli/commands/start.ts @@ -0,0 +1,49 @@ +import os from "node:os"; +import { Flags } from "@oclif/core"; +import { BaseCommand } from "~cli/base"; + +export default class Start extends BaseCommand { + static override args = {}; + + static override description = "Starts Lysand"; + + static override examples = [ + "<%= config.bin %> <%= command.id %> --threads 4", + "<%= config.bin %> <%= command.id %> --all-threads", + ]; + + static override flags = { + threads: Flags.integer({ + char: "t", + description: "Number of threads to use", + default: 1, + exclusive: ["all-threads"], + }), + "all-threads": Flags.boolean({ + description: "Use all available threads", + default: false, + exclusive: ["threads"], + }), + silent: Flags.boolean({ + description: "Don't show logs in console", + default: false, + }), + }; + + public async run(): Promise { + const { flags } = await this.parse(Start); + + const numCPUs = flags["all-threads"] ? os.cpus().length : flags.threads; + + for (let i = 0; i < numCPUs; i++) { + const args = ["bun", "index.ts"]; + if (i !== 0 || flags.silent) { + args.push("--silent"); + } + Bun.spawn(args, { + stdio: ["inherit", "inherit", "inherit"], + env: { ...process.env }, + }); + } + } +} diff --git a/cli/index.ts b/cli/index.ts index 17cd5a78..c4612205 100644 --- a/cli/index.ts +++ b/cli/index.ts @@ -3,6 +3,7 @@ import EmojiAdd from "./commands/emoji/add"; import EmojiDelete from "./commands/emoji/delete"; import EmojiImport from "./commands/emoji/import"; import EmojiList from "./commands/emoji/list"; +import Start from "./commands/start"; import UserCreate from "./commands/user/create"; import UserDelete from "./commands/user/delete"; import UserList from "./commands/user/list"; @@ -18,6 +19,7 @@ export const commands = { "emoji:delete": EmojiDelete, "emoji:list": EmojiList, "emoji:import": EmojiImport, + start: Start, }; if (import.meta.path === Bun.main) { diff --git a/drizzle/db.ts b/drizzle/db.ts index 63a400ed..83d75de2 100644 --- a/drizzle/db.ts +++ b/drizzle/db.ts @@ -20,6 +20,12 @@ export const setupDatabase = async ( try { await client.connect(); } catch (e) { + if ( + (e as Error).message === + "Client has already been connected. You cannot reuse a client." + ) + return; + await logger.logError(LogLevel.CRITICAL, "Database", e as Error); await logger.log( diff --git a/index.ts b/index.ts index 4188cce5..a405109e 100644 --- a/index.ts +++ b/index.ts @@ -18,7 +18,8 @@ import type { APIRouteExports } from "~types/api"; const timeAtStart = performance.now(); -const isEntry = import.meta.path === Bun.main; +const isEntry = + import.meta.path === Bun.main && !process.argv.includes("--silent"); let dualServerLogger: LogManager | MultiLogManager = new LogManager( Bun.file("/dev/null"), diff --git a/server.ts b/server.ts index d85fc356..d32dd826 100644 --- a/server.ts +++ b/server.ts @@ -4,6 +4,7 @@ import type { Hono } from "hono"; export const createServer = (config: Config, app: Hono) => Bun.serve({ port: config.http.bind_port, + reusePort: true, tls: config.http.tls.enabled ? { key: Bun.file(config.http.tls.key), diff --git a/tests/utils.ts b/tests/utils.ts index 81d91cf0..40d9ec11 100644 --- a/tests/utils.ts +++ b/tests/utils.ts @@ -1,17 +1,23 @@ import { randomBytes } from "node:crypto"; +import { consoleLogger } from "@loggers"; import { asc, inArray, like } from "drizzle-orm"; import type { Status } from "~database/entities/Status"; import { db } from "~drizzle/db"; +import { setupDatabase } from "~drizzle/db"; import { Notes, Tokens, Users } from "~drizzle/schema"; import { app } from "~index"; import { Note } from "~packages/database-interface/note"; import { User } from "~packages/database-interface/user"; + +await setupDatabase(consoleLogger); + /** * This allows us to send a test request to the server even when it isnt running * @param req Request to send * @returns Response from the server */ export async function sendTestRequest(req: Request) { + // return fetch(req); return app.fetch(req); }