feat: Add log streaming functionality for Docker containers and improve platform service type handling in HTTP server
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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];
|
||||||
|
|||||||
@@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user