feat: Add log streaming functionality for Docker containers and improve platform service type handling in HTTP server

This commit is contained in:
2025-11-25 08:34:10 +00:00
parent e94906b3bf
commit 76793d512b
3 changed files with 55 additions and 6 deletions

View File

@@ -939,4 +939,49 @@ export class OneboxDockerManager {
} }
return this.dockerClient.listContainers(); return this.dockerClient.listContainers();
} }
/**
* Stream container logs continuously
* @param containerID The container ID
* @param callback Callback for each log line (line, isError)
*/
async streamContainerLogs(
containerID: string,
callback: (line: string, isError: boolean) => void
): Promise<void> {
try {
const container = await this.dockerClient!.getContainerById(containerID);
if (!container) {
throw new Error(`Container not found: ${containerID}`);
}
const logStream = await container.streamLogs({
stdout: true,
stderr: true,
timestamps: true,
tail: 100,
});
logStream.on('data', (chunk: Uint8Array) => {
// Docker multiplexes stdout/stderr with 8-byte header
// Byte 0: stream type (1=stdout, 2=stderr)
// Bytes 4-7: frame size (big-endian)
// Rest: actual log data
const streamType = chunk[0];
const isError = streamType === 2;
const content = new TextDecoder().decode(chunk.slice(8));
if (content.trim()) {
callback(content.trim(), isError);
}
});
logStream.on('error', (err: Error) => {
logger.error(`Log stream error for ${containerID}: ${err.message}`);
});
} catch (error) {
logger.error(`Failed to stream logs for ${containerID}: ${getErrorMessage(error)}`);
throw error;
}
}
} }

View File

@@ -275,13 +275,13 @@ export class OneboxHttpServer {
} else if (path === '/api/platform-services' && method === 'GET') { } else if (path === '/api/platform-services' && method === 'GET') {
return await this.handleListPlatformServicesRequest(); return await this.handleListPlatformServicesRequest();
} else if (path.match(/^\/api\/platform-services\/(mongodb|minio|redis|postgresql|rabbitmq)$/) && method === 'GET') { } else if (path.match(/^\/api\/platform-services\/(mongodb|minio|redis|postgresql|rabbitmq)$/) && method === 'GET') {
const type = path.split('/').pop()!; const type = path.split('/').pop()! as TPlatformServiceType;
return await this.handleGetPlatformServiceRequest(type); return await this.handleGetPlatformServiceRequest(type);
} else if (path.match(/^\/api\/platform-services\/(mongodb|minio|redis|postgresql|rabbitmq)\/start$/) && method === 'POST') { } else if (path.match(/^\/api\/platform-services\/(mongodb|minio|redis|postgresql|rabbitmq)\/start$/) && method === 'POST') {
const type = path.split('/')[3]; const type = path.split('/')[3] as TPlatformServiceType;
return await this.handleStartPlatformServiceRequest(type); return await this.handleStartPlatformServiceRequest(type);
} else if (path.match(/^\/api\/platform-services\/(mongodb|minio|redis|postgresql|rabbitmq)\/stop$/) && method === 'POST') { } else if (path.match(/^\/api\/platform-services\/(mongodb|minio|redis|postgresql|rabbitmq)\/stop$/) && method === 'POST') {
const type = path.split('/')[3]; const type = path.split('/')[3] as TPlatformServiceType;
return await this.handleStopPlatformServiceRequest(type); return await this.handleStopPlatformServiceRequest(type);
} else if (path.match(/^\/api\/services\/[^/]+\/platform-resources$/) && method === 'GET') { } else if (path.match(/^\/api\/services\/[^/]+\/platform-resources$/) && method === 'GET') {
const serviceName = path.split('/')[3]; const serviceName = path.split('/')[3];

View File

@@ -45,10 +45,10 @@ export class RegistryManager {
this.s3Server = await plugins.smarts3.Smarts3.createAndStart({ this.s3Server = await plugins.smarts3.Smarts3.createAndStart({
server: { server: {
port: port, port: port,
host: '0.0.0.0', address: '0.0.0.0',
}, },
storage: { storage: {
bucketsDir: dataDir, directory: dataDir,
cleanSlate: false, // Preserve data across restarts cleanSlate: false, // Preserve data across restarts
}, },
}); });
@@ -70,9 +70,13 @@ export class RegistryManager {
}, },
auth: { auth: {
jwtSecret: this.jwtSecret, jwtSecret: this.jwtSecret,
tokenStore: 'memory',
npmTokens: {
enabled: false,
},
ociTokens: { ociTokens: {
enabled: true, enabled: true,
issuer: 'onebox-registry', realm: 'onebox-registry',
service: 'onebox-registry', service: 'onebox-registry',
}, },
}, },