add website tracking
All checks were successful
deploy / deploy (push) Successful in 22s
Publish Docker Image / docker (push) Successful in 46s

This commit is contained in:
Lee 2024-01-04 00:57:21 +00:00
parent 358bb6272c
commit ff11240334
7 changed files with 195 additions and 3 deletions

14
data/websites.json Normal file
View File

@ -0,0 +1,14 @@
[
{
"name": "Minecraft.net",
"url": "https://minecraft.net"
},
{
"name": "Minecraft Textures",
"url": "https://textures.minecraft.net"
},
{
"name": "Minecraft Session Server",
"url": "https://session.minecraft.net"
}
]

View File

@ -14,7 +14,9 @@
"dependencies": {
"@influxdata/influxdb-client": "^1.33.2",
"@types/mcping-js": "^1.5.4",
"@types/node": "^20.10.6",
"@types/node-cron": "^3.0.11",
"axios": "^1.6.4",
"dns": "^0.2.2",
"mcpe-ping-fixed": "^0.0.3",
"mcping-js": "^1.5.0",
@ -22,7 +24,6 @@
"ts-node": "^10.9.2",
"tsup": "^8.0.1",
"typescript": "^5.3.3",
"winston": "^3.11.0",
"@types/node": "^20.10.6"
"winston": "^3.11.0"
}
}

64
pnpm-lock.yaml generated
View File

@ -17,6 +17,9 @@ dependencies:
'@types/node-cron':
specifier: ^3.0.11
version: 3.0.11
axios:
specifier: ^1.6.4
version: 1.6.4
dns:
specifier: ^0.2.2
version: 0.2.2
@ -570,10 +573,24 @@ packages:
resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==}
dev: false
/asynckit@0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/aws-sign@0.2.0:
resolution: {integrity: sha512-6P7/Ls5F6++DsKu7iacris7qq/AZSWaX+gT4dtSyUxM82ePxWxaP7Slo82ZO3ZTx6GSKxQHAQlmFvM8e+Dd8ZA==}
dev: false
/axios@1.6.4:
resolution: {integrity: sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==}
dependencies:
follow-redirects: 1.15.4
form-data: 4.0.0
proxy-from-env: 1.1.0
transitivePeerDependencies:
- debug
dev: false
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: false
@ -762,6 +779,13 @@ packages:
delayed-stream: 0.0.5
dev: false
/combined-stream@1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: false
/commander@0.6.1:
resolution: {integrity: sha512-0fLycpl1UMTGX257hRsu/arL/cUbcvQM4zMKwvLvzXtfdezIV4yotPS2dYtknF+NmEfWSoCEF6+hj9XLm/6hEw==}
engines: {node: '>= 0.4.x'}
@ -900,6 +924,11 @@ packages:
engines: {node: '>=0.4.0'}
dev: false
/delayed-stream@1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dev: false
/depd@0.3.0:
resolution: {integrity: sha512-Uyx3FgdvEYlpA3W4lf37Ide++2qOsjLlJ7dap0tbM63j/BxTCcxmyIOO6PXbKbOuNSko+fsDHzzx1DUeo1+3fA==}
engines: {node: '>= 0.8.0'}
@ -1158,6 +1187,16 @@ packages:
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
dev: false
/follow-redirects@1.15.4:
resolution: {integrity: sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
dev: false
/foreground-child@3.1.1:
resolution: {integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==}
engines: {node: '>=14'}
@ -1179,6 +1218,15 @@ packages:
mime: 1.2.11
dev: false
/form-data@4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: false
/fresh@0.2.2:
resolution: {integrity: sha512-ZGGi8GROK//ijm2gB33sUuN9TjN1tC/dvG4Bt4j6IWrVGpMmudUBCxx+Ir7qePsdREfkpQC4FL8W0jeSOsgv1w==}
dev: false
@ -1455,11 +1503,23 @@ packages:
picomatch: 2.3.1
dev: false
/mime-db@1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
dev: false
/mime-types@1.0.2:
resolution: {integrity: sha512-echfutj/t5SoTL4WZpqjA1DCud1XO0WQF3/GJ48YBmc4ZMhCK77QA6Z/w6VTQERLKuJ4drze3kw2TUT8xZXVNw==}
engines: {node: '>= 0.8.0'}
dev: false
/mime-types@2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: false
/mime@1.2.11:
resolution: {integrity: sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==}
dev: false
@ -1713,6 +1773,10 @@ packages:
ipaddr.js: 0.1.2
dev: false
/proxy-from-env@1.1.0:
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
dev: false
/punycode@2.3.1:
resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==}
engines: {node: '>=6'}

View File

@ -1,5 +1,6 @@
import Influx from "./influx/influx";
import ServerManager from "./server/serverManager";
import WebsiteManager from "./website/websiteManager";
/**
* The influx database instance.
@ -7,3 +8,4 @@ import ServerManager from "./server/serverManager";
export const influx = new Influx();
new ServerManager();
new WebsiteManager();

View File

@ -41,7 +41,7 @@ export default class ServerManager {
// ping all servers in parallel
await Promise.all(this.servers.map((server) => server.pingServer()));
logger.info("Finished pinging servers");
logger.info("Finished pinging servers!");
}
/**

64
src/website/website.ts Normal file
View File

@ -0,0 +1,64 @@
import { Point } from "@influxdata/influxdb-client";
import axios from "axios";
import { influx } from "..";
import { logger } from "../utils/logger";
import Config from "../../data/config.json";
type WebsiteOptions = {
name: string;
url: string;
};
export default class Website {
/**
* The name of the website.
*/
private name: string;
/**
* The url of the website.
*/
private url: string;
constructor({ name, url }: WebsiteOptions) {
this.name = name;
this.url = url;
}
/**
* Pings a website and gets the response.
*
* @returns the response
*/
public async pingWebsite(): Promise<void> {
try {
const before = Date.now();
const response = await axios.get(this.url, {
validateStatus: () => true, // Don't throw a error on non-200 status codes
timeout: Config.pinger.timeout,
});
if (response.status === 500) {
throw new Error("Server returned 500 status code");
}
const responseTime = Date.now() - before;
influx.writePoint(
new Point("websiteStatus")
.tag("name", this.name)
.booleanField("online", true)
.intField("responseTime", responseTime)
.timestamp(Date.now())
);
} catch (err) {
logger.error(`Failed to ping ${this.name}:`, err);
influx.writePoint(
new Point("websiteStatus")
.tag("name", this.name)
.booleanField("online", false)
.timestamp(Date.now())
);
}
}
}

View File

@ -0,0 +1,47 @@
import cron from "node-cron";
import { logger } from "../utils/logger";
import Config from "../../data/config.json";
import Websites from "../../data/websites.json";
import Website from "./website";
export default class WebsiteManager {
private websites: Website[] = [];
constructor() {
logger.info("Loading websites...");
for (const configWebsite of Websites) {
const website = new Website({
name: configWebsite.name,
url: configWebsite.url,
});
this.websites.push(website);
}
logger.info(`Loaded ${this.websites.length} websites!`);
cron.schedule(Config.pinger.pingCron, () => {
this.pingWebsites();
});
}
/**
* Ping all websites to update their status.
*/
private async pingWebsites(): Promise<void> {
logger.info(`Pinging websites ${this.websites.length}`);
// ping all websites in parallel
await Promise.all(this.websites.map((website) => website.pingWebsite()));
logger.info("Finished pinging websites!");
}
/**
* Returns the websites.
*
* @returns the websites
*/
public getWebsites(): Website[] {
return this.websites;
}
}