This commit is contained in:
2025-11-26 12:16:50 +00:00
parent e6f7d70d51
commit c46ceccb6c
13 changed files with 1970 additions and 473 deletions

View File

@@ -83,6 +83,11 @@ export class OneboxHttpServer {
return this.handleLogStreamUpgrade(req, serviceName);
}
// Network access logs WebSocket
if (path === '/api/network/logs/stream' && req.headers.get('upgrade') === 'websocket') {
return this.handleNetworkLogStreamUpgrade(req, new URL(req.url));
}
// Docker Registry v2 Token endpoint (for OCI authentication)
if (path === '/v2/token') {
return await this.handleRegistryTokenRequest(req, url);
@@ -291,6 +296,11 @@ export class OneboxHttpServer {
} else if (path.match(/^\/api\/services\/[^/]+\/platform-resources$/) && method === 'GET') {
const serviceName = path.split('/')[3];
return await this.handleGetServicePlatformResourcesRequest(serviceName);
// Network endpoints
} else if (path === '/api/network/targets' && method === 'GET') {
return await this.handleGetNetworkTargetsRequest();
} else if (path === '/api/network/stats' && method === 'GET') {
return await this.handleGetNetworkStatsRequest();
} else {
return this.jsonResponse({ success: false, error: 'Not found' }, 404);
}
@@ -995,6 +1005,186 @@ export class OneboxHttpServer {
return response;
}
/**
* Handle WebSocket upgrade for network access log streaming
*/
private handleNetworkLogStreamUpgrade(req: Request, url: URL): Response {
const { socket, response } = Deno.upgradeWebSocket(req);
// Extract filter from query params
const filterDomain = url.searchParams.get('domain');
// Generate unique client ID
const clientId = crypto.randomUUID();
socket.onopen = () => {
logger.info(`Network log stream WebSocket connected (client: ${clientId})`);
// Register with CaddyLogReceiver
const filter = filterDomain ? { domain: filterDomain } : {};
this.oneboxRef.caddyLogReceiver.addClient(clientId, socket, filter);
// Send initial connection message
socket.send(JSON.stringify({
type: 'connected',
clientId,
filter,
}));
};
socket.onmessage = (event) => {
try {
const message = JSON.parse(event.data);
// Handle filter updates from client
if (message.type === 'set_filter') {
const newFilter = {
domain: message.domain || undefined,
sampleRate: message.sampleRate || undefined,
};
this.oneboxRef.caddyLogReceiver.updateClientFilter(clientId, newFilter);
socket.send(JSON.stringify({
type: 'filter_updated',
filter: newFilter,
}));
}
} catch (error) {
logger.debug(`Network log stream message parse error: ${getErrorMessage(error)}`);
}
};
socket.onclose = () => {
logger.info(`Network log stream WebSocket closed (client: ${clientId})`);
this.oneboxRef.caddyLogReceiver.removeClient(clientId);
};
socket.onerror = (error) => {
logger.error(`Network log stream WebSocket error: ${error}`);
this.oneboxRef.caddyLogReceiver.removeClient(clientId);
};
return response;
}
// ============ Network Endpoints ============
/**
* Get all traffic targets (services, registry, platform services)
*/
private async handleGetNetworkTargetsRequest(): Promise<Response> {
try {
const targets: Array<{
type: 'service' | 'registry' | 'platform';
name: string;
domain: string | null;
targetHost: string;
targetPort: number;
status: string;
}> = [];
// Add services
const services = this.oneboxRef.services.listServices();
for (const service of services) {
targets.push({
type: 'service',
name: service.name,
domain: service.domain || null,
targetHost: service.containerIP || 'unknown',
targetPort: service.port || 80,
status: service.status,
});
}
// Add registry if running
const registryStatus = this.oneboxRef.registry.getStatus();
if (registryStatus.running) {
targets.push({
type: 'registry',
name: 'onebox-registry',
domain: null, // Registry is internal
targetHost: 'localhost',
targetPort: registryStatus.port,
status: 'running',
});
}
// Add platform services
const platformServices = this.oneboxRef.platformServices.getAllPlatformServices();
for (const ps of platformServices) {
// Get provider info for display name
const provider = this.oneboxRef.platformServices.getProvider(ps.type);
targets.push({
type: 'platform',
name: provider?.displayName || ps.type,
domain: null, // Platform services are internal
targetHost: 'localhost',
targetPort: this.getPlatformServicePort(ps.type),
status: ps.status,
});
}
return this.jsonResponse({ success: true, data: targets });
} catch (error) {
logger.error(`Failed to get network targets: ${getErrorMessage(error)}`);
return this.jsonResponse({
success: false,
error: getErrorMessage(error) || 'Failed to get network targets',
}, 500);
}
}
/**
* Get default port for a platform service type
*/
private getPlatformServicePort(type: TPlatformServiceType): number {
const ports: Record<TPlatformServiceType, number> = {
mongodb: 27017,
minio: 9000,
redis: 6379,
postgresql: 5432,
rabbitmq: 5672,
};
return ports[type] || 0;
}
/**
* Get Caddy/network stats
*/
private async handleGetNetworkStatsRequest(): Promise<Response> {
try {
const proxyStatus = this.oneboxRef.reverseProxy.getStatus();
const logReceiverStats = this.oneboxRef.caddyLogReceiver.getStats();
return this.jsonResponse({
success: true,
data: {
proxy: {
running: proxyStatus.running,
httpPort: proxyStatus.httpPort,
httpsPort: proxyStatus.httpsPort,
routes: proxyStatus.routes,
certificates: proxyStatus.certificates,
},
logReceiver: {
running: logReceiverStats.running,
port: logReceiverStats.port,
clients: logReceiverStats.clients,
connections: logReceiverStats.connections,
sampleRate: logReceiverStats.sampleRate,
recentLogsCount: logReceiverStats.recentLogsCount,
},
},
});
} catch (error) {
logger.error(`Failed to get network stats: ${getErrorMessage(error)}`);
return this.jsonResponse({
success: false,
error: getErrorMessage(error) || 'Failed to get network stats',
}, 500);
}
}
/**
* Broadcast message to all connected WebSocket clients
*/