fix(smarts3): replace TypeScript server with Rust-powered core and IPC bridge

This commit is contained in:
2026-02-13 13:59:44 +00:00
parent 54a0c2fb65
commit 65eb266983
32 changed files with 4083 additions and 3182 deletions

View File

@@ -1,6 +1,5 @@
import * as plugins from './plugins.js';
import * as paths from './paths.js';
import { Smarts3Server } from './classes/smarts3-server.js';
/**
* Authentication configuration
@@ -165,6 +164,15 @@ function mergeConfig(userConfig: ISmarts3Config): Required<ISmarts3Config> {
};
}
/**
* IPC command type map for RustBridge
*/
type TRustS3Commands = {
start: { params: { config: Required<ISmarts3Config> }; result: {} };
stop: { params: {}; result: {} };
createBucket: { params: { name: string }; result: {} };
};
/**
* Main Smarts3 class - production-ready S3-compatible server
*/
@@ -178,22 +186,28 @@ export class Smarts3 {
// INSTANCE
public config: Required<ISmarts3Config>;
public s3Instance: Smarts3Server;
private bridge: InstanceType<typeof plugins.RustBridge<TRustS3Commands>>;
constructor(configArg: ISmarts3Config = {}) {
this.config = mergeConfig(configArg);
this.bridge = new plugins.RustBridge<TRustS3Commands>({
binaryName: 'rusts3',
localPaths: [
plugins.path.join(paths.packageDir, 'dist_rust', 'rusts3'),
plugins.path.join(paths.packageDir, 'rust', 'target', 'release', 'rusts3'),
plugins.path.join(paths.packageDir, 'rust', 'target', 'debug', 'rusts3'),
],
readyTimeoutMs: 30000,
requestTimeoutMs: 300000,
});
}
public async start() {
this.s3Instance = new Smarts3Server({
port: this.config.server.port,
address: this.config.server.address,
directory: this.config.storage.directory,
cleanSlate: this.config.storage.cleanSlate,
silent: this.config.server.silent,
config: this.config, // Pass full config to server
});
await this.s3Instance.start();
const spawned = await this.bridge.spawn();
if (!spawned) {
throw new Error('Failed to spawn rusts3 binary. Make sure it is compiled (pnpm build).');
}
await this.bridge.sendCommand('start', { config: this.config });
if (!this.config.server.silent) {
console.log('s3 server is running');
@@ -203,7 +217,20 @@ export class Smarts3 {
public async getS3Descriptor(
optionsArg?: Partial<plugins.tsclass.storage.IS3Descriptor>,
): Promise<plugins.tsclass.storage.IS3Descriptor> {
const descriptor = this.s3Instance.getS3Descriptor();
const cred = this.config.auth.credentials[0] || {
accessKeyId: 'S3RVER',
secretAccessKey: 'S3RVER',
};
const descriptor: plugins.tsclass.storage.IS3Descriptor = {
endpoint: this.config.server.address === '0.0.0.0' ? 'localhost' : this.config.server.address!,
port: this.config.server.port!,
useSsl: false,
accessKey: cred.accessKeyId,
accessSecret: cred.secretAccessKey,
bucketName: '',
};
return {
...descriptor,
...(optionsArg ? optionsArg : {}),
@@ -211,15 +238,12 @@ export class Smarts3 {
}
public async createBucket(bucketNameArg: string) {
// Call the filesystem store directly instead of using the client library
await this.s3Instance.store.createBucket(bucketNameArg);
await this.bridge.sendCommand('createBucket', { name: bucketNameArg });
return { name: bucketNameArg };
}
public async stop() {
await this.s3Instance.stop();
await this.bridge.sendCommand('stop', {});
this.bridge.kill();
}
}
// Export the custom server class for direct use
export { Smarts3Server } from './classes/smarts3-server.js';