UNPKG

ble-mcp-test

Version:

Complete BLE testing stack: WebSocket bridge server, MCP observability layer, and Web Bluetooth API mock. Test real BLE devices in Playwright/E2E tests without browser support.

96 lines (95 loc) 3.5 kB
import { LogBuffer } from './log-buffer.js'; /** * Shared state between bridge and observability services * * This provides a clean interface for: * - Bridge to write packet logs and connection state * - Observability to read logs and state without coupling */ export class SharedState { logBuffer; connectionState = { connected: false, deviceName: null, recovering: false, connectedAt: null }; originalConsole = { log: console.log, warn: console.warn, error: console.error }; constructor(interceptConsole = true) { this.logBuffer = new LogBuffer(); if (interceptConsole) { this.setupConsoleInterceptor(); } } setupConsoleInterceptor() { // Intercept console methods to capture bridge logs console.log = (...args) => { this.originalConsole.log.apply(console, args); const message = args.join(' '); if (message.includes('[Bridge]')) { this.logBuffer.pushSystemLog('INFO', message); } }; console.warn = (...args) => { this.originalConsole.warn.apply(console, args); const message = args.join(' '); this.logBuffer.pushSystemLog('WARN', message); }; console.error = (...args) => { this.originalConsole.error.apply(console, args); const message = args.join(' '); this.logBuffer.pushSystemLog('ERROR', message); }; } // === Write Interface (for Bridge) === logPacket(direction, data) { this.logBuffer.logPacket(direction, data); } setConnectionState(state) { const before = { ...this.connectionState }; this.connectionState = { ...this.connectionState, ...state, connectedAt: state.connected ? new Date().toISOString() : state.connected === false ? null : this.connectionState.connectedAt }; // Force this log to appear in the main console (not intercepted) const originalLog = this.originalConsole.log; originalLog(`[SharedState] 📊 State updated: ${JSON.stringify(before)}${JSON.stringify(this.connectionState)}`); // Also log to the buffer directly this.logBuffer.pushSystemLog('INFO', `[SharedState] 📊 State updated: ${JSON.stringify(before)}${JSON.stringify(this.connectionState)}`); // File-based logging fallback try { // Dynamic import for Node.js fs module import('fs').then(fs => { const timestamp = new Date().toISOString(); const logEntry = `${timestamp} [SharedState] 📊 State updated: ${JSON.stringify(before)}${JSON.stringify(this.connectionState)}\n`; fs.appendFileSync('/tmp/ble-state.log', logEntry); }); } catch { // Ignore file logging errors } } // === Read Interface (for Observability) === getLogBuffer() { return this.logBuffer; } getConnectionState() { return { ...this.connectionState }; } getConnectionStats() { return this.logBuffer.getConnectionStats(); } // Restore original console methods restoreConsole() { console.log = this.originalConsole.log; console.warn = this.originalConsole.warn; console.error = this.originalConsole.error; } }