mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-26 02:04:37 +08:00
feat(server): isolate better-sqlite3 native binary for Electron/Node coexistence
Add rebuild-native.sh script that compiles better-sqlite3 in an isolated temp directory for system Node.js, storing the binary at packages/server/native/. DatabaseManager and openBetterSqliteDatabase now accept nativeBinding option. CLI auto-detects non-Electron environment and uses the isolated binary.
This commit is contained in:
1 parent
0d0dbdb6ce
commit
d040aaaa98
6 files changed
+68
-3
No files matched your search
@@ -17,6 +17,7 @@ error-log-*.txt
|
||||
|
||||
# Project
|
||||
dist/
|
||||
packages/server/native/
|
||||
.history/
|
||||
out
|
||||
.obskey
|
||||
|
||||
@@ -61,13 +61,17 @@ export class BetterSqliteAdapter implements DatabaseAdapter {
|
||||
|
||||
/**
|
||||
* 从文件路径打开数据库并返回适配器
|
||||
*
|
||||
* @param options.nativeBinding - 指定 better-sqlite3 原生模块路径,
|
||||
* 用于在独立 Node.js 环境中加载与 Electron 隔离的二进制。
|
||||
*/
|
||||
export function openBetterSqliteDatabase(
|
||||
filePath: string,
|
||||
options?: { readonly?: boolean }
|
||||
options?: { readonly?: boolean; nativeBinding?: string }
|
||||
): BetterSqliteAdapter {
|
||||
const db = new Database(filePath, {
|
||||
readonly: options?.readonly ?? false,
|
||||
nativeBinding: options?.nativeBinding,
|
||||
})
|
||||
db.pragma('journal_mode = WAL')
|
||||
return new BetterSqliteAdapter(db)
|
||||
|
||||
@@ -14,8 +14,14 @@ import { openBetterSqliteDatabase } from './better-sqlite3-adapter'
|
||||
|
||||
export class DatabaseManager {
|
||||
private cache = new Map<string, DatabaseAdapter>()
|
||||
private nativeBinding?: string
|
||||
|
||||
constructor(private pathProvider: PathProvider) {}
|
||||
constructor(
|
||||
private pathProvider: PathProvider,
|
||||
options?: { nativeBinding?: string }
|
||||
) {
|
||||
this.nativeBinding = options?.nativeBinding
|
||||
}
|
||||
|
||||
/**
|
||||
* 打开指定会话的数据库(带缓存)
|
||||
@@ -30,6 +36,7 @@ export class DatabaseManager {
|
||||
|
||||
const adapter = openBetterSqliteDatabase(dbPath, {
|
||||
readonly: options?.readonly ?? true,
|
||||
nativeBinding: this.nativeBinding,
|
||||
})
|
||||
this.cache.set(sessionId, adapter)
|
||||
return adapter
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
"types": "./src/index.ts",
|
||||
"scripts": {
|
||||
"cli": "tsx src/cli.ts",
|
||||
"rebuild-native": "bash scripts/rebuild-native.sh",
|
||||
"rebuild-sqlite": "npm rebuild better-sqlite3"
|
||||
},
|
||||
"dependencies": {
|
||||
|
||||
Executable
+38
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 在隔离目录中编译 better-sqlite3 的系统 Node.js 原生模块,
|
||||
# 避免与 electron-rebuild 产生冲突。
|
||||
#
|
||||
# 产物:packages/server/native/better_sqlite3.node
|
||||
#
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
SERVER_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
TARGET_DIR="$SERVER_DIR/native"
|
||||
|
||||
# 获取当前 workspace 中 better-sqlite3 的版本
|
||||
BS3_VERSION=$(node -e "const p = require('better-sqlite3/package.json'); console.log(p.version)")
|
||||
echo "Building better-sqlite3@${BS3_VERSION} for system Node.js ($(node -v))..."
|
||||
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
trap "rm -rf $TEMP_DIR" EXIT
|
||||
|
||||
cd "$TEMP_DIR"
|
||||
npm init -y > /dev/null 2>&1
|
||||
npm install "better-sqlite3@${BS3_VERSION}" --ignore-scripts > /dev/null 2>&1
|
||||
|
||||
cd "node_modules/better-sqlite3"
|
||||
npx --yes prebuild-install -r napi || npm run build-release 2>/dev/null || npx --yes node-gyp rebuild --release
|
||||
|
||||
BUILT="$TEMP_DIR/node_modules/better-sqlite3/build/Release/better_sqlite3.node"
|
||||
if [ ! -f "$BUILT" ]; then
|
||||
echo "Error: native binary not found at $BUILT"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mkdir -p "$TARGET_DIR"
|
||||
cp "$BUILT" "$TARGET_DIR/better_sqlite3.node"
|
||||
|
||||
echo "Done. Native binary saved to $TARGET_DIR/better_sqlite3.node"
|
||||
echo " ABI: $(node -e 'console.log(process.versions.modules)')"
|
||||
@@ -5,6 +5,8 @@
|
||||
* 开发阶段运行方式:pnpm --filter chatlab cli -- sessions
|
||||
*/
|
||||
|
||||
import * as fs from 'fs'
|
||||
import * as path from 'path'
|
||||
import { Command } from 'commander'
|
||||
import { loadConfig, getConfigPath } from '@openchatlab/config'
|
||||
import { NodePathProvider, DatabaseManager } from '@openchatlab/node-runtime'
|
||||
@@ -227,12 +229,24 @@ configCmd
|
||||
|
||||
// --- 工具函数 ---
|
||||
|
||||
/**
|
||||
* 查找独立编译的 better-sqlite3 原生模块路径。
|
||||
* 在非 Electron 环境下使用,避免与 electron-rebuild 冲突。
|
||||
*/
|
||||
function resolveNativeBinding(): string | undefined {
|
||||
if (process.versions.electron) return undefined
|
||||
const nativePath = path.resolve(__dirname, '../native/better_sqlite3.node')
|
||||
if (fs.existsSync(nativePath)) return nativePath
|
||||
return undefined
|
||||
}
|
||||
|
||||
function initRuntime() {
|
||||
const config = loadConfig()
|
||||
const dataDir = config.data.dir || undefined
|
||||
const pathProvider = new NodePathProvider(dataDir)
|
||||
pathProvider.ensureAllDirs()
|
||||
const dbManager = new DatabaseManager(pathProvider)
|
||||
const nativeBinding = resolveNativeBinding()
|
||||
const dbManager = new DatabaseManager(pathProvider, { nativeBinding })
|
||||
return { config, pathProvider, dbManager }
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user