formatting updates
This commit is contained in:
parent
ffe21e6d6c
commit
d2d0f45c81
50 changed files with 7783 additions and 7432 deletions
170
src/stats.ts
170
src/stats.ts
|
@ -1,39 +1,39 @@
|
|||
import fs from"node:fs";
|
||||
import path from"node:path";
|
||||
import{ getApiUrls }from"./utils.js";
|
||||
import{ fileURLToPath }from"node:url";
|
||||
import{ setTimeout, clearTimeout }from"node:timers";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import {getApiUrls} from "./utils.js";
|
||||
import {fileURLToPath} from "node:url";
|
||||
import {setTimeout, clearTimeout} from "node:timers";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
interface UptimeEntry {
|
||||
time: number;
|
||||
online: boolean;
|
||||
time: number;
|
||||
online: boolean;
|
||||
}
|
||||
|
||||
interface Instance {
|
||||
name: string;
|
||||
urls?: { api: string };
|
||||
url?: string;
|
||||
online?: boolean;
|
||||
uptime?: {
|
||||
daytime: number;
|
||||
weektime: number;
|
||||
alltime: number;
|
||||
};
|
||||
name: string;
|
||||
urls?: {api: string};
|
||||
url?: string;
|
||||
online?: boolean;
|
||||
uptime?: {
|
||||
daytime: number;
|
||||
weektime: number;
|
||||
alltime: number;
|
||||
};
|
||||
}
|
||||
|
||||
const uptimeObject: Map<string, UptimeEntry[]> = loadUptimeObject();
|
||||
export{ uptimeObject as uptime };
|
||||
export {uptimeObject as uptime};
|
||||
|
||||
function loadUptimeObject(): Map<string, UptimeEntry[]>{
|
||||
const filePath = process.env.JANK_UPTIME_JSON_PATH||path.join(__dirname, "..", "uptime.json");
|
||||
if(fs.existsSync(filePath)){
|
||||
try{
|
||||
function loadUptimeObject(): Map<string, UptimeEntry[]> {
|
||||
const filePath = process.env.JANK_UPTIME_JSON_PATH || path.join(__dirname, "..", "uptime.json");
|
||||
if (fs.existsSync(filePath)) {
|
||||
try {
|
||||
const data = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
||||
return new Map(Object.entries(data));
|
||||
}catch(error){
|
||||
} catch (error) {
|
||||
console.error("Error reading uptime.json:", error);
|
||||
return new Map();
|
||||
}
|
||||
|
@ -43,26 +43,26 @@ function loadUptimeObject(): Map<string, UptimeEntry[]>{
|
|||
|
||||
let saveTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
function saveUptimeObject(): void{
|
||||
if(saveTimeout){
|
||||
function saveUptimeObject(): void {
|
||||
if (saveTimeout) {
|
||||
clearTimeout(saveTimeout);
|
||||
}
|
||||
saveTimeout = setTimeout(()=>{
|
||||
saveTimeout = setTimeout(() => {
|
||||
const data = Object.fromEntries(uptimeObject);
|
||||
fs.writeFile(
|
||||
process.env.JANK_UPTIME_JSON_PATH||path.join(__dirname, "..", "uptime.json"),
|
||||
process.env.JANK_UPTIME_JSON_PATH || path.join(__dirname, "..", "uptime.json"),
|
||||
JSON.stringify(data),
|
||||
error=>{
|
||||
if(error){
|
||||
(error) => {
|
||||
if (error) {
|
||||
console.error("Error saving uptime.json:", error);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}, 5000); // Batch updates every 5 seconds
|
||||
}
|
||||
|
||||
function removeUndefinedKey(): void{
|
||||
if(uptimeObject.has("undefined")){
|
||||
function removeUndefinedKey(): void {
|
||||
if (uptimeObject.has("undefined")) {
|
||||
uptimeObject.delete("undefined");
|
||||
saveUptimeObject();
|
||||
}
|
||||
|
@ -70,101 +70,89 @@ function removeUndefinedKey(): void{
|
|||
|
||||
removeUndefinedKey();
|
||||
|
||||
export async function observe(instances: Instance[]): Promise<void>{
|
||||
export async function observe(instances: Instance[]): Promise<void> {
|
||||
const activeInstances = new Set<string>();
|
||||
const instancePromises = instances.map(instance=>resolveInstance(instance, activeInstances)
|
||||
);
|
||||
const instancePromises = instances.map((instance) => resolveInstance(instance, activeInstances));
|
||||
await Promise.allSettled(instancePromises);
|
||||
updateInactiveInstances(activeInstances);
|
||||
}
|
||||
|
||||
async function resolveInstance(
|
||||
instance: Instance,
|
||||
activeInstances: Set<string>
|
||||
): Promise<void>{
|
||||
try{
|
||||
async function resolveInstance(instance: Instance, activeInstances: Set<string>): Promise<void> {
|
||||
try {
|
||||
calcStats(instance);
|
||||
const api = await getApiUrl(instance);
|
||||
if(!api){
|
||||
if (!api) {
|
||||
handleUnresolvedApi(instance);
|
||||
return;
|
||||
}
|
||||
activeInstances.add(instance.name);
|
||||
await checkHealth(instance, api);
|
||||
scheduleHealthCheck(instance, api);
|
||||
}catch(error){
|
||||
} catch (error) {
|
||||
console.error("Error resolving instance:", error);
|
||||
}
|
||||
}
|
||||
|
||||
async function getApiUrl(instance: Instance): Promise<string | null>{
|
||||
if(instance.urls){
|
||||
async function getApiUrl(instance: Instance): Promise<string | null> {
|
||||
if (instance.urls) {
|
||||
return instance.urls.api;
|
||||
}
|
||||
if(instance.url){
|
||||
if (instance.url) {
|
||||
const urls = await getApiUrls(instance.url);
|
||||
return urls ? urls.api : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function handleUnresolvedApi(instance: Instance): void{
|
||||
function handleUnresolvedApi(instance: Instance): void {
|
||||
setStatus(instance, false);
|
||||
console.warn(`${instance.name} does not resolve api URL`, instance);
|
||||
setTimeout(()=>resolveInstance(instance, new Set()), 1000 * 60 * 30);
|
||||
setTimeout(() => resolveInstance(instance, new Set()), 1000 * 60 * 30);
|
||||
}
|
||||
|
||||
function scheduleHealthCheck(instance: Instance, api: string): void{
|
||||
function scheduleHealthCheck(instance: Instance, api: string): void {
|
||||
const checkInterval = 1000 * 60 * 30;
|
||||
const initialDelay = Math.random() * 1000 * 60 * 10;
|
||||
setTimeout(()=>{
|
||||
setTimeout(() => {
|
||||
checkHealth(instance, api);
|
||||
setInterval(()=>checkHealth(instance, api), checkInterval);
|
||||
setInterval(() => checkHealth(instance, api), checkInterval);
|
||||
}, initialDelay);
|
||||
}
|
||||
|
||||
async function checkHealth(
|
||||
instance: Instance,
|
||||
api: string,
|
||||
tries = 0
|
||||
): Promise<void>{
|
||||
try{
|
||||
const response = await fetch(`${api}/ping`, { method: "HEAD" });
|
||||
async function checkHealth(instance: Instance, api: string, tries = 0): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(`${api}/ping`, {method: "HEAD"});
|
||||
console.log(`Checking health for ${instance.name}: ${response.status}`);
|
||||
if(response.ok || tries > 3){
|
||||
if (response.ok || tries > 3) {
|
||||
setStatus(instance, response.ok);
|
||||
}else{
|
||||
} else {
|
||||
retryHealthCheck(instance, api, tries);
|
||||
}
|
||||
}catch(error){
|
||||
} catch (error) {
|
||||
console.error(`Error checking health for ${instance.name}:`, error);
|
||||
if(tries > 3){
|
||||
if (tries > 3) {
|
||||
setStatus(instance, false);
|
||||
}else{
|
||||
} else {
|
||||
retryHealthCheck(instance, api, tries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function retryHealthCheck(
|
||||
instance: Instance,
|
||||
api: string,
|
||||
tries: number
|
||||
): void{
|
||||
setTimeout(()=>checkHealth(instance, api, tries + 1), 30000);
|
||||
function retryHealthCheck(instance: Instance, api: string, tries: number): void {
|
||||
setTimeout(() => checkHealth(instance, api, tries + 1), 30000);
|
||||
}
|
||||
|
||||
function updateInactiveInstances(activeInstances: Set<string>): void{
|
||||
for(const key of uptimeObject.keys()){
|
||||
if(!activeInstances.has(key)){
|
||||
function updateInactiveInstances(activeInstances: Set<string>): void {
|
||||
for (const key of uptimeObject.keys()) {
|
||||
if (!activeInstances.has(key)) {
|
||||
setStatus(key, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calcStats(instance: Instance): void{
|
||||
function calcStats(instance: Instance): void {
|
||||
const obj = uptimeObject.get(instance.name);
|
||||
if(!obj)return;
|
||||
if (!obj) return;
|
||||
|
||||
const now = Date.now();
|
||||
const day = now - 1000 * 60 * 60 * 24;
|
||||
|
@ -176,7 +164,7 @@ function calcStats(instance: Instance): void{
|
|||
let weektime = 0;
|
||||
let online = false;
|
||||
|
||||
for(let i = 0; i < obj.length; i++){
|
||||
for (let i = 0; i < obj.length; i++) {
|
||||
const entry = obj[i];
|
||||
online = entry.online;
|
||||
const stamp = entry.time;
|
||||
|
@ -186,11 +174,11 @@ function calcStats(instance: Instance): void{
|
|||
totalTimePassed += timePassed;
|
||||
alltime += Number(online) * timePassed;
|
||||
|
||||
if(stamp + timePassed > week){
|
||||
if (stamp + timePassed > week) {
|
||||
const weekTimePassed = Math.min(timePassed, nextStamp - week);
|
||||
weektime += Number(online) * weekTimePassed;
|
||||
|
||||
if(stamp + timePassed > day){
|
||||
if (stamp + timePassed > day) {
|
||||
const dayTimePassed = Math.min(weekTimePassed, nextStamp - day);
|
||||
daytime += Number(online) * dayTimePassed;
|
||||
}
|
||||
|
@ -198,13 +186,7 @@ function calcStats(instance: Instance): void{
|
|||
}
|
||||
|
||||
instance.online = online;
|
||||
instance.uptime = calculateUptimeStats(
|
||||
totalTimePassed,
|
||||
alltime,
|
||||
daytime,
|
||||
weektime,
|
||||
online
|
||||
);
|
||||
instance.uptime = calculateUptimeStats(totalTimePassed, alltime, daytime, weektime, online);
|
||||
}
|
||||
|
||||
function calculateUptimeStats(
|
||||
|
@ -212,46 +194,46 @@ function calculateUptimeStats(
|
|||
alltime: number,
|
||||
daytime: number,
|
||||
weektime: number,
|
||||
online: boolean
|
||||
): { daytime: number; weektime: number; alltime: number }{
|
||||
online: boolean,
|
||||
): {daytime: number; weektime: number; alltime: number} {
|
||||
const dayInMs = 1000 * 60 * 60 * 24;
|
||||
const weekInMs = dayInMs * 7;
|
||||
|
||||
alltime /= totalTimePassed;
|
||||
|
||||
if(totalTimePassed > dayInMs){
|
||||
if (totalTimePassed > dayInMs) {
|
||||
daytime = daytime || (online ? dayInMs : 0);
|
||||
daytime /= dayInMs;
|
||||
|
||||
if(totalTimePassed > weekInMs){
|
||||
if (totalTimePassed > weekInMs) {
|
||||
weektime = weektime || (online ? weekInMs : 0);
|
||||
weektime /= weekInMs;
|
||||
}else{
|
||||
} else {
|
||||
weektime = alltime;
|
||||
}
|
||||
}else{
|
||||
} else {
|
||||
weektime = alltime;
|
||||
daytime = alltime;
|
||||
}
|
||||
|
||||
return{ daytime, weektime, alltime };
|
||||
return {daytime, weektime, alltime};
|
||||
}
|
||||
|
||||
function setStatus(instance: string | Instance, status: boolean): void{
|
||||
function setStatus(instance: string | Instance, status: boolean): void {
|
||||
const name = typeof instance === "string" ? instance : instance.name;
|
||||
let obj = uptimeObject.get(name);
|
||||
|
||||
if(!obj){
|
||||
if (!obj) {
|
||||
obj = [];
|
||||
uptimeObject.set(name, obj);
|
||||
}
|
||||
|
||||
const lastEntry = obj.at(-1);
|
||||
if(!lastEntry || lastEntry.online !== status){
|
||||
obj.push({ time: Date.now(), online: status });
|
||||
if (!lastEntry || lastEntry.online !== status) {
|
||||
obj.push({time: Date.now(), online: status});
|
||||
saveUptimeObject();
|
||||
|
||||
if(typeof instance !== "string"){
|
||||
if (typeof instance !== "string") {
|
||||
calcStats(instance);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue