3250530596
The full sync→async conversion is complete and green on the SQLite backend. Every DB call across the app now awaits the async adapter, so the identical code runs on Postgres at cutover. Converted (this commit finishes Phase 3): - session.js: currentUser/apiKeyFromReq async → 63 route awaits + WS + static. - routes.js: all ~250 R.* awaited; DTO helpers (namesFor, avatarsFor, buildMsgDTO, buildPollDTO, reactionsForMessage, postSystemMessage, pushGroupUpdate, issueRefreshToken, provisionFromBizgaze) made async; every `.map(x=>buildDTO(x))` restructured to `await Promise.all(...map(async...))` preserving order; `.filter` predicates that hit the DB moved to an `asyncFilter` helper; chained `R.x.y(...).length/.map/.filter` wrapped as `(await R.x.y(...)).method`; stream upload handlers (recording/transcript/attachment) made async. - calls.js / signaling.js: all call/meeting fns async; leaveMeeting AWAITS persistCallHistory + finalizeTranscript BEFORE endCallByRoom (ordering matters — fire-and-forget would race the map teardown); WS handle()/cleanup() async with .catch guards. - static.js: authAttachment(Raw) async (the .some carrier check became a loop), handleGet async; server.js dispatch catches handler rejections → 500 not a hang. - media.js backfill, push.js, reminders.js, webhooks.js await their repo calls. Validation on DB_BACKEND=sqlite: db-smoke 22/22; legacy e2e 80 checks pass with zero FAILs (throws only at a PRE-EXISTING WS lobby-drift assertion, unrelated). Every server file `node --check` clean. Still on the branch — master untouched. Next: Phase 5 (pg backend + ~7 dialect queries + data migration + Docker Postgres + cutover), then merge. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
70 lines
3.1 KiB
JavaScript
70 lines
3.1 KiB
JavaScript
// BizGaze Connect — backend entry point.
|
|
// Thin wiring layer: HTTP request dispatch + WebSocket attach + listeners.
|
|
// All logic lives in focused modules:
|
|
// repos.js data-access (all SQL)
|
|
// bizgaze.js BizGaze identity provider
|
|
// lib.js HTTP helpers (json/readBody/parseCookies/now)
|
|
// session.js currentUser / audit
|
|
// presence.js shared in-memory live state (agents/sessions/shares)
|
|
// routes.js HTTP JSON API (/api/*, /sso)
|
|
// static.js static files + authenticated downloads (GET fallback)
|
|
// signaling.js WebSocket signaling (consent + SDP/ICE relay)
|
|
const http = require('http');
|
|
const https = require('https');
|
|
const fs = require('fs');
|
|
const path = require('path');
|
|
const { WebSocketServer } = require('ws');
|
|
const { PORT, HTTPS_PORT } = require('./config');
|
|
const { json } = require('./lib');
|
|
const routes = require('./routes');
|
|
const { handleGet } = require('./static');
|
|
const { onConnection } = require('./signaling');
|
|
|
|
// ---------- HTTP request dispatch ----------
|
|
const server = http.createServer((req, res) => {
|
|
const key = `${req.method} ${req.url.split('?')[0]}`;
|
|
// Route/static handlers are async now (DB adapter). Catch any rejection so a handler error becomes a
|
|
// 500 instead of a hung request + unhandled promise rejection.
|
|
let p;
|
|
if (routes[key]) p = routes[key](req, res);
|
|
else if (req.method === 'GET') p = handleGet(req, res); // downloads + static
|
|
else return json(res, 404, { error: 'not found' });
|
|
if (p && typeof p.catch === 'function') p.catch((e) => { try { console.error('handler error', key, e && e.message); json(res, 500, { error: 'server error' }); } catch (_) {} });
|
|
});
|
|
|
|
// ---------- WebSocket signaling ----------
|
|
const wss = new WebSocketServer({ server, path: '/ws' });
|
|
wss.on('connection', onConnection);
|
|
|
|
server.listen(PORT, () => {
|
|
console.log(`HTTP on http://localhost:${PORT}`);
|
|
try { require('./media').backfill(); } catch (e) {} // streaming renditions for older video uploads
|
|
});
|
|
|
|
// HTTPS — required so other devices can share their screen (browsers block
|
|
// screen capture on non-secure origins). Uses cert.pem/key.pem if present.
|
|
let httpsServer = null;
|
|
try {
|
|
const certPath = path.join(__dirname, 'cert.pem');
|
|
const keyPath = path.join(__dirname, 'key.pem');
|
|
if (fs.existsSync(certPath) && fs.existsSync(keyPath)) {
|
|
httpsServer = https.createServer(
|
|
{ cert: fs.readFileSync(certPath), key: fs.readFileSync(keyPath) },
|
|
(req, res) => server.emit('request', req, res)
|
|
);
|
|
const wssSecure = new WebSocketServer({ server: httpsServer, path: '/ws' });
|
|
wssSecure.on('connection', onConnection);
|
|
httpsServer.listen(HTTPS_PORT, () => {
|
|
console.log(`HTTPS on https://localhost:${HTTPS_PORT} (use this address from other devices)`);
|
|
console.log(` End user shares screen: https://<this-pc-ip>:${HTTPS_PORT}/share`);
|
|
console.log(` Technician connects: https://<this-pc-ip>:${HTTPS_PORT}/connect`);
|
|
});
|
|
} else {
|
|
console.log('(No cert.pem/key.pem found — HTTPS disabled. Other devices can view but not share their screen.)');
|
|
}
|
|
} catch (e) {
|
|
console.log('HTTPS failed to start:', e.message);
|
|
}
|
|
|
|
module.exports = { server };
|