feat: Rust sensing server with full DensePose-compatible API
Replace Python FastAPI + WebSocket servers with a single 2.1MB Rust binary (wifi-densepose-sensing-server) that serves all UI endpoints: - REST: /health/*, /api/v1/info, /api/v1/pose/current, /api/v1/pose/stats, /api/v1/pose/zones/summary, /api/v1/stream/status - WebSocket: /api/v1/stream/pose (pose_data with 17 COCO keypoints), /ws/sensing (raw sensing_update stream on port 8765) - Static: /ui/* with no-cache headers WiFi-derived pose estimation: derive_pose_from_sensing() generates 17 COCO keypoints from CSI/WiFi signal data with motion-driven animation. Data sources: ESP32 CSI via UDP :5005, Windows WiFi via netsh, simulation fallback. Auto-detection probes each in order. UI changes: - Point all endpoints to Rust server on :8080 (was Python :8000) - Fix WebSocket sensing URL to include /ws/sensing path - Remove sensingOnlyMode gating — all tabs init normally - Remove api.service.js sensing-only short-circuit - Fix clearPingInterval bug in websocket.service.js Also removes obsolete k8s/ template manifests. Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
29
ui/app.js
29
ui/app.js
@@ -65,18 +65,15 @@ class WiFiDensePoseApp {
|
||||
// Show notification to user
|
||||
this.showBackendStatus('Mock server active - testing mode', 'warning');
|
||||
} else {
|
||||
console.log('🔌 Initializing with real backend');
|
||||
console.log('🔌 Connecting to backend...');
|
||||
|
||||
// Verify backend is actually working
|
||||
try {
|
||||
const health = await healthService.checkLiveness();
|
||||
console.log('✅ Backend is available and responding:', health);
|
||||
this.showBackendStatus('Connected to real backend', 'success');
|
||||
console.log('✅ Backend responding:', health);
|
||||
this.showBackendStatus('Connected to Rust sensing server', 'success');
|
||||
} catch (error) {
|
||||
// DensePose API backend not running — sensing-only mode
|
||||
backendDetector.sensingOnlyMode = true;
|
||||
console.log('ℹ️ DensePose API not running — sensing-only mode via WebSocket on :8765');
|
||||
this.showBackendStatus('Sensing mode — live WiFi data via WebSocket', 'success');
|
||||
console.warn('⚠️ Backend not available:', error.message);
|
||||
this.showBackendStatus('Backend unavailable — start sensing-server', 'warning');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,36 +96,32 @@ class WiFiDensePoseApp {
|
||||
this.components.tabManager.onTabChange((newTab, oldTab) => {
|
||||
this.handleTabChange(newTab, oldTab);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Initialize individual tab components
|
||||
initializeTabComponents() {
|
||||
// Skip DensePose-dependent tabs in sensing-only mode
|
||||
const sensingOnly = backendDetector.sensingOnlyMode;
|
||||
|
||||
// Dashboard tab
|
||||
const dashboardContainer = document.getElementById('dashboard');
|
||||
if (dashboardContainer) {
|
||||
this.components.dashboard = new DashboardTab(dashboardContainer);
|
||||
if (!sensingOnly) {
|
||||
this.components.dashboard.init().catch(error => {
|
||||
console.error('Failed to initialize dashboard:', error);
|
||||
});
|
||||
}
|
||||
this.components.dashboard.init().catch(error => {
|
||||
console.error('Failed to initialize dashboard:', error);
|
||||
});
|
||||
}
|
||||
|
||||
// Hardware tab
|
||||
const hardwareContainer = document.getElementById('hardware');
|
||||
if (hardwareContainer) {
|
||||
this.components.hardware = new HardwareTab(hardwareContainer);
|
||||
if (!sensingOnly) this.components.hardware.init();
|
||||
this.components.hardware.init();
|
||||
}
|
||||
|
||||
// Live demo tab
|
||||
const demoContainer = document.getElementById('demo');
|
||||
if (demoContainer) {
|
||||
this.components.demo = new LiveDemoTab(demoContainer);
|
||||
if (!sensingOnly) this.components.demo.init();
|
||||
this.components.demo.init();
|
||||
}
|
||||
|
||||
// Sensing tab
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// API Configuration for WiFi-DensePose UI
|
||||
|
||||
export const API_CONFIG = {
|
||||
BASE_URL: 'http://localhost:8000', // FastAPI backend port
|
||||
BASE_URL: 'http://localhost:8080', // Rust sensing server port
|
||||
API_VERSION: '/api/v1',
|
||||
WS_PREFIX: 'ws://',
|
||||
WSS_PREFIX: 'wss://',
|
||||
@@ -111,8 +111,8 @@ export function buildWsUrl(endpoint, params = {}) {
|
||||
? API_CONFIG.WSS_PREFIX
|
||||
: API_CONFIG.WS_PREFIX;
|
||||
|
||||
// Use localhost:8000 for WebSocket connections to match FastAPI backend
|
||||
const host = 'localhost:8000';
|
||||
// Match Rust sensing server port
|
||||
const host = 'localhost:8080';
|
||||
let url = `${protocol}${host}${endpoint}`;
|
||||
|
||||
// Add query parameters
|
||||
|
||||
@@ -67,11 +67,6 @@ export class ApiService {
|
||||
// Generic request method
|
||||
async request(url, options = {}) {
|
||||
try {
|
||||
// In sensing-only mode, skip all DensePose API calls
|
||||
if (backendDetector.sensingOnlyMode) {
|
||||
throw new Error('DensePose API unavailable (sensing-only mode)');
|
||||
}
|
||||
|
||||
// Process request through interceptors
|
||||
const processed = await this.processRequest(url, options);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* always shows something.
|
||||
*/
|
||||
|
||||
const SENSING_WS_URL = 'ws://localhost:8765';
|
||||
const SENSING_WS_URL = 'ws://localhost:8765/ws/sensing';
|
||||
const RECONNECT_DELAYS = [1000, 2000, 4000, 8000, 16000];
|
||||
const MAX_RECONNECT_ATTEMPTS = 10;
|
||||
const SIMULATION_INTERVAL = 500; // ms
|
||||
|
||||
@@ -309,8 +309,11 @@ export class WebSocketService {
|
||||
clearTimeout(connection.reconnectTimer);
|
||||
}
|
||||
|
||||
// Clear ping interval
|
||||
this.clearPingInterval(connection.url);
|
||||
// Clear heartbeat timer
|
||||
if (connection.heartbeatTimer) {
|
||||
clearInterval(connection.heartbeatTimer);
|
||||
connection.heartbeatTimer = null;
|
||||
}
|
||||
|
||||
// Close WebSocket
|
||||
if (connection.ws.readyState === WebSocket.OPEN) {
|
||||
|
||||
Reference in New Issue
Block a user