This repository has been archived on 2023-04-19. You can view files and clone it, but cannot push or open issues or pull requests.
odproxy-deprecated/index.ts

140 lines
3.1 KiB
TypeScript
Raw Normal View History

2022-06-08 22:06:57 +02:00
import http, { IncomingMessage, ServerResponse } from "http";
import httpProxy from 'http-proxy';
import fs from "fs";
import path from "path";
import os from "os";
import child_process, { ChildProcess } from "child_process";
import kill from "tree-kill";
class ServiceManager {
pwd!: string;
proxy = httpProxy.createProxy();
server = http.createServer((req, res) => this.listen(req, res));
services: Service[] = [];
stopped: boolean = false;
async setup() {
this.pwd = fs.mkdtempSync(path.join(os.tmpdir(), "odp_"));
this.server.listen(3000);
}
async stop() {
if(this.stopped) return;
this.stopped = true;
this.services.forEach(s => s.stop());
fs.rmdirSync(this.pwd);
}
async listen(req: IncomingMessage, res: ServerResponse) {
let oriHost = req.headers.host;
let host = oriHost.indexOf(":") ? oriHost.split(':')[0] : oriHost;
for(let i in this.services) {
if(this.services[i].hosts.indexOf(host) !== -1) {
this.proxy.web(req, res, {
target: {
socketPath: await this.services[i].start(),
host: "localhost"
}
});
return;
}
}
console.warn("Host", host, "not found!");
res.end("Host not found in host map");
}
}
class Service implements ServiceConfig {
hosts: string[];
command: string;
file: string;
child?: ChildProcess;
timeout?: number;
life_check?: NodeJS.Timeout;
last_activity: Date;
man: ServiceManager;
alive: boolean = false;
constructor(man: ServiceManager, config: ServiceConfig) {
this.man = man;
this.hosts = config.hosts;
this.command = config.command;
this.file = config.file;
this.timeout = config.timeout*1000;
man.services.push(this);
}
async start() {
this.last_activity = new Date;
if(this.timeout) {
if(this.life_check) clearTimeout(this.life_check);
this.life_check = setTimeout(() => {
if((new Date).getTime() > this.last_activity.getTime()+this.timeout) this.stop();
}, this.timeout);
}
if(!this.child) {
if(fs.existsSync(this.file)) fs.rmSync(this.file);
this.child = child_process.exec(this.command);
console.log(`Started service ${this.hosts[0]}`);
}
if(!this.alive) {
await new Promise((resolve) => {
let int = setInterval(() => {
if(fs.existsSync(this.file)) {
clearInterval(int);
resolve(null);
}
}, 100);
});
this.alive = true;
}
return this.file;
}
async stop() {
if(fs.existsSync(this.file)) fs.rmSync(this.file);
if(this.alive) {
this.alive = false;
kill(this.child.pid, "SIGUSR2");
this.child = null;
console.log(`Stopped service ${this.hosts[0]}`);
}
}
}
interface ServiceConfig {
hosts: string[];
command: string;
file: string;
timeout?: number;
};
let start = async (config: ServiceConfig[]) => {
let man = new ServiceManager;
await man.setup();
config.forEach(s => {
new Service(man, s);
});
let exit = async (e: any) => {
if(e) console.log(e);
man.stop();
process.exit(0);
};
process.on('exit', exit);
process.on('beforeExit', exit);
process.on('SIGINT', exit);
process.on('SIGUSR1', exit);
process.on('SIGUSR2', exit);
process.on('SIGTERM', exit);
process.on('uncaughtException', console.error);
};
let map = require("./map.json");
start(map);