github-webhook-filter/lib/webhook.ts

64 lines
1.9 KiB
TypeScript
Raw Normal View History

import config from "./config.ts";
import { requestLog, sleep } from "./util.ts";
export async function sendWebhook(
id: string,
token: string,
headers: Headers,
data: Record<string, any>,
): Promise<[Response, Record<string, string>]> {
const reqLog = requestLog(headers);
const url = `https://discord.com/api/webhooks/${id}/${token}/github?wait=1`;
const body = JSON.stringify(data);
let res: Response;
let retries = 0;
do {
const req = new Request(url, {
method: "POST",
headers: headers,
body: body,
});
reqLog.info(`sending webhook request to ${url}`);
res = await fetch(req);
// return response if everything's fine
if (res.status !== 429) break;
const reset = res.headers.get("retry-after");
// should always exist, even for cf bans, but checking anyway
if (reset === null) break;
// parse retry delay
let resetms = parseFloat(reset);
if (!res.headers.has("via")) {
// if there's no `via` header, this is likely a cf ban, which uses seconds instead of milliseconds
resetms *= 1000;
}
// if we'd wait longer than the configured limit, just return the 429
2022-09-04 13:08:35 +00:00
if (resetms > config.maxWebhookRetryMs) {
reqLog.warn(
2022-09-04 13:08:35 +00:00
`ratelimited for ${resetms}ms (> ${config.maxWebhookRetryMs}ms), not retrying`,
);
break;
}
// maybe wait and retry
2022-09-04 13:08:35 +00:00
if (retries >= config.maxWebhookRetries) {
reqLog.warn(`reached maximum number of retries (${retries})`);
2022-09-04 13:08:35 +00:00
break;
}
retries++;
reqLog.warn(`retrying after ${resetms}ms (retry ${retries})`);
await sleep(resetms);
} while (true);
2022-09-04 13:34:19 +00:00
// set metadata
const meta: Record<string, string> = {};
2022-09-04 13:34:19 +00:00
if (retries) meta["retries"] = retries.toString();
return [res, meta];
2022-09-04 13:34:19 +00:00
}