完善样式系统与调试链路底座
This commit is contained in:
@@ -6,7 +6,9 @@ const { WebSocketServer } = WebSocket
|
||||
|
||||
const HOST = '0.0.0.0'
|
||||
const PORT = 17865
|
||||
const WS_PATH = '/mock-gps'
|
||||
const GPS_WS_PATH = '/mock-gps'
|
||||
const HEART_RATE_WS_PATH = '/mock-hr'
|
||||
const DEBUG_LOG_WS_PATH = '/debug-log'
|
||||
const PROXY_PATH = '/proxy'
|
||||
const BRIDGE_STATUS_PATH = '/bridge-status'
|
||||
const BRIDGE_CONFIG_PATH = '/bridge-config'
|
||||
@@ -91,6 +93,14 @@ function isMockHeartRatePayload(payload) {
|
||||
&& Number.isFinite(payload.bpm)
|
||||
}
|
||||
|
||||
function isDebugLogPayload(payload) {
|
||||
return payload
|
||||
&& payload.type === 'debug-log'
|
||||
&& typeof payload.scope === 'string'
|
||||
&& typeof payload.level === 'string'
|
||||
&& typeof payload.message === 'string'
|
||||
}
|
||||
|
||||
async function handleProxyRequest(request, response) {
|
||||
const requestUrl = new URL(request.url || '/', `http://127.0.0.1:${PORT}`)
|
||||
const targetUrl = requestUrl.searchParams.get('url')
|
||||
@@ -497,9 +507,11 @@ const server = http.createServer((request, response) => {
|
||||
serveStatic(request.url || '/', response)
|
||||
})
|
||||
|
||||
const wss = new WebSocketServer({ noServer: true })
|
||||
const gpsWss = new WebSocketServer({ noServer: true })
|
||||
const heartRateWss = new WebSocketServer({ noServer: true })
|
||||
const debugLogWss = new WebSocketServer({ noServer: true })
|
||||
|
||||
wss.on('connection', (socket) => {
|
||||
gpsWss.on('connection', (socket) => {
|
||||
socket.on('message', (rawMessage) => {
|
||||
const text = String(rawMessage)
|
||||
let parsed
|
||||
@@ -509,51 +521,126 @@ wss.on('connection', (socket) => {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isMockGpsPayload(parsed) && !isMockHeartRatePayload(parsed)) {
|
||||
if (!isMockGpsPayload(parsed)) {
|
||||
return
|
||||
}
|
||||
|
||||
const serialized = isMockGpsPayload(parsed)
|
||||
? JSON.stringify({
|
||||
type: 'mock_gps',
|
||||
timestamp: Number.isFinite(parsed.timestamp) ? parsed.timestamp : Date.now(),
|
||||
lat: Number(parsed.lat),
|
||||
lon: Number(parsed.lon),
|
||||
accuracyMeters: Number.isFinite(parsed.accuracyMeters) ? Number(parsed.accuracyMeters) : 6,
|
||||
speedMps: Number.isFinite(parsed.speedMps) ? Number(parsed.speedMps) : 0,
|
||||
headingDeg: Number.isFinite(parsed.headingDeg) ? Number(parsed.headingDeg) : 0,
|
||||
})
|
||||
: JSON.stringify({
|
||||
type: 'mock_heart_rate',
|
||||
timestamp: Number.isFinite(parsed.timestamp) ? parsed.timestamp : Date.now(),
|
||||
bpm: Math.max(1, Math.round(Number(parsed.bpm))),
|
||||
})
|
||||
const outgoing = JSON.stringify({
|
||||
type: 'mock_gps',
|
||||
timestamp: Number.isFinite(parsed.timestamp) ? parsed.timestamp : Date.now(),
|
||||
lat: Number(parsed.lat),
|
||||
lon: Number(parsed.lon),
|
||||
accuracyMeters: Number.isFinite(parsed.accuracyMeters) ? Number(parsed.accuracyMeters) : 6,
|
||||
speedMps: Number.isFinite(parsed.speedMps) ? Number(parsed.speedMps) : 0,
|
||||
headingDeg: Number.isFinite(parsed.headingDeg) ? Number(parsed.headingDeg) : 0,
|
||||
})
|
||||
gatewayBridge.publish(JSON.parse(outgoing))
|
||||
|
||||
gatewayBridge.publish(JSON.parse(serialized))
|
||||
|
||||
wss.clients.forEach((client) => {
|
||||
gpsWss.clients.forEach((client) => {
|
||||
if (client.readyState === client.OPEN) {
|
||||
client.send(serialized)
|
||||
client.send(outgoing)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
heartRateWss.on('connection', (socket) => {
|
||||
socket.on('message', (rawMessage) => {
|
||||
const text = String(rawMessage)
|
||||
let parsed
|
||||
try {
|
||||
parsed = JSON.parse(text)
|
||||
} catch (_error) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isMockHeartRatePayload(parsed)) {
|
||||
return
|
||||
}
|
||||
|
||||
const outgoing = JSON.stringify({
|
||||
type: 'mock_heart_rate',
|
||||
timestamp: Number.isFinite(parsed.timestamp) ? parsed.timestamp : Date.now(),
|
||||
bpm: Math.max(1, Math.round(Number(parsed.bpm))),
|
||||
})
|
||||
gatewayBridge.publish(JSON.parse(outgoing))
|
||||
|
||||
heartRateWss.clients.forEach((client) => {
|
||||
if (client.readyState === client.OPEN) {
|
||||
client.send(outgoing)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
debugLogWss.on('connection', (socket) => {
|
||||
socket.on('message', (rawMessage) => {
|
||||
const text = String(rawMessage)
|
||||
let parsed
|
||||
try {
|
||||
parsed = JSON.parse(text)
|
||||
} catch (_error) {
|
||||
return
|
||||
}
|
||||
|
||||
if (!isDebugLogPayload(parsed)) {
|
||||
return
|
||||
}
|
||||
|
||||
const outgoing = JSON.stringify({
|
||||
type: 'debug-log',
|
||||
timestamp: Number.isFinite(parsed.timestamp) ? parsed.timestamp : Date.now(),
|
||||
scope: String(parsed.scope || 'app').slice(0, 64),
|
||||
level: parsed.level === 'warn' || parsed.level === 'error' ? parsed.level : 'info',
|
||||
message: String(parsed.message || '').slice(0, 400),
|
||||
...(parsed.payload && typeof parsed.payload === 'object'
|
||||
? { payload: parsed.payload }
|
||||
: {}),
|
||||
})
|
||||
|
||||
debugLogWss.clients.forEach((client) => {
|
||||
if (client.readyState === client.OPEN) {
|
||||
client.send(outgoing)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
server.on('upgrade', (request, socket, head) => {
|
||||
if (!request.url || !request.url.startsWith(WS_PATH)) {
|
||||
socket.destroy()
|
||||
const requestUrl = request.url || ''
|
||||
if (requestUrl.startsWith(GPS_WS_PATH)) {
|
||||
gpsWss.handleUpgrade(request, socket, head, (ws) => {
|
||||
gpsWss.emit('connection', ws, request)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
wss.handleUpgrade(request, socket, head, (ws) => {
|
||||
wss.emit('connection', ws, request)
|
||||
})
|
||||
if (requestUrl.startsWith(HEART_RATE_WS_PATH)) {
|
||||
heartRateWss.handleUpgrade(request, socket, head, (ws) => {
|
||||
heartRateWss.emit('connection', ws, request)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (requestUrl.startsWith(DEBUG_LOG_WS_PATH)) {
|
||||
debugLogWss.handleUpgrade(request, socket, head, (ws) => {
|
||||
debugLogWss.emit('connection', ws, request)
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if (!requestUrl) {
|
||||
socket.destroy()
|
||||
}
|
||||
socket.destroy()
|
||||
})
|
||||
|
||||
server.listen(PORT, HOST, () => {
|
||||
console.log(`Mock GPS simulator running:`)
|
||||
console.log(` UI: http://127.0.0.1:${PORT}/`)
|
||||
console.log(` WS: ws://127.0.0.1:${PORT}${WS_PATH}`)
|
||||
console.log(` GPS WS: ws://127.0.0.1:${PORT}${GPS_WS_PATH}`)
|
||||
console.log(` HR WS: ws://127.0.0.1:${PORT}${HEART_RATE_WS_PATH}`)
|
||||
console.log(` Logger WS: ws://127.0.0.1:${PORT}${DEBUG_LOG_WS_PATH}`)
|
||||
console.log(` Proxy: http://127.0.0.1:${PORT}${PROXY_PATH}?url=<remote-url>`)
|
||||
console.log(` Bridge status: http://127.0.0.1:${PORT}${BRIDGE_STATUS_PATH}`)
|
||||
console.log(` Bridge config: http://127.0.0.1:${PORT}${BRIDGE_CONFIG_PATH}`)
|
||||
|
||||
Reference in New Issue
Block a user