Works now pls test

This commit is contained in:
Scott Gould 2024-09-19 09:03:29 -04:00
parent 69c151162e
commit cc8b3ed638
No known key found for this signature in database
2 changed files with 450 additions and 446 deletions

View file

@ -8,59 +8,59 @@ const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename); const __dirname = path.dirname(__filename);
interface UptimeEntry { interface UptimeEntry {
time: number; time: number;
online: boolean; online: boolean;
} }
interface UptimeObject { interface UptimeObject {
[key: string]: UptimeEntry[]; [key: string]: UptimeEntry[];
} }
interface Instance { interface Instance {
name: string; name: string;
urls?: { api: string }; urls?: { api: string };
url?: string; url?: string;
online?: boolean; online?: boolean;
uptime?: { uptime?: {
daytime: number; daytime: number;
weektime: number; weektime: number;
alltime: number; alltime: number;
}; };
} }
let uptimeObject: UptimeObject = loadUptimeObject(); let uptimeObject: UptimeObject = loadUptimeObject();
export { uptimeObject as uptime }; export { uptimeObject as uptime };
function loadUptimeObject(): UptimeObject { function loadUptimeObject(): UptimeObject {
const filePath = path.join(__dirname, "..", "uptime.json"); const filePath = path.join(__dirname, "..", "uptime.json");
if (fs.existsSync(filePath)) { if (fs.existsSync(filePath)) {
try { try {
return JSON.parse(fs.readFileSync(filePath, "utf8")); return JSON.parse(fs.readFileSync(filePath, "utf8"));
} catch (error) { } catch (error) {
console.error("Error reading uptime.json:", error); console.error("Error reading uptime.json:", error);
return {}; return {};
} }
} }
return {}; return {};
} }
function saveUptimeObject(): void { function saveUptimeObject(): void {
fs.writeFile( fs.writeFile(
`${__dirname}/uptime.json`, path.join(__dirname, "..", "uptime.json"),
JSON.stringify(uptimeObject), JSON.stringify(uptimeObject),
(error) => { (error) => {
if (error) { if (error) {
console.error("Error saving uptime.json:", error); console.error("Error saving uptime.json:", error);
} }
} }
); );
} }
function removeUndefinedKey(): void { function removeUndefinedKey(): void {
if (uptimeObject.undefined) { if (uptimeObject.undefined) {
delete uptimeObject.undefined; delete uptimeObject.undefined;
saveUptimeObject(); saveUptimeObject();
} }
} }
removeUndefinedKey(); removeUndefinedKey();
@ -72,12 +72,12 @@ export async function observe(instances: Instance[]): Promise<void> {
); );
await Promise.allSettled(instancePromises); await Promise.allSettled(instancePromises);
updateInactiveInstances(activeInstances); updateInactiveInstances(activeInstances);
} }
async function resolveInstance( async function resolveInstance(
instance: Instance, instance: Instance,
activeInstances: Set<string> activeInstances: Set<string>
): Promise<void> { ): Promise<void> {
try { try {
calcStats(instance); calcStats(instance);
const api = await getApiUrl(instance); const api = await getApiUrl(instance);
@ -86,13 +86,14 @@ export async function observe(instances: Instance[]): Promise<void> {
return; return;
} }
activeInstances.add(instance.name); activeInstances.add(instance.name);
await checkHealth(instance, api); // Ensure health is checked immediately
scheduleHealthCheck(instance, api); scheduleHealthCheck(instance, api);
} catch (error) { } catch (error) {
console.error("Error resolving instance:", 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) { if (instance.urls) {
return instance.urls.api; return instance.urls.api;
} }
@ -101,62 +102,64 @@ export async function observe(instances: Instance[]): Promise<void> {
return urls ? urls.api : null; return urls ? urls.api : null;
} }
return null; return null;
} }
function handleUnresolvedApi(instance: Instance): void { function handleUnresolvedApi(instance: Instance): void {
setStatus(instance, false); setStatus(instance, false);
console.warn(`${instance.name} does not resolve api URL`, instance); 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 checkInterval = 1000 * 60 * 30;
const initialDelay = Math.random() * 1000 * 60 * 10; const initialDelay = Math.random() * 1000 * 60 * 10;
setTimeout(() => { setTimeout(() => {
checkHealth(instance, api); checkHealth(instance, api);
setInterval(() => checkHealth(instance, api), checkInterval); setInterval(() => checkHealth(instance, api), checkInterval);
}, initialDelay); }, initialDelay);
} }
async function checkHealth( async function checkHealth(
instance: Instance, instance: Instance,
api: string, api: string,
tries = 0 tries = 0
): Promise<void> { ): Promise<void> {
try { 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) { if (response.ok || tries > 3) {
console.log(`Setting status for ${instance.name} to ${response.ok}`);
setStatus(instance, response.ok); setStatus(instance, response.ok);
} else { } else {
retryHealthCheck(instance, api, tries); retryHealthCheck(instance, api, tries);
} }
} catch (error) { } catch (error) {
console.error("Error checking health:", error); console.error(`Error checking health for ${instance.name}:`, error);
if (tries > 3) { if (tries > 3) {
setStatus(instance, false); setStatus(instance, false);
} else { } else {
retryHealthCheck(instance, api, tries); retryHealthCheck(instance, api, tries);
} }
} }
} }
function retryHealthCheck( function retryHealthCheck(
instance: Instance, instance: Instance,
api: string, api: string,
tries: number tries: number
): void { ): void {
setTimeout(() => checkHealth(instance, api, tries + 1), 30000); 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)) { for (const key of Object.keys(uptimeObject)) {
if (!activeInstances.has(key)) { if (!activeInstances.has(key)) {
setStatus(key, false); setStatus(key, false);
} }
} }
} }
function calcStats(instance: Instance): void { function calcStats(instance: Instance): void {
const obj = uptimeObject[instance.name]; const obj = uptimeObject[instance.name];
if (!obj) return; if (!obj) return;
@ -199,15 +202,15 @@ export async function observe(instances: Instance[]): Promise<void> {
weektime, weektime,
online online
); );
} }
function calculateUptimeStats( function calculateUptimeStats(
totalTimePassed: number, totalTimePassed: number,
alltime: number, alltime: number,
daytime: number, daytime: number,
weektime: number, weektime: number,
online: boolean online: boolean
): { daytime: number; weektime: number; alltime: number } { ): { daytime: number; weektime: number; alltime: number } {
const dayInMs = 1000 * 60 * 60 * 24; const dayInMs = 1000 * 60 * 60 * 24;
const weekInMs = dayInMs * 7; const weekInMs = dayInMs * 7;
@ -229,9 +232,9 @@ export async function observe(instances: Instance[]): Promise<void> {
} }
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; const name = typeof instance === "string" ? instance : instance.name;
let obj = uptimeObject[name]; let obj = uptimeObject[name];
@ -240,12 +243,13 @@ export async function observe(instances: Instance[]): Promise<void> {
uptimeObject[name] = obj; 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 }); obj.push({ time: Date.now(), online: status });
saveUptimeObject(); saveUptimeObject();
}
if (typeof instance !== "string") { if (typeof instance !== "string") {
calcStats(instance); calcStats(instance);
} }
} }
}

View file

@ -3,133 +3,133 @@ import { Guild } from "./guild.js";
import { Localuser } from "./localuser.js"; import { Localuser } from "./localuser.js";
class Emoji { class Emoji {
static emojis: { static emojis: {
name: string; name: string;
emojis: { emojis: {
name: string; name: string;
emoji: string; emoji: string;
}[]; }[];
}[]; }[];
name: string; name: string;
id: string; id: string;
animated: boolean; animated: boolean;
owner: Guild | Localuser; owner: Guild | Localuser;
get guild() { get guild() {
if (this.owner instanceof Guild) { if (this.owner instanceof Guild) {
return this.owner; return this.owner;
} }
return; return;
} }
get localuser() { get localuser() {
if (this.owner instanceof Guild) { if (this.owner instanceof Guild) {
return this.owner.localuser; return this.owner.localuser;
} else { } else {
return this.owner; return this.owner;
} }
} }
get info() { get info() {
return this.owner.info; return this.owner.info;
} }
constructor( constructor(
json: { name: string; id: string; animated: boolean }, json: { name: string; id: string; animated: boolean },
owner: Guild | Localuser owner: Guild | Localuser
) { ) {
this.name = json.name; this.name = json.name;
this.id = json.id; this.id = json.id;
this.animated = json.animated; this.animated = json.animated;
this.owner = owner; this.owner = owner;
} }
getHTML(bigemoji: boolean = false) { getHTML(bigemoji: boolean = false) {
const emojiElem = document.createElement("img"); const emojiElem = document.createElement("img");
emojiElem.classList.add("md-emoji"); emojiElem.classList.add("md-emoji");
emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji"); emojiElem.classList.add(bigemoji ? "bigemoji" : "smallemoji");
emojiElem.crossOrigin = "anonymous"; emojiElem.crossOrigin = "anonymous";
emojiElem.src = emojiElem.src =
this.info.cdn + this.info.cdn +
"/emojis/" + "/emojis/" +
this.id + this.id +
"." + "." +
(this.animated ? "gif" : "png") + (this.animated ? "gif" : "png") +
"?size=32"; "?size=32";
emojiElem.alt = this.name; emojiElem.alt = this.name;
emojiElem.loading = "lazy"; emojiElem.loading = "lazy";
return emojiElem; return emojiElem;
} }
static decodeEmojiList(buffer: ArrayBuffer) { static decodeEmojiList(buffer: ArrayBuffer) {
const view = new DataView(buffer, 0); const view = new DataView(buffer, 0);
let i = 0; let i = 0;
function read16() { function read16() {
const int = view.getUint16(i); const int = view.getUint16(i);
i += 2; i += 2;
return int; return int;
} }
function read8() { function read8() {
const int = view.getUint8(i); const int = view.getUint8(i);
i += 1; i += 1;
return int; return int;
} }
function readString8() { function readString8() {
return readStringNo(read8()); return readStringNo(read8());
} }
function readString16() { function readString16() {
return readStringNo(read16()); return readStringNo(read16());
} }
function readStringNo(length: number) { function readStringNo(length: number) {
const array = new Uint8Array(length); const array = new Uint8Array(length);
for (let i = 0; i < length; i++) { for (let i = 0; i < length; i++) {
array[i] = read8(); array[i] = read8();
} }
//console.log(array); //console.log(array);
return new TextDecoder("utf-8").decode(array.buffer); return new TextDecoder("utf-8").decode(array.buffer);
} }
const build: { name: string; emojis: { name: string; emoji: string }[] }[] = const build: { name: string; emojis: { name: string; emoji: string }[] }[] =
[]; [];
let cats = read16(); let cats = read16();
for (; cats !== 0; cats--) { for (; cats !== 0; cats--) {
const name = readString16(); const name = readString16();
const emojis: { const emojis: {
name: string; name: string;
skin_tone_support: boolean; skin_tone_support: boolean;
emoji: string; emoji: string;
}[] = []; }[] = [];
let emojinumber = read16(); let emojinumber = read16();
for (; emojinumber !== 0; emojinumber--) { for (; emojinumber !== 0; emojinumber--) {
//console.log(emojis); //console.log(emojis);
const name = readString8(); const name = readString8();
const len = read8(); const len = read8();
const skin_tone_support = len > 127; const skin_tone_support = len > 127;
const emoji = readStringNo(len - Number(skin_tone_support) * 128); const emoji = readStringNo(len - Number(skin_tone_support) * 128);
emojis.push({ emojis.push({
name, name,
skin_tone_support, skin_tone_support,
emoji, emoji,
}); });
} }
build.push({ build.push({
name, name,
emojis, emojis,
}); });
} }
this.emojis = build; this.emojis = build;
console.log(build); console.log(build);
} }
static grabEmoji() { static grabEmoji() {
fetch("/emoji.bin") fetch("/emoji.bin")
.then((e) => { .then((e) => {
return e.arrayBuffer(); return e.arrayBuffer();
}) })
.then((e) => { .then((e) => {
Emoji.decodeEmojiList(e); Emoji.decodeEmojiList(e);
}); });
} }
static async emojiPicker( static async emojiPicker(
x: number, x: number,
y: number, y: number,
localuser: Localuser localuser: Localuser
): Promise<Emoji | string> { ): Promise<Emoji | string> {
let res: (r: Emoji | string) => void; let res: (r: Emoji | string) => void;
const promise: Promise<Emoji | string> = new Promise((r) => { const promise: Promise<Emoji | string> = new Promise((r) => {
res = r; res = r;
@ -254,6 +254,6 @@ localuser: Localuser
menu.append(body); menu.append(body);
return promise; return promise;
} }
} }
Emoji.grabEmoji(); Emoji.grabEmoji();
export { Emoji }; export { Emoji };