193 lines
5.3 KiB
JavaScript
193 lines
5.3 KiB
JavaScript
#!/usr/bin/env node
|
||
|
||
const fs = require("fs");
|
||
const ws = require("ws");
|
||
const https = require("https");
|
||
// const mediasoup = require("mediasoup");
|
||
const config = require("./Config");
|
||
const Logger = require("./Logger");
|
||
const Signal = require("./Signal");
|
||
const { fail } = require("assert");
|
||
|
||
// 线程名称
|
||
process.title = config.name;
|
||
|
||
// 无效信令终端列表
|
||
const clients = [];
|
||
// Mediasoup Worker列表
|
||
const mediasoupWorkers = [];
|
||
|
||
// HTTPS server
|
||
let httpsServer;
|
||
// WebSocket server
|
||
let webSocketServer;
|
||
// 日志
|
||
const logger = new Logger();
|
||
// 信令
|
||
const signal = new Signal(mediasoupWorkers);
|
||
|
||
/**
|
||
* 启动Mediasoup Worker
|
||
*/
|
||
async function buildMediasoupWorkers() {
|
||
const { workerSize } = config.mediasoup;
|
||
logger.info("启动Mediasoup Worker", workerSize);
|
||
for (let i = 0; i < workerSize; i++) {
|
||
// 新建Worker
|
||
const worker = await mediasoup.createWorker({
|
||
logLevel: config.mediasoup.workerSettings.logLevel,
|
||
logTags: config.mediasoup.workerSettings.logTags,
|
||
rtcMinPort: Number(config.mediasoup.workerSettings.rtcMinPort),
|
||
rtcMaxPort: Number(config.mediasoup.workerSettings.rtcMaxPort),
|
||
});
|
||
// 监听Worker事件
|
||
worker.on("died", () => {
|
||
logger.warn("Mediasoup Worker停止服务", worker.pid);
|
||
setTimeout(() => process.exit(1), 2000);
|
||
});
|
||
// 加入Worker队列
|
||
mediasoupWorkers.push(worker);
|
||
// 配置WebRTC服务
|
||
if (process.env.MEDIASOUP_USE_WEBRTC_SERVER !== "false") {
|
||
// 配置Worker端口
|
||
const portIncrement = mediasoupWorkers.length - 1;
|
||
const webRtcServerOptions = JSON.parse(
|
||
JSON.stringify(config.mediasoup.webRtcServerOptions)
|
||
);
|
||
for (const listenInfo of webRtcServerOptions.listenInfos) {
|
||
listenInfo.port += portIncrement;
|
||
}
|
||
// 配置WebRTC服务
|
||
const webRtcServer = await worker.createWebRtcServer(webRtcServerOptions);
|
||
worker.appData.webRtcServer = webRtcServer;
|
||
}
|
||
// 定时记录使用日志
|
||
setInterval(async () => {
|
||
const usage = await worker.getResourceUsage();
|
||
logger.info("Mediasoup Worker使用情况", worker.pid, usage);
|
||
}, 120 * 1000);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 启动信令服务
|
||
*/
|
||
async function buildSignalServer() {
|
||
const tls = {
|
||
cert: fs.readFileSync(config.https.tls.cert),
|
||
key: fs.readFileSync(config.https.tls.key),
|
||
};
|
||
// 配置HTTPS
|
||
httpsServer = https.createServer(tls, (request, response) => {
|
||
response.writeHead(200);
|
||
response.end(fs.readFileSync(config.welcome));
|
||
});
|
||
// 配置WebSocket
|
||
webSocketServer = new ws.Server({ server: httpsServer });
|
||
webSocketServer.on("connection", (session) => {
|
||
logger.info("打开信令通道", session._socket.remoteAddress);
|
||
session.datetime = Date.now();
|
||
session.authorize = false;
|
||
clients.push(session);
|
||
session.on("close", (code) => {
|
||
logger.info("关闭信令通道", session._socket.remoteAddress, code);
|
||
});
|
||
session.on("error", (error) => {
|
||
logger.error("信令通道异常", session._socket.remoteAddress, error);
|
||
});
|
||
session.on("message", (message) => {
|
||
logger.debug("处理信令消息", message.toString());
|
||
try {
|
||
signal.on(JSON.parse(message), session);
|
||
} catch (error) {
|
||
logger.error("处理信令消息异常", message.toString(), error);
|
||
}
|
||
});
|
||
});
|
||
// 打开监听
|
||
httpsServer.listen(
|
||
Number(config.https.listenPort),
|
||
config.https.listenIp,
|
||
() => {
|
||
logger.info("信令服务启动完成");
|
||
}
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 定时清理无效信令终端
|
||
*/
|
||
async function buildClientInterval() {
|
||
setInterval(() => {
|
||
const datetime = Date.now();
|
||
let failSize = 0;
|
||
let successSize = 0;
|
||
for (let i = 0; i < clients.length; i++) {
|
||
const session = clients[i];
|
||
// 超过五秒自动关闭
|
||
if (datetime - session.datetime >= 5000) {
|
||
clients.splice(i, 1);
|
||
if(session.authorize) {
|
||
successSize++;
|
||
} else {
|
||
failSize++;
|
||
session.close();
|
||
}
|
||
i--;
|
||
}
|
||
}
|
||
logger.info("定时清理无效信令终端", failSize, successSize, clients.length);
|
||
}, 60 * 1000);
|
||
}
|
||
|
||
/**
|
||
* 交互式控制台
|
||
*/
|
||
async function buildCommandConsole() {
|
||
if (!config.command) {
|
||
return;
|
||
}
|
||
process.stdin.setEncoding("UTF-8");
|
||
process.stdin.resume();
|
||
process.stdin.on("data", (data) => {
|
||
process.stdin.pause();
|
||
const command = data.replace(/^\s*/, "").replace(/\s*$/, "");
|
||
logger.info("");
|
||
switch (command) {
|
||
case "h":
|
||
case "help": {
|
||
logger.info("- h, help : 帮助信息");
|
||
logger.info("- os : 系统信息");
|
||
break;
|
||
}
|
||
case "":
|
||
default: {
|
||
logger.warn(`未知命令:'${command}'`);
|
||
logger.info("查询命令:'h' | 'help'");
|
||
break;
|
||
}
|
||
}
|
||
logger.info("");
|
||
process.stdin.resume();
|
||
});
|
||
}
|
||
|
||
/**
|
||
* 启动方法
|
||
*/
|
||
async function main() {
|
||
logger.debug("闹市早行客");
|
||
logger.info("江边独钓翁");
|
||
logger.warn("山中与谁同");
|
||
logger.error("绿竹细雨风");
|
||
logger.info("开始启动", config.name);
|
||
// await buildMediasoupWorkers();
|
||
await buildSignalServer();
|
||
await buildClientInterval();
|
||
await buildCommandConsole();
|
||
logger.info("启动完成", config.name);
|
||
}
|
||
|
||
// 启动服务
|
||
main();
|