8a5409987c
THE ANSWER to "why does an already-downloaded video still buffer?" — it was never the download, and it was not the server. Probing the real uploads on the box: d0e49e58… 1920x1080 19.4 Mbps 75 MB / 31 s ad929d0b… 1920x1080 19.0 Mbps 27 MB / 11 s 9f4e0865… 720x1584 3.6 Mbps 14 MB / 31 s To play a 19 Mbps file the client has to SUSTAIN a 19 Mbps download for the whole clip. No mobile link does, so the <video> buffer drains every few seconds: buffers, plays, buffers, plays. Server-side disk read was instant and load was 1.7 on 20 cores throughout — the bottleneck is the media itself, not the delivery path. Second, independent defect: phone MP4s store `moov` AFTER `mdat` (verified on two uploads), so the player must fetch the file's tail before it can start at all. Fix — keep the original bytes untouched (that is what the download button serves, full quality) and build <id>.web.mp4 beside it: longest side capped at 1280, ~2.5 Mbps ceiling, +faststart. Measured on the 19 Mbps file: 27.3 MB @ 19.0 Mbps -> 2.55 MB @ 1.78 Mbps (10.7x less bandwidth) transcode took 2.4 s for an 11.5 s clip - server/media.js (new): probe, decide, 2-at-a-time background queue. Already light + correctly sized + faststart => no rendition at all. Light but wrong atom order => remux -c copy (seconds, no re-encode). Otherwise re-encode. A rendition that lands bigger than the original is discarded. MP4 box-walker for the faststart test is unit-checked against known fast/slow files, both directions. - /stream/<id> serves the rendition, falling back to the original while it is still transcoding, so a video is never unplayable. /files/<id> is unchanged and still serves the pristine original for download. - Renditions are queued at upload, and backfilled 15 s after boot for the videos that predate this. Range serving is now one shared helper for both routes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
66 lines
2.8 KiB
JavaScript
66 lines
2.8 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]}`;
|
|
if (routes[key]) return routes[key](req, res);
|
|
if (req.method === 'GET') return handleGet(req, res); // downloads + static
|
|
json(res, 404, { error: 'not found' });
|
|
});
|
|
|
|
// ---------- 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 };
|