Create server.ts
Browse files
server.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import express from 'express';
|
| 2 |
+
import { createServer as createViteServer } from 'vite';
|
| 3 |
+
import { createProxyMiddleware } from 'http-proxy-middleware';
|
| 4 |
+
import path from 'path';
|
| 5 |
+
import crypto from 'crypto';
|
| 6 |
+
import { createRequire } from 'module';
|
| 7 |
+
|
| 8 |
+
const require = createRequire(import.meta.url);
|
| 9 |
+
const NodeMediaServer = require('node-media-server');
|
| 10 |
+
|
| 11 |
+
async function startServer() {
|
| 12 |
+
const app = express();
|
| 13 |
+
const PORT = 3000;
|
| 14 |
+
|
| 15 |
+
// Start Node Media Server for RTMP Ingest (1935) and HTTP FLV (8123)
|
| 16 |
+
const nmsConfig = {
|
| 17 |
+
rtmp: {
|
| 18 |
+
port: 1935,
|
| 19 |
+
chunk_size: 60000,
|
| 20 |
+
gop_cache: true,
|
| 21 |
+
ping: 30,
|
| 22 |
+
ping_timeout: 60
|
| 23 |
+
},
|
| 24 |
+
http: {
|
| 25 |
+
port: 8123,
|
| 26 |
+
allow_origin: '*',
|
| 27 |
+
}
|
| 28 |
+
};
|
| 29 |
+
|
| 30 |
+
const nms = new NodeMediaServer(nmsConfig);
|
| 31 |
+
nms.run();
|
| 32 |
+
|
| 33 |
+
// Proxy HTTP FLV requests from port 3000 to port 8123 where NMS is listening
|
| 34 |
+
// This allows the frontend web player to access the stream using HTTP-FLV over port 3000
|
| 35 |
+
app.use('/live', createProxyMiddleware({
|
| 36 |
+
target: 'http://127.0.0.1:8123',
|
| 37 |
+
changeOrigin: true,
|
| 38 |
+
ws: true
|
| 39 |
+
}));
|
| 40 |
+
app.use('/api/streams', createProxyMiddleware({
|
| 41 |
+
target: 'http://127.0.0.1:8123',
|
| 42 |
+
changeOrigin: true
|
| 43 |
+
}));
|
| 44 |
+
|
| 45 |
+
// API Route to get connection info
|
| 46 |
+
app.get('/api/config', (req, res) => {
|
| 47 |
+
const appUrl = process.env.APP_URL || 'localhost';
|
| 48 |
+
let rtmpUrl = '';
|
| 49 |
+
|
| 50 |
+
// Determine the external URL. Note: AI Studio only exposes Port 3000 (HTTP).
|
| 51 |
+
// Testing RTMP from OBS externally requires running this code locally or using a TCP tunnel.
|
| 52 |
+
if (appUrl.startsWith('https://')) {
|
| 53 |
+
const hostname = new URL(appUrl).hostname;
|
| 54 |
+
rtmpUrl = `rtmp://${hostname}/live`;
|
| 55 |
+
} else {
|
| 56 |
+
rtmpUrl = `rtmp://${appUrl.split(':')[0]}/live`;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
res.json({ rtmpUrl });
|
| 60 |
+
});
|
| 61 |
+
|
| 62 |
+
// Vite middleware for development
|
| 63 |
+
if (process.env.NODE_ENV !== 'production') {
|
| 64 |
+
const vite = await createViteServer({
|
| 65 |
+
server: { middlewareMode: true },
|
| 66 |
+
appType: 'spa',
|
| 67 |
+
});
|
| 68 |
+
app.use(vite.middlewares);
|
| 69 |
+
} else {
|
| 70 |
+
// production mode
|
| 71 |
+
const distPath = path.join(process.cwd(), 'dist');
|
| 72 |
+
app.use(express.static(distPath));
|
| 73 |
+
app.get('*', (req, res) => {
|
| 74 |
+
res.sendFile(path.join(distPath, 'index.html'));
|
| 75 |
+
});
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
const server = app.listen(PORT, '0.0.0.0', () => {
|
| 79 |
+
console.log(`Express server running on http://localhost:${PORT}`);
|
| 80 |
+
});
|
| 81 |
+
|
| 82 |
+
// Graceful shutdown to release ports
|
| 83 |
+
process.on('SIGTERM', () => {
|
| 84 |
+
console.log('SIGTERM received, shutting down...');
|
| 85 |
+
nms.stop();
|
| 86 |
+
server.close();
|
| 87 |
+
process.exit(0);
|
| 88 |
+
});
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
startServer();
|