diff --git a/server/api/bridge/data.post.ts b/server/api/bridge/data.post.ts index 820a875..8e32c49 100644 --- a/server/api/bridge/data.post.ts +++ b/server/api/bridge/data.post.ts @@ -1,12 +1,56 @@ -import { defineEventHandler, readBody } from 'h3' +import { defineEventHandler, readBody, getHeader } from 'h3' +import { resolveUserFromToken } from '../../utils/auth' +import { flightlabTelemetryStore } from '../../utils/flightlabTelemetry' +/** + * Receives MSFS SimConnect telemetry data from an external bridge application. + * + * The bridge should POST telemetry data with an Authorization header so we + * can route the data to the correct FlightLab WebSocket session. + * + * ────────────────────────────────────────── + * EXAMPLE REQUEST (from SimBridge app): + * ────────────────────────────────────────── + * + * POST /api/bridge/data + * Authorization: Bearer + * Content-Type: application/json + * + * { + * "AIRSPEED_INDICATED": 145.2, + * "GROUND_VELOCITY": 142.8, + * "VERTICAL_SPEED": 0, + * "PLANE_ALTITUDE": 364, + * "PLANE_PITCH_DEGREES": 0.5, + * "TURB_ENG_N1_1": 87.3, + * "TURB_ENG_N1_2": 86.9, + * "SIM_ON_GROUND": true, + * "GEAR_HANDLE_POSITION": true, + * "FLAPS_HANDLE_INDEX": 2, + * "BRAKE_PARKING_POSITION": false, + * "AUTOPILOT_MASTER": false + * } + * + * ────────────────────────────────────────── + * RESPONSE: 204 No Content (success) + * 401 Unauthorized (missing/invalid token) + * ────────────────────────────────────────── + */ export default defineEventHandler(async (event) => { - // Body einlesen - const body = await readBody(event) + // Resolve user from Bearer token (optional — also works with ?userId query param) + const user = await resolveUserFromToken(event) + const userId = user?._id?.toString() + ?? new URL(event.node.req.url ?? '', 'http://localhost').searchParams.get('userId') - // Alles in der Server-Konsole ausgeben - console.log('MSFS Telemetry:', body) + if (!userId) { + event.node.res.statusCode = 401 + return { error: 'Authorization required — send Bearer token or ?userId query param' } + } - // Leere 204-Antwort zurückgeben - event.node.res.statusCode = 204 + const body = await readBody(event) + + // Store telemetry and broadcast to WebSocket subscribers + flightlabTelemetryStore.update(userId, body) + + event.node.res.statusCode = 204 }) diff --git a/server/utils/flightlabTelemetry.ts b/server/utils/flightlabTelemetry.ts new file mode 100644 index 0000000..a56775b --- /dev/null +++ b/server/utils/flightlabTelemetry.ts @@ -0,0 +1,35 @@ +/** + * In-memory telemetry store that bridges the HTTP POST endpoint + * with FlightLab WebSocket sessions. + * + * Flow: SimBridge → POST /api/bridge/data → telemetryStore → WS → Client + */ + +type TelemetryListener = (userId: string, data: any) => void + +class FlightLabTelemetryStore { + /** Latest telemetry per userId */ + private data = new Map() + /** WebSocket listeners that get notified on new data */ + private listeners = new Set() + + update(userId: string, telemetry: any) { + this.data.set(userId, { ...telemetry, timestamp: Date.now() }) + // Notify all listeners (WebSocket handler subscribes here) + for (const listener of this.listeners) { + try { listener(userId, this.data.get(userId)) } catch {} + } + } + + get(userId: string) { + return this.data.get(userId) ?? null + } + + subscribe(listener: TelemetryListener) { + this.listeners.add(listener) + return () => { this.listeners.delete(listener) } + } +} + +// Singleton — shared across all server handlers +export const flightlabTelemetryStore = new FlightLabTelemetryStore()