2024-04-04 05:47:26 +00:00
|
|
|
import "dotenv/config";
|
|
|
|
|
2024-04-04 07:16:33 +00:00
|
|
|
const AUTH_KEY = Bun.env.TBA_AUTH_KEY as string;
|
2024-04-04 06:56:41 +00:00
|
|
|
if (!AUTH_KEY) {
|
2024-04-04 07:16:33 +00:00
|
|
|
process.exit(1);
|
2024-04-04 06:56:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const authHeaders = new Headers({
|
|
|
|
"X-TBA-Auth-Key": AUTH_KEY,
|
|
|
|
});
|
|
|
|
|
2024-04-04 05:47:26 +00:00
|
|
|
const BASE_URL = "https://www.thebluealliance.com/api/v3";
|
|
|
|
|
2024-04-04 06:56:41 +00:00
|
|
|
interface CacheEntry {
|
|
|
|
etag: string;
|
|
|
|
data: string;
|
|
|
|
staleTime: number;
|
|
|
|
}
|
|
|
|
|
2024-04-04 07:16:33 +00:00
|
|
|
const CACHE_PATH = Bun.env.CACHE_PATH as string;
|
|
|
|
if (!CACHE_PATH) {
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function initializeCache() {
|
|
|
|
let data = {};
|
|
|
|
|
|
|
|
const cacheFile = Bun.file(".cache");
|
|
|
|
if (cacheFile.size > 0) {
|
|
|
|
data = JSON.parse(await cacheFile.text());
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log(Object.keys(data));
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
const tbaCache: { [name: string]: CacheEntry } = await initializeCache();
|
|
|
|
|
|
|
|
async function writeCache() {
|
|
|
|
Bun.write(CACHE_PATH, JSON.stringify(tbaCache));
|
|
|
|
}
|
2024-04-04 06:56:41 +00:00
|
|
|
|
|
|
|
interface TBAResponse {
|
|
|
|
data: string;
|
|
|
|
status: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateCache(
|
|
|
|
endpoint: string,
|
|
|
|
etag: string | null,
|
|
|
|
data: string,
|
|
|
|
maxAge: number,
|
|
|
|
) {
|
|
|
|
if (etag) {
|
2024-04-04 07:16:33 +00:00
|
|
|
tbaCache[endpoint] = { etag, data, staleTime: Date.now() + maxAge * 1000 };
|
2024-04-04 06:56:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function fetchCache(endpoint: string) {
|
|
|
|
return tbaCache[endpoint];
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getTBAEndpoint(endpoint: string): Promise<TBAResponse> {
|
|
|
|
const time = Date.now();
|
|
|
|
if (tbaCache[endpoint] && tbaCache[endpoint].staleTime > time) {
|
|
|
|
console.log("Cache hit... " + endpoint);
|
|
|
|
return { data: fetchCache(endpoint).data, status: 200 };
|
|
|
|
}
|
|
|
|
|
|
|
|
console.log("Fetching... " + endpoint);
|
|
|
|
const headers = new Headers(authHeaders);
|
|
|
|
const response = await fetch(BASE_URL + endpoint, { headers });
|
|
|
|
|
|
|
|
let data;
|
|
|
|
if (response.status === 200) {
|
|
|
|
data = await response.text();
|
|
|
|
const maxAge = parseInt(
|
|
|
|
response.headers
|
|
|
|
.get("cache-control")
|
|
|
|
?.split(",")
|
|
|
|
.filter((d) => d.includes("max-age"))[0]
|
|
|
|
.trim()
|
|
|
|
.split("=")[1] as string,
|
|
|
|
);
|
|
|
|
updateCache(endpoint, response.headers.get("ETag"), data, maxAge);
|
|
|
|
} else if (response.status === 304) {
|
|
|
|
// Safety: a 304 response indicates out cache is valid based on ETag
|
|
|
|
data = fetchCache(endpoint).data as string;
|
|
|
|
|
|
|
|
console.log("Unchanged... " + endpoint);
|
|
|
|
} else {
|
|
|
|
data = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
data,
|
|
|
|
status: response.status,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
const response = await getTBAEndpoint("/team/frc4043/events/simple");
|
|
|
|
|
2024-04-04 07:16:33 +00:00
|
|
|
writeCache();
|
2024-04-04 05:47:26 +00:00
|
|
|
|