updates
This commit is contained in:
210
libraries/deno-server-control-1.6.0-mod.ts
Normal file
210
libraries/deno-server-control-1.6.0-mod.ts
Normal file
@@ -0,0 +1,210 @@
|
||||
// Compatible with Deno 1.6.0 (works on CentOS 7)
|
||||
// https://play.hatter.me/doc/showDocDetail.jssp?id=8879
|
||||
// https://github.com/denoland/deno/releases/tag/v1.6.0
|
||||
// https://play.hatter.me/doc/showDocDetail.jssp?id=8881
|
||||
// https://play.hatter.me/doc/showDocDetail.jssp?id=8882
|
||||
|
||||
import {
|
||||
execCommand,
|
||||
execCommandShell,
|
||||
fetchWithTimeout,
|
||||
fromFileUrl,
|
||||
log,
|
||||
parseProcessLine,
|
||||
Process,
|
||||
ProcessBar,
|
||||
readFileToString,
|
||||
sleep,
|
||||
} from "https://global.hatter.ink/script/get/@1/deno-commons-1.6.0-mod.ts";
|
||||
|
||||
interface HealthCheck {
|
||||
url?: string;
|
||||
count?: number; // default 30
|
||||
timeoutMillis?: number; // default 1000
|
||||
intervalMillis?: number; // default 1000
|
||||
}
|
||||
|
||||
interface ServerControlConfig {
|
||||
appId?: string;
|
||||
startup?: string;
|
||||
healthCheck?: HealthCheck;
|
||||
}
|
||||
|
||||
async function listJavaProcesses(
|
||||
serverControlConfig: ServerControlConfig,
|
||||
): Promise<Process[]> {
|
||||
const appId = serverControlConfig.appId;
|
||||
const processOutput = await execCommand("ps", ["aux"]);
|
||||
processOutput.assertSuccess();
|
||||
const stdout = processOutput.getStdoutAsStringThenTrim();
|
||||
const lines = stdout.split("\n");
|
||||
const processes = lines.filter((line) => {
|
||||
return line.includes("java") && line.includes("hatterserver") &&
|
||||
line.includes(`-DAPPID=${appId}`);
|
||||
}).map((line) => {
|
||||
return parseProcessLine(line);
|
||||
});
|
||||
const filterProcesses: Process[] = [];
|
||||
for (const process of processes) {
|
||||
if (process !== null) {
|
||||
filterProcesses.push(process);
|
||||
}
|
||||
}
|
||||
return filterProcesses;
|
||||
}
|
||||
|
||||
async function checkServerStarted(
|
||||
serverControlConfig: ServerControlConfig,
|
||||
): Promise<boolean> {
|
||||
const healthCheck = serverControlConfig.healthCheck;
|
||||
const healthCheckUrl = healthCheck?.url;
|
||||
if (!healthCheck || !healthCheckUrl) {
|
||||
log.error("Health check URL is not configured!");
|
||||
return false;
|
||||
}
|
||||
const count = healthCheck.count || 30;
|
||||
const intervalMillis = healthCheck.intervalMillis || 1000;
|
||||
const timeoutMillis = healthCheck.timeoutMillis || 1000;
|
||||
let startServerSuccess = false;
|
||||
await new ProcessBar("Starting server").call(async () => {
|
||||
for (let i = 0; i < count; i++) {
|
||||
try {
|
||||
const response = await fetchWithTimeout(
|
||||
healthCheckUrl,
|
||||
timeoutMillis,
|
||||
);
|
||||
if (response.status === 200) {
|
||||
startServerSuccess = true;
|
||||
return true;
|
||||
}
|
||||
} catch (e) {
|
||||
// IGNORE
|
||||
}
|
||||
await sleep(intervalMillis);
|
||||
}
|
||||
});
|
||||
if (startServerSuccess) {
|
||||
log.success("Server started!");
|
||||
} else {
|
||||
log.warn("Server failed!");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function loadServerControlConfig(
|
||||
metaUrl: string,
|
||||
serverControlConfigFile?: string,
|
||||
): Promise<ServerControlConfig> {
|
||||
const fullServerControlConfigFile = serverControlConfigFile ||
|
||||
(fromFileUrl(metaUrl).replace(".ts", ".json"));
|
||||
log.debug(
|
||||
`Read server control config file: ${fullServerControlConfigFile}`,
|
||||
);
|
||||
const serverControlConfigJson = await readFileToString(
|
||||
fullServerControlConfigFile,
|
||||
);
|
||||
if (serverControlConfigJson === null) {
|
||||
throw new Error(`Read file ${fullServerControlConfigFile} failed.`);
|
||||
}
|
||||
return JSON.parse(
|
||||
serverControlConfigJson,
|
||||
) as ServerControlConfig;
|
||||
}
|
||||
|
||||
async function handleStatus(
|
||||
serverControlConfig: ServerControlConfig,
|
||||
): Promise<void> {
|
||||
const processes = await listJavaProcesses(serverControlConfig);
|
||||
if (processes.length === 0) {
|
||||
log.warn("No process are running!");
|
||||
return;
|
||||
}
|
||||
log.success(
|
||||
`Find ${processes.length} process(es), pid: \n-> ${
|
||||
processes.map((p) => p.pid).join("-> ")
|
||||
}`,
|
||||
);
|
||||
}
|
||||
|
||||
async function handleStop(serverControlConfig: ServerControlConfig) {
|
||||
const processes = await listJavaProcesses(serverControlConfig);
|
||||
if (processes.length === 0) {
|
||||
log.info("No process are running!");
|
||||
return;
|
||||
}
|
||||
if (processes.length > 1) {
|
||||
log.warn(
|
||||
`Too many processes are running, pid(s): ${
|
||||
processes.map((p) => p.pid).join(", ")
|
||||
}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
const pid = processes[0].pid;
|
||||
log.warn(`Kill pid: ${pid}`);
|
||||
await execCommandShell("kill", [`${pid}`]);
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
async function handleRestart(serverControlConfig: ServerControlConfig) {
|
||||
let processes = await listJavaProcesses(serverControlConfig);
|
||||
if (processes.length > 1) {
|
||||
log.warn(
|
||||
`Too many processes are running, pid(s): ${
|
||||
processes.map((p) => p.pid).join(", ")
|
||||
}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!serverControlConfig.startup) {
|
||||
log.error("Startup command is not configured!");
|
||||
return;
|
||||
}
|
||||
while (processes.length > 0) {
|
||||
await execCommandShell("kill", [`${processes[0].pid}`]);
|
||||
await sleep(500);
|
||||
processes = await listJavaProcesses(serverControlConfig);
|
||||
}
|
||||
log.info(`Run command: ${serverControlConfig.startup} &`);
|
||||
await execCommandShell("sh", ["-c", `${serverControlConfig.startup} &`]);
|
||||
log.success("Start server, checking ...");
|
||||
await checkServerStarted(serverControlConfig);
|
||||
}
|
||||
|
||||
export async function serverControlMain(metaUrl: string) {
|
||||
const args = Deno.args;
|
||||
if (args.length === 0) {
|
||||
log.error(`No args.
|
||||
|
||||
server-control.ts status
|
||||
server-control.ts kill|stop
|
||||
server-control.ts re|restart`);
|
||||
return;
|
||||
}
|
||||
const serverControlConfigFile = Deno.env.get("SERVER_CONTROL_CONFIG_FILE");
|
||||
const serverControlConfig = await loadServerControlConfig(
|
||||
metaUrl,
|
||||
serverControlConfigFile,
|
||||
);
|
||||
if (!serverControlConfig.appId) {
|
||||
log.error("Config appId not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (args[0]) {
|
||||
case "status":
|
||||
await handleStatus(serverControlConfig);
|
||||
return;
|
||||
case "kill":
|
||||
case "stop":
|
||||
await handleStop(serverControlConfig);
|
||||
return;
|
||||
case "re":
|
||||
case "restart":
|
||||
await handleRestart(serverControlConfig);
|
||||
return;
|
||||
default:
|
||||
log.warn("Argument error!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user