| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 |
- const http = require('http')
- const fs = require('fs')
- const path = require('path')
- const { WebSocketServer } = require('ws')
- const HOST = '0.0.0.0'
- const PORT = 17865
- const WS_PATH = '/mock-gps'
- const PROXY_PATH = '/proxy'
- const PUBLIC_DIR = path.join(__dirname, 'public')
- function getContentType(filePath) {
- const ext = path.extname(filePath).toLowerCase()
- if (ext === '.html') {
- return 'text/html; charset=utf-8'
- }
- if (ext === '.css') {
- return 'text/css; charset=utf-8'
- }
- if (ext === '.js') {
- return 'application/javascript; charset=utf-8'
- }
- if (ext === '.json') {
- return 'application/json; charset=utf-8'
- }
- if (ext === '.svg') {
- return 'image/svg+xml'
- }
- return 'text/plain; charset=utf-8'
- }
- function serveStatic(requestPath, response) {
- const safePath = requestPath === '/' ? '/index.html' : requestPath
- const resolvedPath = path.normalize(path.join(PUBLIC_DIR, safePath))
- if (!resolvedPath.startsWith(PUBLIC_DIR)) {
- response.writeHead(403)
- response.end('Forbidden')
- return
- }
- fs.readFile(resolvedPath, (error, content) => {
- if (error) {
- response.writeHead(404)
- response.end('Not Found')
- return
- }
- response.writeHead(200, {
- 'Content-Type': getContentType(resolvedPath),
- 'Cache-Control': 'no-store',
- })
- response.end(content)
- })
- }
- function isMockGpsPayload(payload) {
- return payload
- && payload.type === 'mock_gps'
- && Number.isFinite(payload.lat)
- && Number.isFinite(payload.lon)
- }
- async function handleProxyRequest(request, response) {
- const requestUrl = new URL(request.url || '/', `http://127.0.0.1:${PORT}`)
- const targetUrl = requestUrl.searchParams.get('url')
- if (!targetUrl) {
- response.writeHead(400, {
- 'Content-Type': 'text/plain; charset=utf-8',
- 'Access-Control-Allow-Origin': '*',
- })
- response.end('Missing url')
- return
- }
- try {
- const upstream = await fetch(targetUrl)
- const body = Buffer.from(await upstream.arrayBuffer())
- response.writeHead(upstream.status, {
- 'Content-Type': upstream.headers.get('content-type') || 'application/octet-stream',
- 'Cache-Control': 'no-store',
- 'Access-Control-Allow-Origin': '*',
- })
- response.end(body)
- } catch (error) {
- response.writeHead(502, {
- 'Content-Type': 'text/plain; charset=utf-8',
- 'Access-Control-Allow-Origin': '*',
- })
- response.end(error && error.message ? error.message : 'Proxy request failed')
- }
- }
- const server = http.createServer((request, response) => {
- if ((request.url || '').startsWith(PROXY_PATH)) {
- handleProxyRequest(request, response)
- return
- }
- serveStatic(request.url || '/', response)
- })
- const wss = new WebSocketServer({ noServer: true })
- wss.on('connection', (socket) => {
- socket.on('message', (rawMessage) => {
- const text = String(rawMessage)
- let parsed
- try {
- parsed = JSON.parse(text)
- } catch (_error) {
- return
- }
- if (!isMockGpsPayload(parsed)) {
- return
- }
- const serialized = 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,
- })
- wss.clients.forEach((client) => {
- if (client.readyState === client.OPEN) {
- client.send(serialized)
- }
- })
- })
- })
- server.on('upgrade', (request, socket, head) => {
- if (!request.url || !request.url.startsWith(WS_PATH)) {
- socket.destroy()
- return
- }
- wss.handleUpgrade(request, socket, head, (ws) => {
- wss.emit('connection', ws, request)
- })
- })
- 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(` Proxy: http://127.0.0.1:${PORT}${PROXY_PATH}?url=<remote-url>`)
- })
|