Works now pls test
This commit is contained in:
parent
69c151162e
commit
cc8b3ed638
2 changed files with 450 additions and 446 deletions
130
src/stats.ts
130
src/stats.ts
|
@ -8,59 +8,59 @@ const __filename = fileURLToPath(import.meta.url);
|
|||
const __dirname = path.dirname(__filename);
|
||||
|
||||
interface UptimeEntry {
|
||||
time: number;
|
||||
online: boolean;
|
||||
time: number;
|
||||
online: boolean;
|
||||
}
|
||||
|
||||
interface UptimeObject {
|
||||
[key: string]: UptimeEntry[];
|
||||
[key: string]: UptimeEntry[];
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
}
|
||||
|
||||
let uptimeObject: UptimeObject = loadUptimeObject();
|
||||
export { uptimeObject as uptime };
|
||||
|
||||
function loadUptimeObject(): UptimeObject {
|
||||
const filePath = path.join(__dirname, "..", "uptime.json");
|
||||
if (fs.existsSync(filePath)) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
||||
} catch (error) {
|
||||
console.error("Error reading uptime.json:", error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
const filePath = path.join(__dirname, "..", "uptime.json");
|
||||
if (fs.existsSync(filePath)) {
|
||||
try {
|
||||
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
||||
} catch (error) {
|
||||
console.error("Error reading uptime.json:", error);
|
||||
return {};
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
function saveUptimeObject(): void {
|
||||
fs.writeFile(
|
||||
`${__dirname}/uptime.json`,
|
||||
JSON.stringify(uptimeObject),
|
||||
(error) => {
|
||||
if (error) {
|
||||
console.error("Error saving uptime.json:", error);
|
||||
}
|
||||
}
|
||||
);
|
||||
fs.writeFile(
|
||||
path.join(__dirname, "..", "uptime.json"),
|
||||
JSON.stringify(uptimeObject),
|
||||
(error) => {
|
||||
if (error) {
|
||||
console.error("Error saving uptime.json:", error);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function removeUndefinedKey(): void {
|
||||
if (uptimeObject.undefined) {
|
||||
delete uptimeObject.undefined;
|
||||
saveUptimeObject();
|
||||
}
|
||||
if (uptimeObject.undefined) {
|
||||
delete uptimeObject.undefined;
|
||||
saveUptimeObject();
|
||||
}
|
||||
}
|
||||
|
||||
removeUndefinedKey();
|
||||
|
@ -72,12 +72,12 @@ export async function observe(instances: Instance[]): Promise<void> {
|
|||
);
|
||||
await Promise.allSettled(instancePromises);
|
||||
updateInactiveInstances(activeInstances);
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveInstance(
|
||||
async function resolveInstance(
|
||||
instance: Instance,
|
||||
activeInstances: Set<string>
|
||||
): Promise<void> {
|
||||
): Promise<void> {
|
||||
try {
|
||||
calcStats(instance);
|
||||
const api = await getApiUrl(instance);
|
||||
|
@ -86,13 +86,14 @@ export async function observe(instances: Instance[]): Promise<void> {
|
|||
return;
|
||||
}
|
||||
activeInstances.add(instance.name);
|
||||
await checkHealth(instance, api); // Ensure health is checked immediately
|
||||
scheduleHealthCheck(instance, api);
|
||||
} catch (error) {
|
||||
console.error("Error resolving instance:", error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getApiUrl(instance: Instance): Promise<string | null> {
|
||||
async function getApiUrl(instance: Instance): Promise<string | null> {
|
||||
if (instance.urls) {
|
||||
return instance.urls.api;
|
||||
}
|
||||
|
@ -101,62 +102,64 @@ export async function observe(instances: Instance[]): Promise<void> {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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(() => {
|
||||
checkHealth(instance, api);
|
||||
setInterval(() => checkHealth(instance, api), checkInterval);
|
||||
}, initialDelay);
|
||||
}
|
||||
}
|
||||
|
||||
async function checkHealth(
|
||||
async function checkHealth(
|
||||
instance: Instance,
|
||||
api: string,
|
||||
tries = 0
|
||||
): Promise<void> {
|
||||
): Promise<void> {
|
||||
try {
|
||||
const response = await fetch(`${api}ping`, { method: "HEAD" });
|
||||
const response = await fetch(`${api}/ping`, { method: "HEAD" });
|
||||
console.log(`Checking health for ${instance.name}: ${response.status}`);
|
||||
if (response.ok || tries > 3) {
|
||||
console.log(`Setting status for ${instance.name} to ${response.ok}`);
|
||||
setStatus(instance, response.ok);
|
||||
} else {
|
||||
retryHealthCheck(instance, api, tries);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error checking health:", error);
|
||||
console.error(`Error checking health for ${instance.name}:`, error);
|
||||
if (tries > 3) {
|
||||
setStatus(instance, false);
|
||||
} else {
|
||||
retryHealthCheck(instance, api, tries);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function retryHealthCheck(
|
||||
function retryHealthCheck(
|
||||
instance: Instance,
|
||||
api: string,
|
||||
tries: number
|
||||
): void {
|
||||
): void {
|
||||
setTimeout(() => checkHealth(instance, api, tries + 1), 30000);
|
||||
}
|
||||
}
|
||||
|
||||
function updateInactiveInstances(activeInstances: Set<string>): void {
|
||||
function updateInactiveInstances(activeInstances: Set<string>): void {
|
||||
for (const key of Object.keys(uptimeObject)) {
|
||||
if (!activeInstances.has(key)) {
|
||||
setStatus(key, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function calcStats(instance: Instance): void {
|
||||
function calcStats(instance: Instance): void {
|
||||
const obj = uptimeObject[instance.name];
|
||||
if (!obj) return;
|
||||
|
||||
|
@ -199,15 +202,15 @@ export async function observe(instances: Instance[]): Promise<void> {
|
|||
weektime,
|
||||
online
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function calculateUptimeStats(
|
||||
function calculateUptimeStats(
|
||||
totalTimePassed: number,
|
||||
alltime: number,
|
||||
daytime: number,
|
||||
weektime: number,
|
||||
online: boolean
|
||||
): { daytime: number; weektime: number; alltime: number } {
|
||||
): { daytime: number; weektime: number; alltime: number } {
|
||||
const dayInMs = 1000 * 60 * 60 * 24;
|
||||
const weekInMs = dayInMs * 7;
|
||||
|
||||
|
@ -229,9 +232,9 @@ export async function observe(instances: Instance[]): Promise<void> {
|
|||
}
|
||||
|
||||
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[name];
|
||||
|
||||
|
@ -240,12 +243,13 @@ export async function observe(instances: Instance[]): Promise<void> {
|
|||
uptimeObject[name] = obj;
|
||||
}
|
||||
|
||||
if (obj.at(-1)?.online !== status) {
|
||||
const lastEntry = obj.at(-1);
|
||||
if (!lastEntry || lastEntry.online !== status) {
|
||||
obj.push({ time: Date.now(), online: status });
|
||||
saveUptimeObject();
|
||||
}
|
||||
|
||||
if (typeof instance !== "string") {
|
||||
calcStats(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,133 +3,133 @@ import { Guild } from "./guild.js";
|
|||
import { Localuser } from "./localuser.js";
|
||||
|
||||
class Emoji {
|
||||
static emojis: {
|
||||
name: string;
|
||||
emojis: {
|
||||
name: string;
|
||||
emoji: string;
|
||||
}[];
|
||||
}[];
|
||||
name: string;
|
||||
id: string;
|
||||
animated: boolean;
|
||||
owner: Guild | Localuser;
|
||||
get guild() {
|
||||
if (this.owner instanceof Guild) {
|
||||
return this.owner;
|
||||
}
|
||||
return;
|
||||
}
|
||||
get localuser() {
|
||||
if (this.owner instanceof Guild) {
|
||||
return this.owner.localuser;
|
||||
} else {
|
||||
return this.owner;
|
||||
}
|
||||
}
|
||||
get info() {
|
||||
return this.owner.info;
|
||||
}
|
||||
constructor(
|
||||
json: { name: string; id: string; animated: boolean },
|
||||
owner: Guild | Localuser
|
||||
) {
|
||||
this.name = json.name;
|
||||
this.id = json.id;
|
||||
this.animated = json.animated;
|
||||
this.owner = owner;
|
||||
}
|
||||
getHTML(bigemoji: boolean = false) {
|
||||
const emojiElem = document.createElement("img");
|
||||
emojiElem.classList.add("md-emoji");
|
||||
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
|
||||
emojiElem.crossOrigin = "anonymous";
|
||||
emojiElem.src =
|
||||
this.info.cdn +
|
||||
"/emojis/" +
|
||||
this.id +
|
||||
"." +
|
||||
(this.animated ? "gif" : "png") +
|
||||
"?size=32";
|
||||
static emojis: {
|
||||
name: string;
|
||||
emojis: {
|
||||
name: string;
|
||||
emoji: string;
|
||||
}[];
|
||||
}[];
|
||||
name: string;
|
||||
id: string;
|
||||
animated: boolean;
|
||||
owner: Guild | Localuser;
|
||||
get guild() {
|
||||
if (this.owner instanceof Guild) {
|
||||
return this.owner;
|
||||
}
|
||||
return;
|
||||
}
|
||||
get localuser() {
|
||||
if (this.owner instanceof Guild) {
|
||||
return this.owner.localuser;
|
||||
} else {
|
||||
return this.owner;
|
||||
}
|
||||
}
|
||||
get info() {
|
||||
return this.owner.info;
|
||||
}
|
||||
constructor(
|
||||
json: { name: string; id: string; animated: boolean },
|
||||
owner: Guild | Localuser
|
||||
) {
|
||||
this.name = json.name;
|
||||
this.id = json.id;
|
||||
this.animated = json.animated;
|
||||
this.owner = owner;
|
||||
}
|
||||
getHTML(bigemoji: boolean = false) {
|
||||
const emojiElem = document.createElement("img");
|
||||
emojiElem.classList.add("md-emoji");
|
||||
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
|
||||
emojiElem.crossOrigin = "anonymous";
|
||||
emojiElem.src =
|
||||
this.info.cdn +
|
||||
"/emojis/" +
|
||||
this.id +
|
||||
"." +
|
||||
(this.animated ? "gif" : "png") +
|
||||
"?size=32";
|
||||
|
||||
emojiElem.alt = this.name;
|
||||
emojiElem.loading = "lazy";
|
||||
return emojiElem;
|
||||
}
|
||||
static decodeEmojiList(buffer: ArrayBuffer) {
|
||||
const view = new DataView(buffer, 0);
|
||||
let i = 0;
|
||||
function read16() {
|
||||
const int = view.getUint16(i);
|
||||
i += 2;
|
||||
return int;
|
||||
}
|
||||
function read8() {
|
||||
const int = view.getUint8(i);
|
||||
i += 1;
|
||||
return int;
|
||||
}
|
||||
function readString8() {
|
||||
return readStringNo(read8());
|
||||
}
|
||||
function readString16() {
|
||||
return readStringNo(read16());
|
||||
}
|
||||
function readStringNo(length: number) {
|
||||
const array = new Uint8Array(length);
|
||||
emojiElem.alt = this.name;
|
||||
emojiElem.loading = "lazy";
|
||||
return emojiElem;
|
||||
}
|
||||
static decodeEmojiList(buffer: ArrayBuffer) {
|
||||
const view = new DataView(buffer, 0);
|
||||
let i = 0;
|
||||
function read16() {
|
||||
const int = view.getUint16(i);
|
||||
i += 2;
|
||||
return int;
|
||||
}
|
||||
function read8() {
|
||||
const int = view.getUint8(i);
|
||||
i += 1;
|
||||
return int;
|
||||
}
|
||||
function readString8() {
|
||||
return readStringNo(read8());
|
||||
}
|
||||
function readString16() {
|
||||
return readStringNo(read16());
|
||||
}
|
||||
function readStringNo(length: number) {
|
||||
const array = new Uint8Array(length);
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
array[i] = read8();
|
||||
}
|
||||
//console.log(array);
|
||||
return new TextDecoder("utf-8").decode(array.buffer);
|
||||
}
|
||||
const build: { name: string; emojis: { name: string; emoji: string }[] }[] =
|
||||
[];
|
||||
let cats = read16();
|
||||
for (let i = 0; i < length; i++) {
|
||||
array[i] = read8();
|
||||
}
|
||||
//console.log(array);
|
||||
return new TextDecoder("utf-8").decode(array.buffer);
|
||||
}
|
||||
const build: { name: string; emojis: { name: string; emoji: string }[] }[] =
|
||||
[];
|
||||
let cats = read16();
|
||||
|
||||
for (; cats !== 0; cats--) {
|
||||
const name = readString16();
|
||||
const emojis: {
|
||||
name: string;
|
||||
skin_tone_support: boolean;
|
||||
emoji: string;
|
||||
}[] = [];
|
||||
let emojinumber = read16();
|
||||
for (; emojinumber !== 0; emojinumber--) {
|
||||
//console.log(emojis);
|
||||
const name = readString8();
|
||||
const len = read8();
|
||||
const skin_tone_support = len > 127;
|
||||
const emoji = readStringNo(len - Number(skin_tone_support) * 128);
|
||||
emojis.push({
|
||||
name,
|
||||
skin_tone_support,
|
||||
emoji,
|
||||
});
|
||||
}
|
||||
build.push({
|
||||
name,
|
||||
emojis,
|
||||
});
|
||||
}
|
||||
this.emojis = build;
|
||||
console.log(build);
|
||||
}
|
||||
static grabEmoji() {
|
||||
fetch("/emoji.bin")
|
||||
.then((e) => {
|
||||
return e.arrayBuffer();
|
||||
})
|
||||
.then((e) => {
|
||||
Emoji.decodeEmojiList(e);
|
||||
});
|
||||
}
|
||||
static async emojiPicker(
|
||||
x: number,
|
||||
y: number,
|
||||
localuser: Localuser
|
||||
): Promise<Emoji | string> {
|
||||
for (; cats !== 0; cats--) {
|
||||
const name = readString16();
|
||||
const emojis: {
|
||||
name: string;
|
||||
skin_tone_support: boolean;
|
||||
emoji: string;
|
||||
}[] = [];
|
||||
let emojinumber = read16();
|
||||
for (; emojinumber !== 0; emojinumber--) {
|
||||
//console.log(emojis);
|
||||
const name = readString8();
|
||||
const len = read8();
|
||||
const skin_tone_support = len > 127;
|
||||
const emoji = readStringNo(len - Number(skin_tone_support) * 128);
|
||||
emojis.push({
|
||||
name,
|
||||
skin_tone_support,
|
||||
emoji,
|
||||
});
|
||||
}
|
||||
build.push({
|
||||
name,
|
||||
emojis,
|
||||
});
|
||||
}
|
||||
this.emojis = build;
|
||||
console.log(build);
|
||||
}
|
||||
static grabEmoji() {
|
||||
fetch("/emoji.bin")
|
||||
.then((e) => {
|
||||
return e.arrayBuffer();
|
||||
})
|
||||
.then((e) => {
|
||||
Emoji.decodeEmojiList(e);
|
||||
});
|
||||
}
|
||||
static async emojiPicker(
|
||||
x: number,
|
||||
y: number,
|
||||
localuser: Localuser
|
||||
): Promise<Emoji | string> {
|
||||
let res: (r: Emoji | string) => void;
|
||||
const promise: Promise<Emoji | string> = new Promise((r) => {
|
||||
res = r;
|
||||
|
@ -254,6 +254,6 @@ localuser: Localuser
|
|||
menu.append(body);
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
Emoji.grabEmoji();
|
||||
export { Emoji };
|
||||
}
|
||||
Emoji.grabEmoji();
|
||||
export { Emoji };
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue