better backend comms
This commit is contained in:
parent
d0e8623cf9
commit
02a057622c
17 changed files with 1054 additions and 134 deletions
|
|
@ -8,6 +8,10 @@ import type { WatchBlocksReturnType } from "viem";
|
|||
import { bigInt2Number } from "@/utils/helper";
|
||||
const demo = sessionStorage.getItem("demo") === "true";
|
||||
|
||||
const GRAPHQL_TIMEOUT_MS = 15_000;
|
||||
const RETRY_BASE_DELAY_MS = 1_500;
|
||||
const RETRY_MAX_DELAY_MS = 60_000;
|
||||
|
||||
interface StatsRecord {
|
||||
burnNextHourProjected: string;
|
||||
burnedLastDay: string;
|
||||
|
|
@ -27,14 +31,54 @@ interface StatsRecord {
|
|||
const rawStatsCollections = ref<Array<StatsRecord>>([]);
|
||||
const loading = ref(false);
|
||||
const initialized = ref(false);
|
||||
const statsError = ref<string | null>(null);
|
||||
const statsRetryDelayMs = ref(RETRY_BASE_DELAY_MS);
|
||||
let statsRetryTimer: number | null = null;
|
||||
|
||||
export async function loadStatsCollection() {
|
||||
logger.info(`loadStatsCollection for chain: ${chainData.value?.path}`);
|
||||
if (!chainData.value?.graphql) {
|
||||
return [];
|
||||
function formatGraphqlError(error: unknown): string {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const responseErrors = (error.response?.data as any)?.errors;
|
||||
if (Array.isArray(responseErrors) && responseErrors.length > 0) {
|
||||
return responseErrors.map((err: any) => err?.message ?? "GraphQL error").join(", ");
|
||||
}
|
||||
if (error.response?.status) {
|
||||
return `GraphQL request failed with status ${error.response.status}`;
|
||||
}
|
||||
if (error.message) {
|
||||
return error.message;
|
||||
}
|
||||
}
|
||||
if (error instanceof Error && error.message) {
|
||||
return error.message;
|
||||
}
|
||||
return "Unknown GraphQL error";
|
||||
}
|
||||
|
||||
const res = await axios.post(chainData.value?.graphql, {
|
||||
function clearStatsRetryTimer() {
|
||||
if (statsRetryTimer !== null) {
|
||||
clearTimeout(statsRetryTimer);
|
||||
statsRetryTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
function scheduleStatsRetry() {
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
if (statsRetryTimer !== null) {
|
||||
return;
|
||||
}
|
||||
const delay = statsRetryDelayMs.value;
|
||||
statsRetryTimer = window.setTimeout(async () => {
|
||||
statsRetryTimer = null;
|
||||
await loadStats();
|
||||
}, delay);
|
||||
statsRetryDelayMs.value = Math.min(statsRetryDelayMs.value * 2, RETRY_MAX_DELAY_MS);
|
||||
}
|
||||
|
||||
export async function loadStatsCollection(endpoint: string) {
|
||||
logger.info(`loadStatsCollection for chain: ${chainData.value?.path}`);
|
||||
const res = await axios.post(endpoint, {
|
||||
query: `query StatsQuery {
|
||||
stats(id: "0x01") {
|
||||
burnNextHourProjected
|
||||
|
|
@ -52,11 +96,16 @@ export async function loadStatsCollection() {
|
|||
totalMinted
|
||||
}
|
||||
}`,
|
||||
});
|
||||
}, { timeout: GRAPHQL_TIMEOUT_MS });
|
||||
|
||||
const errors = res.data?.errors;
|
||||
if (Array.isArray(errors) && errors.length > 0) {
|
||||
throw new Error(errors.map((err: any) => err?.message ?? "GraphQL error").join(", "));
|
||||
}
|
||||
|
||||
const stats = res.data?.data?.stats as StatsRecord | undefined;
|
||||
if (!stats) {
|
||||
return [];
|
||||
throw new Error("Stats entity not found in GraphQL response");
|
||||
}
|
||||
|
||||
return [{ ...stats, kraikenTotalSupply: stats.kraikenTotalSupply }];
|
||||
|
|
@ -178,10 +227,31 @@ const claimedSlots = computed(() => {
|
|||
export async function loadStats() {
|
||||
loading.value = true;
|
||||
|
||||
rawStatsCollections.value = await loadStatsCollection();
|
||||
const endpoint = chainData.value?.graphql?.trim();
|
||||
if (!endpoint) {
|
||||
rawStatsCollections.value = [];
|
||||
statsError.value = "GraphQL endpoint not configured for this chain.";
|
||||
clearStatsRetryTimer();
|
||||
statsRetryDelayMs.value = RETRY_BASE_DELAY_MS;
|
||||
loading.value = false;
|
||||
initialized.value = true;
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = false;
|
||||
initialized.value = true;
|
||||
try {
|
||||
rawStatsCollections.value = await loadStatsCollection(endpoint);
|
||||
statsError.value = null;
|
||||
statsRetryDelayMs.value = RETRY_BASE_DELAY_MS;
|
||||
clearStatsRetryTimer();
|
||||
} catch (error) {
|
||||
console.warn("[stats] loadStats() failed", error);
|
||||
rawStatsCollections.value = [];
|
||||
statsError.value = formatGraphqlError(error);
|
||||
scheduleStatsRetry();
|
||||
} finally {
|
||||
loading.value = false;
|
||||
initialized.value = true;
|
||||
}
|
||||
}
|
||||
|
||||
let unwatch: any = null;
|
||||
|
|
@ -212,6 +282,7 @@ export function useStatCollection() {
|
|||
// })
|
||||
}
|
||||
onUnmounted(() => {
|
||||
clearStatsRetryTimer();
|
||||
unwatch();
|
||||
});
|
||||
|
||||
|
|
@ -227,5 +298,7 @@ export function useStatCollection() {
|
|||
maxSlots,
|
||||
stakeableSupply,
|
||||
claimedSlots,
|
||||
statsError,
|
||||
loading,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue