diff --git a/dist/index.js b/dist/index.js index 4fab8a0..8649926 100644 --- a/dist/index.js +++ b/dist/index.js @@ -36,11 +36,15 @@ 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")); +const node_cron_1 = require("node-cron"); +const sendMessage_1 = __importDefault(require("./routes/sendMessage")); +const ServerStatusLog_1 = __importDefault(require("./models/ServerStatusLog")); (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)()); +app.use("/sendMessage", sendMessage_1.default); const serverLocation = process.env.SERVER_LOCATION; const serverName = process.env.SERVER_NAME; const serverType = process.env.SERVER_TYPE; @@ -170,6 +174,10 @@ async function endSession(activeSessionId) { } async function init() { try { + await ServerStatusLog_1.default.create({ + hostname: serverHostname, + action: "online", + }); await SessionServer_1.default.findOneAndUpdate({ hostname: serverHostname }, { location: serverLocation, name: serverName, @@ -210,3 +218,43 @@ app.listen(port, () => { console.log(`Server is listening on port ${port}`); init(); }); +(0, node_cron_1.schedule)("*/3 * * * * *", async () => { + // TODO - hostname + try { + const activeSessions = await ActiveSession_1.default.find({ + location: serverLocation, + name: serverName, + }); + for (const activeSession of activeSessions) { + const { ueProcessId, buildName, uePort, id } = activeSession; + const { stdout } = await execAsync(`wmic process where processId=${ueProcessId}`, { windowsHide: true }); + const ueProcessInfo = stdout.trim(); + if (ueProcessInfo) + return; + const filePath = `C:/pixel-streaming/builds/${buildName}/${buildName}.exe`; + const newUeProcess = (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 newUeProcesscessId = newUeProcess.pid; + await ActiveSession_1.default.findByIdAndUpdate(id, { + ueProcessId: newUeProcesscessId, + }); + } + } + catch (error) { + console.log(error); + } +}); diff --git a/dist/routes/register.js b/dist/routes/register.js deleted file mode 100644 index 590d51b..0000000 --- a/dist/routes/register.js +++ /dev/null @@ -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; diff --git a/package.json b/package.json index fa61117..37ec10a 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,8 @@ "express": "^4.18.2", "jsonwebtoken": "^9.0.2", "mongoose": "^8.2.0", + "node-cron": "^3.0.3", + "nodemailer": "^6.9.15", "tree-kill": "^1.2.2" }, "devDependencies": { @@ -22,6 +24,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" diff --git a/src/index.ts b/src/index.ts index adff15d..ad830a0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -8,6 +8,9 @@ import { exec, execFile } from "child_process"; import treeKill from "tree-kill"; import SessionServer from "./models/SessionServer"; import ActiveSession from "./models/ActiveSession"; +import { schedule } from "node-cron"; +import sendMessageRoute from "./routes/sendMessage"; +import ServerStatusLog from "./models/ServerStatusLog"; connectDB(); @@ -17,6 +20,8 @@ const port = process.env.PORT; 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; @@ -182,6 +187,11 @@ async function endSession(activeSessionId: string) { async function init() { try { + await ServerStatusLog.create({ + hostname: serverHostname, + action: "online", + }); + await SessionServer.findOneAndUpdate( { hostname: serverHostname }, { @@ -236,3 +246,53 @@ app.listen(port, () => { console.log(`Server is listening on port ${port}`); init(); }); + +schedule("*/3 * * * * *", async () => { + // TODO - hostname + try { + const activeSessions = await ActiveSession.find({ + location: serverLocation, + name: serverName, + }); + + for (const activeSession of activeSessions) { + const { ueProcessId, buildName, uePort, id } = activeSession; + + const { stdout } = await execAsync( + `wmic process where processId=${ueProcessId}`, + { windowsHide: true } + ); + + const ueProcessInfo = stdout.trim(); + + if (ueProcessInfo) return; + + const filePath = `C:/pixel-streaming/builds/${buildName}/${buildName}.exe`; + + const newUeProcess = 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 newUeProcesscessId = newUeProcess.pid; + + await ActiveSession.findByIdAndUpdate(id, { + ueProcessId: newUeProcesscessId, + }); + } + } catch (error) { + console.log(error); + } +}); diff --git a/src/models/ServerStatusLog.ts b/src/models/ServerStatusLog.ts new file mode 100644 index 0000000..a667f70 --- /dev/null +++ b/src/models/ServerStatusLog.ts @@ -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; diff --git a/src/routes/sendMessage.ts b/src/routes/sendMessage.ts new file mode 100644 index 0000000..27892fd --- /dev/null +++ b/src/routes/sendMessage.ts @@ -0,0 +1,41 @@ +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.from, // generated ethereal user + pass: req.body.password, // generated ethereal password + }, + }); + + const files = fs.readdirSync(req.body.path); + + // send mail with defined transport object + 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 + }); + + return res.json({ ok: 1 }); + } catch (error) { + console.log(error); + return res.json({ error: 1 }); + } +}); + +const sendMessageRoute = router; + +export default sendMessageRoute; diff --git a/src/routes/test.ts b/src/routes/test.ts deleted file mode 100644 index 9b000fd..0000000 --- a/src/routes/test.ts +++ /dev/null @@ -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; diff --git a/yarn.lock b/yarn.lock index ea90a4a..b435781 100644 --- a/yarn.lock +++ b/yarn.lock @@ -140,6 +140,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 +152,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" @@ -977,6 +989,13 @@ 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-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: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" @@ -984,6 +1003,11 @@ node-fetch@^2.6.7: 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" @@ -1383,6 +1407,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"