Files
smartdb/ts/ts_smartdb/rust-db-bridge.ts

139 lines
4.1 KiB
TypeScript

import * as plugins from './plugins.js';
import * as path from 'path';
import * as url from 'url';
import { EventEmitter } from 'events';
/**
* Type-safe command definitions for the RustDb IPC protocol.
*/
type TSmartDbCommands = {
start: { params: { config: ISmartDbRustConfig }; result: { connectionUri: string } };
stop: { params: Record<string, never>; result: void };
getStatus: { params: Record<string, never>; result: { running: boolean } };
getMetrics: { params: Record<string, never>; result: any };
};
/**
* Configuration sent to the Rust binary on start.
*/
interface ISmartDbRustConfig {
port?: number;
host?: string;
socketPath?: string;
storage: 'memory' | 'file';
storagePath?: string;
persistPath?: string;
persistIntervalMs?: number;
}
/**
* Get the package root directory using import.meta.url.
* This file is at ts/ts_smartdb/, so package root is 2 levels up.
*/
function getPackageRoot(): string {
const thisDir = path.dirname(url.fileURLToPath(import.meta.url));
return path.resolve(thisDir, '..', '..');
}
/**
* Map Node.js process.platform/process.arch to tsrust's friendly name suffix.
* tsrust names cross-compiled binaries as: rustdb_linux_amd64, rustdb_linux_arm64, etc.
*/
function getTsrustPlatformSuffix(): string | null {
const archMap: Record<string, string> = { x64: 'amd64', arm64: 'arm64' };
const osMap: Record<string, string> = { linux: 'linux', darwin: 'macos' };
const os = osMap[process.platform];
const arch = archMap[process.arch];
if (os && arch) {
return `${os}_${arch}`;
}
return null;
}
/**
* Build local search paths for the Rust binary, including dist_rust/ candidates
* (built by tsrust) and local development build paths.
*/
function buildLocalPaths(): string[] {
const packageRoot = getPackageRoot();
const suffix = getTsrustPlatformSuffix();
const paths: string[] = [];
// dist_rust/ candidates (tsrust cross-compiled output)
if (suffix) {
paths.push(path.join(packageRoot, 'dist_rust', `rustdb_${suffix}`));
}
paths.push(path.join(packageRoot, 'dist_rust', 'rustdb'));
// Local dev build paths
paths.push(path.resolve(process.cwd(), 'rust', 'target', 'release', 'rustdb'));
paths.push(path.resolve(process.cwd(), 'rust', 'target', 'debug', 'rustdb'));
return paths;
}
/**
* Bridge between TypeScript SmartdbServer and the Rust binary.
* Wraps @push.rocks/smartrust's RustBridge with type-safe command definitions.
*/
export class RustDbBridge extends EventEmitter {
private bridge: plugins.smartrust.RustBridge<TSmartDbCommands>;
constructor() {
super();
this.bridge = new plugins.smartrust.RustBridge<TSmartDbCommands>({
binaryName: 'rustdb',
envVarName: 'SMARTDB_RUST_BINARY',
platformPackagePrefix: '@push.rocks/smartdb',
localPaths: buildLocalPaths(),
maxPayloadSize: 10 * 1024 * 1024, // 10 MB
});
// Forward events from the inner bridge
this.bridge.on('exit', (code: number | null, signal: string | null) => {
this.emit('exit', code, signal);
});
}
/**
* Spawn the Rust binary in management mode.
* Returns true if the binary was found and spawned successfully.
*/
public async spawn(): Promise<boolean> {
return this.bridge.spawn();
}
/**
* Kill the Rust process and clean up.
*/
public kill(): void {
this.bridge.kill();
}
/**
* Whether the bridge is currently running.
*/
public get running(): boolean {
return this.bridge.running;
}
// --- Convenience methods for each management command ---
public async startDb(config: ISmartDbRustConfig): Promise<{ connectionUri: string }> {
return await this.bridge.sendCommand('start', { config }) as { connectionUri: string };
}
public async stopDb(): Promise<void> {
await this.bridge.sendCommand('stop', {} as Record<string, never>);
}
public async getStatus(): Promise<{ running: boolean }> {
return await this.bridge.sendCommand('getStatus', {} as Record<string, never>) as { running: boolean };
}
public async getMetrics(): Promise<any> {
return this.bridge.sendCommand('getMetrics', {} as Record<string, never>);
}
}