Compare commits
5 Commits
86864ac19e
...
eef57a9b21
| Author | SHA1 | Date | |
|---|---|---|---|
| eef57a9b21 | |||
| d977290646 | |||
| c8ce49acd6 | |||
| 1cf520814e | |||
| 312082d94c |
@@ -1,5 +1,5 @@
|
||||
SERVER_LOCATION=a1
|
||||
SERVER_NAME=s6
|
||||
SERVER_NAME=s7
|
||||
SERVER_TYPE=prod
|
||||
PORT=3000
|
||||
MONGO_URI=mongodb://root:p62Z!ZatgY25@194.26.138.94:27017
|
||||
+2
-1
@@ -1,2 +1,3 @@
|
||||
/logs
|
||||
/node_modules
|
||||
/node_modules
|
||||
/dist
|
||||
Vendored
-16
@@ -1,16 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const mongoose_1 = require("mongoose");
|
||||
async function connectDB() {
|
||||
try {
|
||||
await (0, mongoose_1.connect)(process.env.MONGO_URI, { dbName: "pixel_streaming2" });
|
||||
console.log("MongoDB connected...");
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.error(error.message);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
exports.default = connectDB;
|
||||
Vendored
-212
@@ -1,212 +0,0 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
require("dotenv/config");
|
||||
const db_1 = __importDefault(require("./config/db"));
|
||||
const express_1 = __importStar(require("express"));
|
||||
const cors_1 = __importDefault(require("cors"));
|
||||
const os_1 = __importStar(require("os"));
|
||||
const util_1 = __importDefault(require("util"));
|
||||
const child_process_1 = require("child_process");
|
||||
const tree_kill_1 = __importDefault(require("tree-kill"));
|
||||
const SessionServer_1 = __importDefault(require("./models/SessionServer"));
|
||||
const ActiveSession_1 = __importDefault(require("./models/ActiveSession"));
|
||||
(0, db_1.default)();
|
||||
const app = (0, express_1.default)();
|
||||
const port = process.env.PORT;
|
||||
app.use((0, express_1.json)());
|
||||
app.use((0, cors_1.default)());
|
||||
const serverLocation = process.env.SERVER_LOCATION;
|
||||
const serverName = process.env.SERVER_NAME;
|
||||
const serverType = process.env.SERVER_TYPE;
|
||||
const serverHostname = os_1.default.hostname();
|
||||
const nets = (0, os_1.networkInterfaces)();
|
||||
const localIP = Object.entries(nets)
|
||||
.find((net) => net[0] === "Ethernet")?.[1]
|
||||
?.find((obj) => obj.family === "IPv4")?.address;
|
||||
async function updateSessionServerData(data) {
|
||||
try {
|
||||
await SessionServer_1.default.findOneAndUpdate({ hostname: serverHostname }, data);
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.log("Error: ", error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
const execAsync = util_1.default.promisify(child_process_1.exec);
|
||||
async function getGpuMemoryFree() {
|
||||
try {
|
||||
const { stdout } = await execAsync("nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits", { windowsHide: true });
|
||||
const gpuMemoryFree = stdout.trimEnd();
|
||||
await updateSessionServerData({ gpuMemoryFree });
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.log("Error: ", error.message);
|
||||
}
|
||||
}
|
||||
setTimeout(async () => {
|
||||
await getGpuMemoryFree();
|
||||
}, 1000);
|
||||
}
|
||||
async function getAvailablePorts() {
|
||||
const cirrusPorts = [14000, 14001, 14002];
|
||||
for (const cirrusPort of cirrusPorts) {
|
||||
const activeSession = await ActiveSession_1.default.exists({
|
||||
location: serverLocation,
|
||||
name: serverName,
|
||||
cirrusPort,
|
||||
});
|
||||
if (activeSession)
|
||||
continue;
|
||||
const uePort = cirrusPort + 10;
|
||||
return { cirrusPort, uePort };
|
||||
}
|
||||
}
|
||||
async function startSession(buildName, ownerIp, endAt) {
|
||||
const filePath = `C:/pixel-streaming/builds/${buildName}/${buildName}.exe`;
|
||||
const availablePorts = await getAvailablePorts();
|
||||
if (!availablePorts) {
|
||||
console.log("No available ports");
|
||||
return;
|
||||
}
|
||||
const { cirrusPort, uePort } = availablePorts;
|
||||
const cirrusProcess = (0, child_process_1.execFile)("node", [
|
||||
`C:/pixel-streaming/signalling-server/cirrus.js`,
|
||||
`--StreamerPort`,
|
||||
`${uePort}`,
|
||||
`--HttpPort`,
|
||||
`${cirrusPort}`,
|
||||
]);
|
||||
const cirrusProcessId = cirrusProcess.pid;
|
||||
if (!cirrusProcessId) {
|
||||
console.log("Cirrus server was not started");
|
||||
return;
|
||||
}
|
||||
const ueProcess = (0, child_process_1.execFile)(filePath, [
|
||||
"-PixelStreamingIP=127.0.0.1",
|
||||
`-PixelStreamingPort=${uePort}`,
|
||||
"-RenderOffScreen",
|
||||
"-ForceRes",
|
||||
"-ResX=1920",
|
||||
"-ResY=1080",
|
||||
"-Unattended",
|
||||
"-PixelStreamingWebRTCMinBitrate=5000000",
|
||||
"-PixelStreamingWebRTCMaxBitrate=20000000",
|
||||
"-PixelStreamingH264Profile=HIGH",
|
||||
"-PixelStreamingWebRTCDisableReceiveAudio=true",
|
||||
"-PixelStreamingEncoderRateControl=VBR",
|
||||
// "-PixelStreamingHudStats=true",
|
||||
// `-SessionID=${session.id}`,
|
||||
]);
|
||||
const ueProcessId = ueProcess.pid;
|
||||
if (!ueProcessId) {
|
||||
console.log("UE application was not started");
|
||||
return;
|
||||
}
|
||||
const type = serverType;
|
||||
try {
|
||||
const activeSession = await ActiveSession_1.default.create({
|
||||
location: serverLocation,
|
||||
name: serverName,
|
||||
buildName,
|
||||
type,
|
||||
cirrusPort,
|
||||
uePort,
|
||||
cirrusProcessId,
|
||||
ueProcessId,
|
||||
ownerIp,
|
||||
endAt,
|
||||
localIP,
|
||||
});
|
||||
return activeSession;
|
||||
}
|
||||
catch (error) {
|
||||
(0, tree_kill_1.default)(cirrusProcessId);
|
||||
(0, tree_kill_1.default)(ueProcessId);
|
||||
console.log(error.message);
|
||||
}
|
||||
}
|
||||
async function endSession(activeSessionId) {
|
||||
try {
|
||||
const activeSession = await ActiveSession_1.default.findByIdAndDelete(activeSessionId);
|
||||
if (!activeSession) {
|
||||
console.log("Session with this ID not found");
|
||||
return;
|
||||
}
|
||||
(0, tree_kill_1.default)(activeSession.cirrusProcessId);
|
||||
(0, tree_kill_1.default)(activeSession.ueProcessId);
|
||||
console.log("Kill session");
|
||||
}
|
||||
catch (error) {
|
||||
console.log(error.message);
|
||||
}
|
||||
}
|
||||
async function init() {
|
||||
try {
|
||||
await SessionServer_1.default.findOneAndUpdate({ hostname: serverHostname }, {
|
||||
location: serverLocation,
|
||||
name: serverName,
|
||||
type: serverType,
|
||||
hostname: serverHostname,
|
||||
localIP,
|
||||
}, { upsert: true, new: true });
|
||||
getGpuMemoryFree();
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.log("Error: ", error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
app.post("/start", async (req, res) => {
|
||||
for (const [key, value] of Object.entries(req.body)) {
|
||||
if (value === "null")
|
||||
req.body[key] = undefined;
|
||||
}
|
||||
const { buildName, ownerIp, endAt } = req.body;
|
||||
console.log("req.body", req.body);
|
||||
if (!buildName || !ownerIp) {
|
||||
return res.json({ error: 1 });
|
||||
}
|
||||
const activeSession = await startSession(buildName, ownerIp, endAt);
|
||||
res.json(activeSession);
|
||||
});
|
||||
app.post("/end", async (req, res) => {
|
||||
const activeSessionId = req.body.activeSessionId;
|
||||
if (!activeSessionId) {
|
||||
return res.json({ error: 1 });
|
||||
}
|
||||
await endSession(activeSessionId);
|
||||
res.json({ ok: 1 });
|
||||
});
|
||||
app.listen(port, () => {
|
||||
console.log(`Server is listening on port ${port}`);
|
||||
init();
|
||||
});
|
||||
Vendored
-44
@@ -1,44 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const mongoose_1 = require("mongoose");
|
||||
const activeSessionSchema = new mongoose_1.Schema({
|
||||
location: {
|
||||
type: String,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
buildName: {
|
||||
type: String,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
},
|
||||
uePort: {
|
||||
type: Number,
|
||||
},
|
||||
cirrusPort: {
|
||||
type: Number,
|
||||
},
|
||||
ueProcessId: {
|
||||
type: Number,
|
||||
},
|
||||
cirrusProcessId: {
|
||||
type: Number,
|
||||
},
|
||||
ownerIp: {
|
||||
type: String,
|
||||
},
|
||||
endAt: {
|
||||
type: Date || null,
|
||||
},
|
||||
localIP: {
|
||||
type: String,
|
||||
},
|
||||
}, {
|
||||
timestamps: true,
|
||||
toJSON: { virtuals: true },
|
||||
toObject: { virtuals: true },
|
||||
});
|
||||
const ActiveSession = (0, mongoose_1.model)("Active_Session", activeSessionSchema);
|
||||
exports.default = ActiveSession;
|
||||
Vendored
-30
@@ -1,30 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const mongoose_1 = require("mongoose");
|
||||
const sessionServerSchema = new mongoose_1.Schema({
|
||||
location: {
|
||||
type: String,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
},
|
||||
hostname: {
|
||||
type: String,
|
||||
unique: true,
|
||||
},
|
||||
gpuMemoryFree: {
|
||||
type: Number,
|
||||
},
|
||||
localIP: {
|
||||
type: String,
|
||||
},
|
||||
}, {
|
||||
timestamps: true,
|
||||
toJSON: { virtuals: true },
|
||||
toObject: { virtuals: true },
|
||||
});
|
||||
const SessionServer = (0, mongoose_1.model)("Session_Server", sessionServerSchema);
|
||||
exports.default = SessionServer;
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = require("express");
|
||||
const router = (0, express_1.Router)();
|
||||
router.post("/", async (req, res) => {
|
||||
res.json({ ok: 1 });
|
||||
});
|
||||
const registerRouter = router;
|
||||
exports.default = registerRouter;
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const express_1 = require("express");
|
||||
const router = (0, express_1.Router)();
|
||||
router.get("/", async (_req, res) => {
|
||||
res.json({ ok: 1 });
|
||||
});
|
||||
const testRouter = router;
|
||||
exports.default = testRouter;
|
||||
Binary file not shown.
@@ -10,10 +10,15 @@
|
||||
"dependencies": {
|
||||
"bcrypt": "^5.1.1",
|
||||
"cors": "^2.8.5",
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.18.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"mongoose": "^8.2.0",
|
||||
"node-cron": "^3.0.3",
|
||||
"nodemailer": "^6.9.15",
|
||||
"systeminformation": "^5.31.0",
|
||||
"telegraf": "^4.16.3",
|
||||
"tree-kill": "^1.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -22,6 +27,8 @@
|
||||
"@types/express": "^4.17.21",
|
||||
"@types/jsonwebtoken": "^9.0.6",
|
||||
"@types/node": "^20.11.20",
|
||||
"@types/node-cron": "^3.0.11",
|
||||
"@types/nodemailer": "^6.4.16",
|
||||
"nodemon": "^3.1.0",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.3.3"
|
||||
|
||||
+191
-65
@@ -1,36 +1,76 @@
|
||||
import "dotenv/config";
|
||||
import connectDB from "./config/db";
|
||||
import express, { json } from "express";
|
||||
import { exec, execFile } from "child_process";
|
||||
import cors from "cors";
|
||||
import express, { json } from "express";
|
||||
import os, { networkInterfaces } from "os";
|
||||
import util from "util";
|
||||
import { exec, execFile } from "child_process";
|
||||
import { schedule } from "node-cron";
|
||||
import si from "systeminformation";
|
||||
import treeKill from "tree-kill";
|
||||
import SessionServer from "./models/SessionServer";
|
||||
|
||||
import connectDB from "./config/db";
|
||||
import ActiveSession from "./models/ActiveSession";
|
||||
import SessionServer from "./models/SessionServer";
|
||||
import sendMessageRoute from "./routes/sendMessage";
|
||||
|
||||
// Constants
|
||||
const BUILDS_PATH = "C:/pixel-streaming/builds";
|
||||
const CIRRUS_SERVER_PATH = "C:/pixel-streaming/signalling-server/cirrus.js";
|
||||
const CIRRUS_PORTS = [14000, 14001, 14002] as const;
|
||||
const PORT_OFFSET = 10;
|
||||
const GPU_POLL_INTERVAL_MS = 1000;
|
||||
|
||||
const UE_PROCESS_ARGS = [
|
||||
"-RenderOffScreen",
|
||||
"-ForceRes",
|
||||
"-ResX=1920",
|
||||
"-ResY=1080",
|
||||
"-Unattended",
|
||||
"-PixelStreamingWebRTCMinBitrate=5000000",
|
||||
"-PixelStreamingWebRTCMaxBitrate=20000000",
|
||||
"-PixelStreamingH264Profile=HIGH",
|
||||
"-PixelStreamingWebRTCDisableReceiveAudio=true",
|
||||
"-PixelStreamingEncoderRateControl=VBR",
|
||||
] as const;
|
||||
|
||||
function getUeProcessArgs(uePort: number): string[] {
|
||||
return [
|
||||
"-PixelStreamingIP=127.0.0.1",
|
||||
`-PixelStreamingPort=${uePort}`,
|
||||
...UE_PROCESS_ARGS,
|
||||
];
|
||||
}
|
||||
|
||||
connectDB();
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT;
|
||||
const port = process.env.PORT ?? 3000;
|
||||
|
||||
app.use(json());
|
||||
app.use(cors());
|
||||
app.use("/sendMessage", sendMessageRoute);
|
||||
|
||||
const serverLocation = process.env.SERVER_LOCATION;
|
||||
const serverName = process.env.SERVER_NAME;
|
||||
const serverType = process.env.SERVER_TYPE;
|
||||
const serverHostname = os.hostname();
|
||||
const serverConfig = {
|
||||
location: process.env.SERVER_LOCATION,
|
||||
name: process.env.SERVER_NAME,
|
||||
type: process.env.SERVER_TYPE,
|
||||
hostname: os.hostname(),
|
||||
};
|
||||
|
||||
const nets = networkInterfaces();
|
||||
|
||||
const localIP = Object.entries(nets)
|
||||
.find((net) => net[0] === "Ethernet")?.[1]
|
||||
?.find((obj) => obj.family === "IPv4")?.address;
|
||||
function getLocalIP(): string | undefined {
|
||||
return Object.entries(nets)
|
||||
.find((net) => net[0].includes("Ethernet"))?.[1]
|
||||
?.find((obj) => obj.family === "IPv4")?.address;
|
||||
}
|
||||
|
||||
async function updateSessionServerData(data: any) {
|
||||
async function updateSessionServerData(data: Record<string, unknown>) {
|
||||
try {
|
||||
await SessionServer.findOneAndUpdate({ hostname: serverHostname }, data);
|
||||
await SessionServer.findOneAndUpdate(
|
||||
{ hostname: serverConfig.hostname },
|
||||
data
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.log("Error: ", error.message);
|
||||
@@ -39,43 +79,100 @@ async function updateSessionServerData(data: any) {
|
||||
}
|
||||
|
||||
const execAsync = util.promisify(exec);
|
||||
const NETWORK_LOG_INTERVAL = 10; // log network devices every N polls
|
||||
let networkPollCount = 0;
|
||||
|
||||
async function getGpuMemoryFree() {
|
||||
async function getSystemStats() {
|
||||
try {
|
||||
const { stdout } = await execAsync(
|
||||
"nvidia-smi --query-gpu=memory.free --format=csv,noheader,nounits",
|
||||
{ windowsHide: true }
|
||||
);
|
||||
const data: Record<string, unknown> = {};
|
||||
|
||||
const gpuMemoryFree = stdout.trimEnd();
|
||||
// RAM (os)
|
||||
const ramTotalMB = Math.round(os.totalmem() / 1024 / 1024);
|
||||
const ramUsedMB = ramTotalMB - Math.round(os.freemem() / 1024 / 1024);
|
||||
data.ramTotal = ramTotalMB;
|
||||
data.ramUsed = ramUsedMB;
|
||||
|
||||
await updateSessionServerData({ gpuMemoryFree });
|
||||
// CPU (systeminformation)
|
||||
const cpuLoad = await si.currentLoad();
|
||||
data.cpuUtilization = Math.round(cpuLoad.currentLoad);
|
||||
|
||||
// GPU (nvidia-smi)
|
||||
try {
|
||||
const { stdout } = await execAsync(
|
||||
"nvidia-smi --query-gpu=memory.total,memory.used,utilization.gpu --format=csv,noheader,nounits",
|
||||
{ windowsHide: true }
|
||||
);
|
||||
|
||||
const values = stdout
|
||||
.trim()
|
||||
.split("\n")[0]
|
||||
.split(",")
|
||||
.map((v) => parseInt(v.trim(), 10));
|
||||
const [gpuTotal, gpuUsed, gpuUtilization] = values;
|
||||
|
||||
if (!Number.isNaN(gpuTotal) && !Number.isNaN(gpuUsed)) {
|
||||
data.gpuMemoryTotal = gpuTotal;
|
||||
data.gpuMemoryUsed = gpuUsed;
|
||||
if (!Number.isNaN(gpuUtilization)) {
|
||||
data.gpuUtilization = gpuUtilization;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// GPU unavailable, CPU/RAM still updated
|
||||
}
|
||||
|
||||
// Network (systeminformation)
|
||||
try {
|
||||
const networkStats = await si.networkStats("*");
|
||||
const totalRxSec = networkStats.reduce(
|
||||
(sum, iface) => sum + (iface.rx_sec ?? 0),
|
||||
0
|
||||
);
|
||||
const totalTxSec = networkStats.reduce(
|
||||
(sum, iface) => sum + (iface.tx_sec ?? 0),
|
||||
0
|
||||
);
|
||||
|
||||
data.networkDownloadSpeed =
|
||||
Math.round(((totalRxSec * 8) / 1_000_000) * 100) / 100;
|
||||
data.networkUploadSpeed =
|
||||
Math.round(((totalTxSec * 8) / 1_000_000) * 100) / 100;
|
||||
|
||||
networkPollCount++;
|
||||
if (networkPollCount % NETWORK_LOG_INTERVAL === 0) {
|
||||
const ifaceInfo = networkStats
|
||||
.map(
|
||||
(n) =>
|
||||
`${n.iface} (${(((n.rx_sec ?? 0) * 8) / 1_000_000).toFixed(2)} ↓ / ${(((n.tx_sec ?? 0) * 8) / 1_000_000).toFixed(2)} ↑ Mbps)`
|
||||
)
|
||||
.join("; ");
|
||||
console.log("Network stats from:", ifaceInfo || "no interfaces");
|
||||
}
|
||||
} catch {
|
||||
// networkStats unavailable
|
||||
}
|
||||
|
||||
await updateSessionServerData(data);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.log("Error: ", error.message);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(async () => {
|
||||
await getGpuMemoryFree();
|
||||
}, 1000);
|
||||
setTimeout(getSystemStats, GPU_POLL_INTERVAL_MS);
|
||||
}
|
||||
|
||||
async function getAvailablePorts() {
|
||||
const cirrusPorts = [14000, 14001, 14002];
|
||||
|
||||
for (const cirrusPort of cirrusPorts) {
|
||||
for (const cirrusPort of CIRRUS_PORTS) {
|
||||
const activeSession = await ActiveSession.exists({
|
||||
location: serverLocation,
|
||||
name: serverName,
|
||||
location: serverConfig.location,
|
||||
name: serverConfig.name,
|
||||
cirrusPort,
|
||||
});
|
||||
|
||||
if (activeSession) continue;
|
||||
|
||||
const uePort = cirrusPort + 10;
|
||||
|
||||
return { cirrusPort, uePort };
|
||||
return { cirrusPort, uePort: cirrusPort + PORT_OFFSET };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,8 +181,7 @@ async function startSession(
|
||||
ownerIp: string,
|
||||
endAt?: string
|
||||
) {
|
||||
const filePath = `C:/pixel-streaming/builds/${buildName}/${buildName}.exe`;
|
||||
|
||||
const filePath = `${BUILDS_PATH}/${buildName}/${buildName}.exe`;
|
||||
const availablePorts = await getAvailablePorts();
|
||||
|
||||
if (!availablePorts) {
|
||||
@@ -96,11 +192,11 @@ async function startSession(
|
||||
const { cirrusPort, uePort } = availablePorts;
|
||||
|
||||
const cirrusProcess = execFile("node", [
|
||||
`C:/pixel-streaming/signalling-server/cirrus.js`,
|
||||
`--StreamerPort`,
|
||||
`${uePort}`,
|
||||
`--HttpPort`,
|
||||
`${cirrusPort}`,
|
||||
CIRRUS_SERVER_PATH,
|
||||
"--StreamerPort",
|
||||
String(uePort),
|
||||
"--HttpPort",
|
||||
String(cirrusPort),
|
||||
]);
|
||||
|
||||
const cirrusProcessId = cirrusProcess.pid;
|
||||
@@ -110,38 +206,24 @@ async function startSession(
|
||||
return;
|
||||
}
|
||||
|
||||
const ueProcess = execFile(filePath, [
|
||||
"-PixelStreamingIP=127.0.0.1",
|
||||
`-PixelStreamingPort=${uePort}`,
|
||||
"-RenderOffScreen",
|
||||
"-ForceRes",
|
||||
"-ResX=1920",
|
||||
"-ResY=1080",
|
||||
"-Unattended",
|
||||
"-PixelStreamingWebRTCMinBitrate=5000000",
|
||||
"-PixelStreamingWebRTCMaxBitrate=20000000",
|
||||
"-PixelStreamingH264Profile=HIGH",
|
||||
"-PixelStreamingWebRTCDisableReceiveAudio=true",
|
||||
"-PixelStreamingEncoderRateControl=VBR",
|
||||
// "-PixelStreamingHudStats=true",
|
||||
// `-SessionID=${session.id}`,
|
||||
]);
|
||||
const ueProcess = execFile(filePath, getUeProcessArgs(uePort));
|
||||
|
||||
const ueProcessId = ueProcess.pid;
|
||||
|
||||
if (!ueProcessId) {
|
||||
console.log("UE application was not started");
|
||||
treeKill(cirrusProcessId);
|
||||
return;
|
||||
}
|
||||
|
||||
const type = serverType;
|
||||
const localIP = getLocalIP();
|
||||
|
||||
try {
|
||||
const activeSession = await ActiveSession.create({
|
||||
location: serverLocation,
|
||||
name: serverName,
|
||||
location: serverConfig.location,
|
||||
name: serverConfig.name,
|
||||
buildName,
|
||||
type,
|
||||
type: serverConfig.type,
|
||||
cirrusPort,
|
||||
uePort,
|
||||
cirrusProcessId,
|
||||
@@ -182,19 +264,26 @@ async function endSession(activeSessionId: string) {
|
||||
|
||||
async function init() {
|
||||
try {
|
||||
// await ServerStatusLog.create({
|
||||
// hostname: serverHostname,
|
||||
// action: "online",
|
||||
// });
|
||||
|
||||
const localIP = getLocalIP();
|
||||
|
||||
await SessionServer.findOneAndUpdate(
|
||||
{ hostname: serverHostname },
|
||||
{ hostname: serverConfig.hostname },
|
||||
{
|
||||
location: serverLocation,
|
||||
name: serverName,
|
||||
type: serverType,
|
||||
hostname: serverHostname,
|
||||
location: serverConfig.location,
|
||||
name: serverConfig.name,
|
||||
type: serverConfig.type,
|
||||
hostname: serverConfig.hostname,
|
||||
localIP,
|
||||
},
|
||||
{ upsert: true, new: true }
|
||||
);
|
||||
|
||||
getGpuMemoryFree();
|
||||
getSystemStats();
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
console.log("Error: ", error.message);
|
||||
@@ -236,3 +325,40 @@ app.listen(port, () => {
|
||||
console.log(`Server is listening on port ${port}`);
|
||||
init();
|
||||
});
|
||||
|
||||
async function checkAndRestartUeProcesses() {
|
||||
try {
|
||||
const activeSessions = await ActiveSession.find({
|
||||
location: serverConfig.location,
|
||||
name: serverConfig.name,
|
||||
});
|
||||
|
||||
for (const activeSession of activeSessions) {
|
||||
const { ueProcessId, buildName, uePort, id } = activeSession;
|
||||
|
||||
if (uePort == null || !buildName) continue;
|
||||
|
||||
const { stdout } = await execAsync(
|
||||
`wmic process where processId=${ueProcessId}`,
|
||||
{ windowsHide: true }
|
||||
);
|
||||
|
||||
const ueProcessInfo = stdout.trim();
|
||||
if (ueProcessInfo) continue;
|
||||
|
||||
const filePath = `${BUILDS_PATH}/${buildName}/${buildName}.exe`;
|
||||
const newUeProcess = execFile(filePath, getUeProcessArgs(uePort));
|
||||
const newUeProcessId = newUeProcess.pid;
|
||||
|
||||
if (newUeProcessId) {
|
||||
await ActiveSession.findByIdAndUpdate(id, {
|
||||
ueProcessId: newUeProcessId,
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("checkAndRestartUeProcesses:", error);
|
||||
}
|
||||
}
|
||||
|
||||
schedule("*/3 * * * * *", checkAndRestartUeProcesses);
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import { model, Schema } from "mongoose";
|
||||
|
||||
const serverStatusLogSchema = new Schema(
|
||||
{
|
||||
hostname: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
action: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
toJSON: { virtuals: true },
|
||||
toObject: { virtuals: true },
|
||||
}
|
||||
);
|
||||
|
||||
const ServerStatusLog = model("ServerStatusLog", serverStatusLogSchema);
|
||||
|
||||
export default ServerStatusLog;
|
||||
@@ -15,12 +15,33 @@ const sessionServerSchema = new Schema(
|
||||
type: String,
|
||||
unique: true,
|
||||
},
|
||||
gpuMemoryFree: {
|
||||
gpuMemoryTotal: {
|
||||
type: Number,
|
||||
},
|
||||
gpuMemoryUsed: {
|
||||
type: Number,
|
||||
},
|
||||
gpuUtilization: {
|
||||
type: Number,
|
||||
},
|
||||
cpuUtilization: {
|
||||
type: Number,
|
||||
},
|
||||
ramTotal: {
|
||||
type: Number,
|
||||
},
|
||||
ramUsed: {
|
||||
type: Number,
|
||||
},
|
||||
localIP: {
|
||||
type: String,
|
||||
},
|
||||
networkDownloadSpeed: {
|
||||
type: Number,
|
||||
},
|
||||
networkUploadSpeed: {
|
||||
type: Number,
|
||||
},
|
||||
},
|
||||
{
|
||||
timestamps: true,
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { Router } from "express";
|
||||
import { createTransport } from "nodemailer";
|
||||
import fs from "fs";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post("/", async (req, res) => {
|
||||
console.log(req.body);
|
||||
|
||||
try {
|
||||
const transporter = createTransport({
|
||||
host: req.body.host,
|
||||
port: req.body.port,
|
||||
secure: true, // true for 465, false for other ports
|
||||
auth: {
|
||||
user: req.body.login, // generated ethereal user
|
||||
pass: req.body.password, // generated ethereal password
|
||||
},
|
||||
});
|
||||
|
||||
const files = fs.readdirSync(req.body.path);
|
||||
|
||||
// send mail with defined transport object
|
||||
const result = await transporter.sendMail({
|
||||
from: req.body.from, // sender address
|
||||
to: req.body.to, // list of receivers
|
||||
subject: req.body.subject, // Subject line
|
||||
html: req.body.text, // html body
|
||||
attachments: files.map((file) => ({ path: `${req.body.path}/${file}` })), // attachment files
|
||||
});
|
||||
|
||||
console.log(result);
|
||||
|
||||
return res.json({ ok: 1 });
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return res.json({ error: 1 });
|
||||
}
|
||||
});
|
||||
|
||||
const sendMessageRoute = router;
|
||||
|
||||
export default sendMessageRoute;
|
||||
@@ -1,11 +0,0 @@
|
||||
import { Router } from "express";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/", async (_req, res) => {
|
||||
res.json({ ok: 1 });
|
||||
});
|
||||
|
||||
const testRouter = router;
|
||||
|
||||
export default testRouter;
|
||||
@@ -49,6 +49,11 @@
|
||||
dependencies:
|
||||
sparse-bitfield "^3.0.3"
|
||||
|
||||
"@telegraf/types@^7.1.0":
|
||||
version "7.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@telegraf/types/-/types-7.1.0.tgz#d8bd9b2f5070b4de46971416e890338cd89fc23d"
|
||||
integrity sha512-kGevOIbpMcIlCDeorKGpwZmdH7kHbqlk/Yj6dEpJMKEQw5lk0KVQY0OLXaCswy8GqlIVLd5625OB+rAntP9xVw==
|
||||
|
||||
"@tsconfig/node10@^1.0.7":
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.9.tgz#df4907fc07a886922637b15e02d4cebc4c0021b2"
|
||||
@@ -140,6 +145,11 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690"
|
||||
integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==
|
||||
|
||||
"@types/node-cron@^3.0.11":
|
||||
version "3.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@types/node-cron/-/node-cron-3.0.11.tgz#70b7131f65038ae63cfe841354c8aba363632344"
|
||||
integrity sha512-0ikrnug3/IyneSHqCBeslAhlK2aBfYek1fGo4bP4QnZPmiqSGRK+Oy7ZMisLWkesffJvQ1cqAcBnJC+8+nxIAg==
|
||||
|
||||
"@types/node@*", "@types/node@^20.11.20":
|
||||
version "20.11.24"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.24.tgz#cc207511104694e84e9fb17f9a0c4c42d4517792"
|
||||
@@ -147,6 +157,13 @@
|
||||
dependencies:
|
||||
undici-types "~5.26.4"
|
||||
|
||||
"@types/nodemailer@^6.4.16":
|
||||
version "6.4.16"
|
||||
resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.16.tgz#db006abcb1e1c8e6ea2fb53b27fefec3c03eaa6c"
|
||||
integrity sha512-uz6hN6Pp0upXMcilM61CoKyjT7sskBoOWpptkjjJp8jIMlTdc3xG01U7proKkXzruMS4hS0zqtHNkNPFB20rKQ==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/qs@*":
|
||||
version "6.9.12"
|
||||
resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.12.tgz#afa96b383a3a6fdc859453a1892d41b607fc7756"
|
||||
@@ -191,6 +208,13 @@ abbrev@1:
|
||||
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
|
||||
integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
|
||||
|
||||
abort-controller@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392"
|
||||
integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==
|
||||
dependencies:
|
||||
event-target-shim "^5.0.0"
|
||||
|
||||
accepts@~1.3.8:
|
||||
version "1.3.8"
|
||||
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e"
|
||||
@@ -308,11 +332,29 @@ bson@^6.2.0:
|
||||
resolved "https://registry.yarnpkg.com/bson/-/bson-6.4.0.tgz#99c2e37b515e6766ce8b5929e01fa79de5767d50"
|
||||
integrity sha512-6/gSSEdbkuFlSb+ufj5jUSU4+wo8xQOwm2bDSqwmxiPE17JTpsP63eAwoN8iF8Oy4gJYj+PAL3zdRCTdaw5Y1g==
|
||||
|
||||
buffer-alloc-unsafe@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
|
||||
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
||||
|
||||
buffer-alloc@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
|
||||
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
|
||||
dependencies:
|
||||
buffer-alloc-unsafe "^1.1.0"
|
||||
buffer-fill "^1.0.0"
|
||||
|
||||
buffer-equal-constant-time@1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
|
||||
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
|
||||
|
||||
buffer-fill@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
|
||||
integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==
|
||||
|
||||
bytes@3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
|
||||
@@ -399,6 +441,11 @@ create-require@^1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||
|
||||
date-fns@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-4.1.0.tgz#64b3d83fff5aa80438f5b1a633c2e83b8a1c2d14"
|
||||
integrity sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==
|
||||
|
||||
debug@2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
@@ -413,6 +460,13 @@ debug@4, debug@4.x, debug@^4:
|
||||
dependencies:
|
||||
ms "2.1.2"
|
||||
|
||||
debug@^4.3.4:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a"
|
||||
integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==
|
||||
dependencies:
|
||||
ms "^2.1.3"
|
||||
|
||||
define-data-property@^1.1.2:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
|
||||
@@ -496,6 +550,11 @@ etag@~1.8.1:
|
||||
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
|
||||
integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==
|
||||
|
||||
event-target-shim@^5.0.0:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789"
|
||||
integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==
|
||||
|
||||
express@^4.18.2:
|
||||
version "4.18.3"
|
||||
resolved "https://registry.yarnpkg.com/express/-/express-4.18.3.tgz#6870746f3ff904dee1819b82e4b51509afffb0d4"
|
||||
@@ -952,6 +1011,11 @@ mquery@5.0.0:
|
||||
dependencies:
|
||||
debug "4.x"
|
||||
|
||||
mri@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b"
|
||||
integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==
|
||||
|
||||
ms@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
|
||||
@@ -962,7 +1026,7 @@ ms@2.1.2:
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
|
||||
|
||||
ms@2.1.3, ms@^2.1.1:
|
||||
ms@2.1.3, ms@^2.1.1, ms@^2.1.3:
|
||||
version "2.1.3"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
|
||||
integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
|
||||
@@ -977,13 +1041,25 @@ node-addon-api@^5.0.0:
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-5.1.0.tgz#49da1ca055e109a23d537e9de43c09cca21eb762"
|
||||
integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==
|
||||
|
||||
node-fetch@^2.6.7:
|
||||
node-cron@^3.0.3:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/node-cron/-/node-cron-3.0.3.tgz#c4bc7173dd96d96c50bdb51122c64415458caff2"
|
||||
integrity sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==
|
||||
dependencies:
|
||||
uuid "8.3.2"
|
||||
|
||||
node-fetch@^2.6.7, node-fetch@^2.7.0:
|
||||
version "2.7.0"
|
||||
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d"
|
||||
integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==
|
||||
dependencies:
|
||||
whatwg-url "^5.0.0"
|
||||
|
||||
nodemailer@^6.9.15:
|
||||
version "6.9.15"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.15.tgz#57b79dc522be27e0e47ac16cc860aa0673e62e04"
|
||||
integrity sha512-AHf04ySLC6CIfuRtRiEYtGEXgRfa6INgWGluDhnxTZhHSKvrBu7lc1VVchQ0d8nPc4cFaZoPq8vkyNoZr0TpGQ==
|
||||
|
||||
nodemon@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.1.0.tgz#ff7394f2450eb6a5e96fe4180acd5176b29799c9"
|
||||
@@ -1053,6 +1129,11 @@ once@^1.3.0:
|
||||
dependencies:
|
||||
wrappy "1"
|
||||
|
||||
p-timeout@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-4.1.0.tgz#788253c0452ab0ffecf18a62dff94ff1bd09ca0a"
|
||||
integrity sha512-+/wmHtzJuWii1sXn3HCuH/FTwGhrp4tmJTxSKJbfS+vkipci6osxXM5mY0jUiRzWKMTgUT8l7HFbeSwZAynqHw==
|
||||
|
||||
parseurl@~1.3.3:
|
||||
version "1.3.3"
|
||||
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
|
||||
@@ -1141,11 +1222,23 @@ safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0:
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
|
||||
integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
|
||||
|
||||
safe-compare@^1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/safe-compare/-/safe-compare-1.1.4.tgz#5e0128538a82820e2e9250cd78e45da6786ba593"
|
||||
integrity sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ==
|
||||
dependencies:
|
||||
buffer-alloc "^1.2.0"
|
||||
|
||||
"safer-buffer@>= 2.1.2 < 3":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
|
||||
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
|
||||
|
||||
sandwich-stream@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/sandwich-stream/-/sandwich-stream-2.0.2.tgz#6d1feb6cf7e9fe9fadb41513459a72c2e84000fa"
|
||||
integrity sha512-jLYV0DORrzY3xaz/S9ydJL6Iz7essZeAfnAavsJ+zsJGZ1MOnsS52yRjU3uF3pJa/lla7+wisp//fxOwOH8SKQ==
|
||||
|
||||
semver@^6.0.0:
|
||||
version "6.3.1"
|
||||
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
|
||||
@@ -1278,6 +1371,11 @@ supports-color@^5.5.0:
|
||||
dependencies:
|
||||
has-flag "^3.0.0"
|
||||
|
||||
systeminformation@^5.31.0:
|
||||
version "5.31.0"
|
||||
resolved "https://registry.yarnpkg.com/systeminformation/-/systeminformation-5.31.0.tgz#fce21969b080e6971accf2d601b78f17271d7715"
|
||||
integrity sha512-z5pjzvC8UnQJ/iu34z+mo3lAeMzTGdArjPQoG5uPyV5XY4BY+M6ZcRTl4XnZqudz6sP713LhWMKv6e0kGFGCgQ==
|
||||
|
||||
tar@^6.1.11:
|
||||
version "6.2.0"
|
||||
resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73"
|
||||
@@ -1290,6 +1388,20 @@ tar@^6.1.11:
|
||||
mkdirp "^1.0.3"
|
||||
yallist "^4.0.0"
|
||||
|
||||
telegraf@^4.16.3:
|
||||
version "4.16.3"
|
||||
resolved "https://registry.yarnpkg.com/telegraf/-/telegraf-4.16.3.tgz#f03fa30482b540a7f9895af8f13ec8f432840a66"
|
||||
integrity sha512-yjEu2NwkHlXu0OARWoNhJlIjX09dRktiMQFsM678BAH/PEPVwctzL67+tvXqLCRQQvm3SDtki2saGO9hLlz68w==
|
||||
dependencies:
|
||||
"@telegraf/types" "^7.1.0"
|
||||
abort-controller "^3.0.0"
|
||||
debug "^4.3.4"
|
||||
mri "^1.2.0"
|
||||
node-fetch "^2.7.0"
|
||||
p-timeout "^4.1.0"
|
||||
safe-compare "^1.1.4"
|
||||
sandwich-stream "^2.0.2"
|
||||
|
||||
to-regex-range@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
|
||||
@@ -1383,6 +1495,11 @@ utils-merge@1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
|
||||
|
||||
uuid@8.3.2:
|
||||
version "8.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
|
||||
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
|
||||
|
||||
v8-compile-cache-lib@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"
|
||||
|
||||
Reference in New Issue
Block a user