feat(opsserver,web): add real-time platform service log streaming to the dashboard
This commit is contained in:
@@ -961,3 +961,73 @@ const startAutoRefresh = () => {
|
||||
uiStatePart.select((s) => s).subscribe(() => startAutoRefresh());
|
||||
loginStatePart.select((s) => s).subscribe(() => startAutoRefresh());
|
||||
startAutoRefresh();
|
||||
|
||||
// ============================================================================
|
||||
// TypedSocket — real-time server push (logs, events)
|
||||
// ============================================================================
|
||||
|
||||
let socketClient: InstanceType<typeof plugins.typedsocket.TypedSocket> | null = null;
|
||||
const socketRouter = new plugins.domtools.plugins.typedrequest.TypedRouter();
|
||||
|
||||
// Handle server-pushed platform service log entries
|
||||
socketRouter.addTypedHandler(
|
||||
new plugins.domtools.plugins.typedrequest.TypedHandler<interfaces.requests.IReq_PushPlatformServiceLog>(
|
||||
'pushPlatformServiceLog',
|
||||
async (dataArg) => {
|
||||
const state = servicesStatePart.getState();
|
||||
const entry: interfaces.data.ILogEntry = {
|
||||
id: state.currentPlatformServiceLogs.length,
|
||||
serviceId: 0,
|
||||
timestamp: new Date(dataArg.entry.timestamp).getTime(),
|
||||
message: dataArg.entry.message,
|
||||
level: dataArg.entry.level as 'info' | 'warn' | 'error' | 'debug',
|
||||
source: 'stdout',
|
||||
};
|
||||
const updated = [...state.currentPlatformServiceLogs, entry];
|
||||
// Cap at 2000 entries
|
||||
if (updated.length > 2000) {
|
||||
updated.splice(0, updated.length - 2000);
|
||||
}
|
||||
servicesStatePart.setState({
|
||||
...state,
|
||||
currentPlatformServiceLogs: updated,
|
||||
});
|
||||
return {};
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
async function connectSocket() {
|
||||
if (socketClient) return;
|
||||
try {
|
||||
socketClient = await plugins.typedsocket.TypedSocket.createClient(
|
||||
socketRouter,
|
||||
plugins.typedsocket.TypedSocket.useWindowLocationOriginUrl(),
|
||||
);
|
||||
await socketClient.setTag('role', 'ops_dashboard');
|
||||
console.log('TypedSocket dashboard connection established');
|
||||
} catch (err) {
|
||||
console.error('TypedSocket connection failed:', err);
|
||||
socketClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
async function disconnectSocket() {
|
||||
if (socketClient) {
|
||||
try {
|
||||
await socketClient.disconnect();
|
||||
} catch {
|
||||
// ignore disconnect errors
|
||||
}
|
||||
socketClient = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Connect socket when logged in, disconnect when logged out
|
||||
loginStatePart.select((s) => s).subscribe((loginState) => {
|
||||
if (loginState.isLoggedIn) {
|
||||
connectSocket();
|
||||
} else {
|
||||
disconnectSocket();
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user