Files
2026-06-21 03:53:06 +03:00

115 lines
3.3 KiB
TypeScript

import config from "./config.ts";
import { getBgVMManagers } from "./vm/utils.ts";
import express from "express";
import bodyParser from "body-parser";
const app = express();
const vmManagers = getBgVMManagers();
app.use(bodyParser.json());
Object.values(vmManagers).forEach((manager) => {
manager?.runBackgroundJobs();
});
app.post("/assignVM", async (req, res) => {
try {
// Find a pool that matches the size and region requirements
const pools = Object.values(vmManagers).filter((mgr) => {
return (
mgr.getIsLarge() === Boolean(req.body.isLarge) &&
(mgr.getRegion() === req.body.region || !req.body.region)
);
});
let vm = null;
// Sequentially try each to give earlier pools preference
// We might want to add the ability to load balance as well by randomly selecting between pools with same priority
for (let pool of pools) {
console.log(
"try assignVM from pool:",
pool.getPoolName(),
req.body.roomId,
req.body.uid,
);
vm = await pool.assignVM(req.body.roomId, req.body.uid);
if (vm) {
res.json(vm);
return;
}
}
res.json(null);
} catch (e) {
console.warn(e);
res.status(500).end();
}
});
app.post("/releaseVM", async (req, res) => {
try {
const pool =
vmManagers[
req.body.provider + (req.body.isLarge ? "Large" : "") + req.body.region
];
if (req.body.id) {
await pool?.resetVM(req.body.id, req.body.roomId);
}
res.end();
} catch (e) {
console.warn(e);
res.status(500).end();
}
});
app.get("/stats", async (req, res) => {
const vmManagerStats: AnyDict = {};
for (let [key, vmManager] of Object.entries(vmManagers)) {
const availableVBrowsers = await vmManager?.getAvailableVBrowsers();
const stagingVBrowsers = await vmManager?.getStagingVBrowsers();
const size = await vmManager?.getCurrentSize();
if (key && vmManager) {
vmManagerStats[key] = {
availableVBrowsers,
stagingVBrowsers,
bufferSize: vmManager?.getTargetBuffer(),
// terminationVBrowsers,
size,
};
}
}
res.json(vmManagerStats);
});
app.get("/isFreePoolFull", async (req, res) => {
const freePools = Object.values(vmManagers).filter((mgr) => {
return mgr?.getIsLarge() === false && mgr?.getLimitSize() > 0;
});
const fullResult = await Promise.all<Boolean>(
freePools.map(async (freePool) => {
let isFull = false;
if (freePool) {
const availableCount = await freePool.getAvailableCount();
const limitSize = freePool?.getLimitSize() ?? 0;
const currentSize = await freePool.getCurrentSize();
isFull = Boolean(
limitSize > 0 &&
(Number(availableCount) === 0 ||
Number(currentSize) - Number(availableCount) > limitSize * 0.95),
);
}
return isFull;
}),
);
const isFull = freePools.length && fullResult.every(Boolean);
res.json({ isFull });
});
app.post("/updateSnapshot", async (req, res) => {
const pool = vmManagers[req.body.provider + req.body.region];
const result = await pool?.updateSnapshot();
res.send(result?.toString() + "\n");
});
app.listen(config.VMWORKER_PORT, () => {
console.log("vmWorker listening on %s", config.VMWORKER_PORT);
});