This commit is contained in:
Gleb Koval 2021-07-04 14:12:12 +01:00
parent 0e5c664250
commit af2c334e66
No known key found for this signature in database
GPG Key ID: 120F2F6DA9D995FB
5 changed files with 210 additions and 4 deletions

View File

@ -30,3 +30,92 @@ export async function getAPIKeyInformation(key: string): Promise<
_response: response
};
}
/**
* Get Skyblock profiles by player
* @param key API key
* @param player The player's UUID
* @returns A response with the player's profiles
*/
export async function getProfilesByPlayer(
key: string,
player: string
): Promise<
HypixelResponse<{
profiles?: {
profile_id: string;
members: any;
community_upgrades: any | null;
cute_name: string;
banking: any | null;
game_mode: string | null;
}[];
}>
> {
let response = await request(
`/skyblock/profiles?uuid=${player}`,
authorize(key)
);
return {
...(await response.json()),
_response: response
};
}
/**
* Get Skyblock profile by its UUID
* @param key API key
* @param profile The profile's UUID
* @returns A response with the profile data
*/
export async function getProfileByUUID(
key: string,
profile: string
): Promise<
HypixelResponse<{
profile?: {
profile_id: string;
members: any;
community_upgrades: any | null;
cute_name: string;
banking: any | null;
game_mode: string | null;
};
}>
> {
let response = await request(
`/skyblock/profile?profile=${profile}`,
authorize(key)
);
return {
...(await response.json()),
_response: response
};
}
/**
* Get a player's current online status
* @param key API key
* @param player Player to get status of
* @returns A response with player status data
*/
export async function getOnlineStatus(
key: string,
player: string
): Promise<
HypixelResponse<{
uuid?: string;
session?: {
online: boolean;
gameType: string;
mode: string;
map: string;
};
}>
> {
let response = await request(`/status?uuid=${player}`, authorize(key));
return {
...(await response.json()),
_response: response
};
}

17
src/lib/permissions.ts Normal file
View File

@ -0,0 +1,17 @@
export enum Permissions {
ALL = "*"
}
/**
* Check permissions
* @param required The permission required
* @param has The permissions to check against
* @returns Whether the required permissions are fulfilled
*/
export function checkPermissions(required: string[], has: string[]): boolean {
if (has.includes("*")) return true;
return !required.some(req => {
if (!has.includes(req)) return true;
});
}

View File

@ -1,5 +1,3 @@
import { join } from "path";
/**
* Get a fetch function
* @returns A fetch function
@ -11,6 +9,12 @@ export function getFetch(): typeof fetch {
return fetch;
}
/**
* Create a fetch-like function with defaults
* @param baseURL Base URL of all requests
* @param defaultInit Default RequestInit options
* @returns A fetch-like function
*/
export function requestWithDefaults(
baseURL: string,
defaultInit?: RequestInit
@ -20,7 +24,7 @@ export function requestWithDefaults(
overrideInit?: RequestInit
): Promise<Response> {
let response = await getFetch()(
join(baseURL, endpoint),
new URL(endpoint, baseURL).href,
defaultInit ? deepMerge(defaultInit, overrideInit) : overrideInit
);
if (response.ok) {

16
src/logger.ts Normal file
View File

@ -0,0 +1,16 @@
import { getOnlineStatus, getProfileByUUID } from "./lib/hypixel";
export async function log(key: string, profile: string) {
let r = await getProfileByUUID(key, profile);
if (!r.success || !r.profile) throw new Error("No success from Hypixel");
let d = r.profile;
for (const member in d.members) {
let onlineStatus = await getOnlineStatus(key, member);
if (onlineStatus.success && onlineStatus.session) {
d.members[member].online_status = onlineStatus.session;
}
}
return d;
}

View File

@ -3,8 +3,88 @@ import polka from "polka";
import compression from "compression";
import * as sapper from "@sapper/server";
const { PORT, NODE_ENV } = process.env;
import arangojs, { Database, aql } from "arangojs";
import { hash } from "bcrypt";
import { log } from "./logger";
const { PORT, NODE_ENV, DB_USERNAME, DB_PASSWORD, DB_URL, DB_NAME, API_KEY } =
process.env;
const dev = NODE_ENV === "development";
const db = arangojs({
auth: {
username: DB_USERNAME || "root",
password: DB_PASSWORD
},
url: DB_URL || "http://127.0.0.1:8529",
databaseName: DB_NAME || "sbdatatracker"
});
const saltRounds = 10;
const delay = 3 * 60 * 1000;
const intervalFunc = async (db: Database) => {
const cnf = db.collection("config");
const users = db.collection("users");
if (!(await cnf.exists())) {
await cnf.create();
}
if (!(await users.exists())) {
await users.create();
await users.save({
username: DB_USERNAME,
password: await hash(DB_PASSWORD || "SBDataTracker", saltRounds),
forceChangePassword: true,
permissions: ["*"]
});
}
const cursor = await db.query(
aql`
FOR doc IN ${cnf}
FILTER doc.type == "tracker"
RETURN doc
`,
{
count: true
}
);
/*
Instead of running a loop on all trackers at once,
they are spread out evenly across the delay which
lowers the chance of exceeding the Hypixel rate-limit
when there are a lot of trackers.
TODO : Add a hard-stop if the rate-limit is about
to be exceeded.
*/
if (cursor.hasNext) {
let counter = 0;
let interval: NodeJS.Timeout;
const iterate = async () => {
if (++counter >= (cursor.count as number)) clearInterval(interval);
const { _key, profile } = await cursor.next();
if (profile) {
const col = db.collection(`c${profile}`);
if (!(await col.exists())) col.create();
await col.save(await log(API_KEY || "", profile));
} else {
console.warn(
`Configuration entry '${_key}' with type 'tracker' has no "profile" value`
);
}
};
if ((cursor.count as number) > 1)
interval = setInterval(
iterate,
delay / ((cursor.count as number) - 1)
);
setTimeout(iterate);
}
};
setInterval(intervalFunc, delay, db);
setTimeout(intervalFunc, 0, db);
polka({
onError: err => {