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:
ruv
2026-02-28 21:29:45 -05:00
parent cd5943df23
commit d956c30f9e
16 changed files with 1285 additions and 1913 deletions

View File

@@ -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