aboutsummaryrefslogtreecommitdiff
path: root/build/hypixelApi.js
blob: a35dd640a30bf5e305197b3a00de8b53d8715ec0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
var _a, _b, _c;
Object.defineProperty(exports, "__esModule", { value: true });
exports.sendApiRequest = exports.getKeyUsage = exports.chooseApiKey = void 0;
/**
 * Fetch the raw Hypixel API
 */
const node_fetch_1 = __importDefault(require("node-fetch"));
const util_1 = require("./util");
const https_1 = require("https");
if (!process.env.hypixel_keys)
    // if there's no hypixel keys in env, run dotenv
    require('dotenv').config();
// We need to create an agent to prevent memory leaks and to only do dns lookups once
const httpsAgent = new https_1.Agent({
    keepAlive: true
});
/** This array should only ever contain one item because using multiple hypixel api keys isn't allowed :) */
const apiKeys = (_c = (_b = (_a = process.env) === null || _a === void 0 ? void 0 : _a.hypixel_keys) === null || _b === void 0 ? void 0 : _b.split(' ')) !== null && _c !== void 0 ? _c : [];
const apiKeyUsage = {};
const baseHypixelAPI = 'https://api.hypixel.net';
/** Choose the best current API key */
function chooseApiKey() {
    // find the api key with the lowest amount of uses
    let bestKeyUsage = null;
    let bestKey = null;
    for (let key of util_1.shuffle(apiKeys.slice())) {
        const keyUsage = apiKeyUsage[key];
        // if the key has never been used before, use it
        if (!keyUsage)
            return key;
        // if the key has reset since the last use, set the remaining count to the default
        if (Date.now() > keyUsage.reset)
            keyUsage.remaining = keyUsage.limit;
        // if this key has more uses remaining than the current known best one, save it
        if (bestKeyUsage === null || keyUsage.remaining > bestKeyUsage.remaining) {
            bestKeyUsage = keyUsage;
            bestKey = key;
        }
    }
    return bestKey;
}
exports.chooseApiKey = chooseApiKey;
function getKeyUsage() {
    let keyLimit = 0;
    let keyUsage = 0;
    for (let key of Object.values(apiKeyUsage)) {
        keyLimit += key.limit;
        keyUsage += key.limit - key.remaining;
    }
    return {
        limit: keyLimit,
        usage: keyUsage
    };
}
exports.getKeyUsage = getKeyUsage;
/** Send an HTTP request to the Hypixel API */
async function sendApiRequest({ path, key, args }) {
    // Send a raw http request to api.hypixel.net, and return the parsed json
    var _a, _b, _c;
    if (key)
        // If there's an api key, add it to the arguments
        args.key = key;
    // Construct a url from the base api url, path, and arguments
    const fetchUrl = baseHypixelAPI + '/' + path + '?' + util_1.jsonToQuery(args);
    let fetchResponse;
    let fetchJsonParsed;
    try {
        fetchResponse = await node_fetch_1.default(fetchUrl, { agent: () => httpsAgent });
        fetchJsonParsed = await fetchResponse.json();
    }
    catch {
        // if there's an error, wait a second and try again
        await new Promise((resolve) => setTimeout(resolve, 1000));
        return await sendApiRequest({ path, key, args });
    }
    // bruh
    if (fetchJsonParsed.cause === 'This endpoint is currently disabled') {
        await new Promise((resolve) => setTimeout(resolve, 30000));
        return await sendApiRequest({ path, key, args });
    }
    if (fetchResponse.headers.get('ratelimit-limit'))
        // remember how many uses it has
        apiKeyUsage[key] = {
            remaining: parseInt((_a = fetchResponse.headers.get('ratelimit-remaining')) !== null && _a !== void 0 ? _a : '0'),
            limit: parseInt((_b = fetchResponse.headers.get('ratelimit-limit')) !== null && _b !== void 0 ? _b : '0'),
            reset: Date.now() + parseInt((_c = fetchResponse.headers.get('ratelimit-reset')) !== null && _c !== void 0 ? _c : '0') * 1000
        };
    if (fetchJsonParsed.throttle) {
        if (apiKeyUsage[key])
            apiKeyUsage[key].remaining = 0;
        // if it's throttled, wait 10 seconds and try again
        await new Promise((resolve) => setTimeout(resolve, 10000));
        return await sendApiRequest({ path, key, args });
    }
    return fetchJsonParsed;
}
exports.sendApiRequest = sendApiRequest;