From 709274987658f52594073ab6810205da19804038 Mon Sep 17 00:00:00 2001 From: red Date: Wed, 25 Feb 2026 04:35:46 +0000 Subject: [PATCH] gotta fix storage. --- src/cli-shared.ts | 49 ++++++++++++++++++++++++++++++++++++++----- src/cli.ts | 43 +++++++++++++++++++++++++++++++++----- src/daemon.ts | 51 ++++++++++++++++++++++++++++++++++++--------- src/utils/config.ts | 1 + test_curl.sh | 11 ++++++++++ 5 files changed, 135 insertions(+), 20 deletions(-) create mode 100755 test_curl.sh diff --git a/src/cli-shared.ts b/src/cli-shared.ts index 2a8ea33..f8d6709 100644 --- a/src/cli-shared.ts +++ b/src/cli-shared.ts @@ -1,8 +1,10 @@ import { program } from "commander"; -import { existsSync } from "fs"; +import { existsSync, createWriteStream } from "fs"; +import { appendFile } from "fs/promises"; import { CONFIG_FILE, DEFAULT_CONFIG, + LOG_FILE, type RoutstrdConfig, } from "./utils/config"; @@ -55,12 +57,27 @@ export async function isDaemonRunning(): Promise { } export async function startDaemonProcess(): Promise { - const proc = Bun.spawn({ - cmd: ["bun", "run", `${import.meta.dir}/index.ts`, "daemon"], - stdout: "ignore", - stderr: "ignore", + const logWriter = createLogWriter(); + const proc = Bun.spawn([ + "bun", "run", `${import.meta.dir}/index.ts`, "daemon" + ], { + stdout: "pipe", + stderr: "pipe", stdin: "ignore", }); + + proc.stdout?.pipeTo(new WritableStream({ + write(data) { + logWriter.write(data.toString()); + } + })); + + proc.stderr?.pipeTo(new WritableStream({ + write(data) { + logWriter.writeError(data.toString()); + } + })); + proc.unref(); for (let i = 0; i < 50; i++) { @@ -121,3 +138,25 @@ export async function handleDaemonCommand( } export { program, callDaemon }; + +async function writeToLog(line: string): Promise { + try { + await appendFile(LOG_FILE, line + "\n"); + } catch { + // Ignore log errors + } +} + +function createLogWriter() { + let logStream: ReturnType | null = null; + return { + write(data: string) { + process.stdout.write(data); + writeToLog(data.trimEnd()); + }, + writeError(data: string) { + process.stderr.write(data); + writeToLog(data.trimEnd()); + }, + }; +} diff --git a/src/cli.ts b/src/cli.ts index c64b12d..07d5341 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -6,12 +6,14 @@ import { ensureDaemonRunning, isDaemonRunning, } from "./cli-shared"; -import { existsSync, mkdirSync } from "fs"; +import { existsSync, mkdirSync, createWriteStream } from "fs"; +import { appendFile } from "fs/promises"; import { join } from "path"; import { CONFIG_DIR, DB_PATH, CONFIG_FILE, + LOG_FILE, DEFAULT_CONFIG, type RoutstrdConfig, } from "./utils/config"; @@ -40,12 +42,43 @@ async function initDaemon(): Promise { console.log(`Database will be stored at: ${DB_PATH}`); console.log("\nInitializing cocod..."); + async function writeToLog(line: string): Promise { + try { + await appendFile(LOG_FILE, line + "\n"); + } catch { + // Ignore log errors + } + } + + const logWriter = { + write(data: string) { + process.stdout.write(data); + writeToLog(data.trimEnd()); + }, + writeError(data: string) { + process.stderr.write(data); + writeToLog(data.trimEnd()); + }, + }; + // Initialize cocod - const initProc = Bun.spawn({ - cmd: ["cocod", "init"], - stdout: "inherit", - stderr: "inherit", + const initProc = Bun.spawn(["cocod", "init"], { + stdout: "pipe", + stderr: "pipe", }); + + initProc.stdout?.pipeTo(new WritableStream({ + write(data) { + logWriter.write(data.toString()); + } + })); + + initProc.stderr?.pipeTo(new WritableStream({ + write(data) { + logWriter.writeError(data.toString()); + } + })); + const initCode = await initProc.exited; if (initCode !== 0) { diff --git a/src/daemon.ts b/src/daemon.ts index e521a22..770746a 100644 --- a/src/daemon.ts +++ b/src/daemon.ts @@ -3,7 +3,7 @@ import { Readable } from "stream"; import { ReadableStream as WebReadableStream } from "stream/web"; import { spawn } from "child_process"; import { getDecodedToken } from "@cashu/cashu-ts"; -import { mkdir } from "fs/promises"; +import { mkdir, appendFile } from "fs/promises"; import { join } from "path"; import { existsSync } from "fs"; import SQLite from "bun:sqlite"; @@ -13,6 +13,7 @@ import { SOCKET_PATH, PID_FILE, CONFIG_FILE, + LOG_FILE, DEFAULT_CONFIG, type RoutstrdConfig, } from "./utils/config"; @@ -32,7 +33,7 @@ async function loadSdk() { function createBunSqliteDriver(dbPath: string) { const db = new SQLite(dbPath); - db.exec(` + db.run(` CREATE TABLE IF NOT EXISTS sdk_storage ( key TEXT PRIMARY KEY, value TEXT NOT NULL @@ -245,11 +246,10 @@ async function main(): Promise { saveConfig(updatedConfig); const sdkModule = await loadSdk(); - const { ModelManager, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultStorageAdapter, createMemoryDriver, createSdkStore } = sdkModule; + const { ModelManager, getDefaultDiscoveryAdapter, getDefaultProviderRegistry, getDefaultStorageAdapter, createSdkStore } = sdkModule; - // For now, use memory driver (can be upgraded to sqlite later) - const memoryDriver = createMemoryDriver(); - const store = createSdkStore({ driver: memoryDriver }); + const sqliteDriver = createBunSqliteDriver(DB_PATH); + const store = createSdkStore({ driver: sqliteDriver }); // Get adapters (these use the default store, but we'll work with what we have) const discoveryAdapter = getDefaultDiscoveryAdapter(); @@ -590,13 +590,44 @@ export async function startDaemon(options: { port?: string; provider?: string } args.push("--provider", options.provider); } + async function writeToLog(line: string): Promise { + try { + await appendFile(LOG_FILE, line + "\n"); + } catch { + // Ignore log errors + } + } + + const logWriter = { + write(data: string) { + process.stdout.write(data); + writeToLog(data.trimEnd()); + }, + writeError(data: string) { + process.stderr.write(data); + writeToLog(data.trimEnd()); + }, + }; + // Spawn daemon.ts directly as a detached background process - const proc = Bun.spawn({ - cmd: ["bun", "run", `${import.meta.dir}/daemon.ts`, ...args], - stdout: "inherit", - stderr: "inherit", + const proc = Bun.spawn(["bun", "run", `${import.meta.dir}/daemon.ts`, ...args], { + stdout: "pipe", + stderr: "pipe", stdin: "ignore", }); + + proc.stdout?.pipeTo(new WritableStream({ + write(data) { + logWriter.write(data.toString()); + } + })); + + proc.stderr?.pipeTo(new WritableStream({ + write(data) { + logWriter.writeError(data.toString()); + } + })); + proc.unref(); const port = options.port || "8008"; diff --git a/src/utils/config.ts b/src/utils/config.ts index 205256b..acc27a8 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -5,6 +5,7 @@ export const SOCKET_PATH = process.env.ROUTSTRD_SOCKET || `${CONFIG_DIR}/routstr export const PID_FILE = process.env.ROUTSTRD_PID || `${CONFIG_DIR}/routstrd.pid`; export const DB_PATH = `${CONFIG_DIR}/routstr.db`; export const CONFIG_FILE = `${CONFIG_DIR}/config.json`; +export const LOG_FILE = `${CONFIG_DIR}/routstrd.log`; export interface RoutstrdConfig { port: number; diff --git a/test_curl.sh b/test_curl.sh new file mode 100755 index 0000000..f6c2d16 --- /dev/null +++ b/test_curl.sh @@ -0,0 +1,11 @@ +#!/bin/bash +curl -X POST "http://localhost:8008/v1/chat/completions" \ + -H "Authorization: Bearer YOUR_API_KEY" \ + -H "Content-Type: application/json" \ + -d '{ + "model": "gemma-3n-e4b-it", + "messages": [ + {"role":"system","content":"You are Routstr."}, + {"role":"user","content":"Ping the node"} + ] + }'