Add a time-based cache for the progress result from the API
This commit is contained in:
parent
1c74ae9de5
commit
3822339dd9
@ -1,8 +1,9 @@
|
|||||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||||
export default defineNuxtConfig({
|
export default defineNuxtConfig({
|
||||||
compatibilityDate: '2024-11-01',
|
compatibilityDate: '2024-12-16',
|
||||||
ssr: true,
|
ssr: true,
|
||||||
devtools: { enabled: false },
|
|
||||||
|
devtools: { enabled: true },
|
||||||
css: ['@/assets/css/main.css'],
|
css: ['@/assets/css/main.css'],
|
||||||
|
|
||||||
postcss: {
|
postcss: {
|
||||||
@ -12,5 +13,10 @@ export default defineNuxtConfig({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
routeRules: {
|
||||||
|
"/": {isr: true},
|
||||||
|
"/progress": {isr: true},
|
||||||
|
},
|
||||||
|
|
||||||
modules: ['@nuxtjs/tailwindcss'],
|
modules: ['@nuxtjs/tailwindcss'],
|
||||||
})
|
})
|
26
frontend/package-lock.json
generated
26
frontend/package-lock.json
generated
@ -7,6 +7,7 @@
|
|||||||
"name": "nuxt-app",
|
"name": "nuxt-app",
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@nuxtjs/partytown": "^1.5.0",
|
||||||
"nuxt": "^3.14.1592",
|
"nuxt": "^3.14.1592",
|
||||||
"vue": "latest",
|
"vue": "latest",
|
||||||
"vue-router": "latest"
|
"vue-router": "latest"
|
||||||
@ -509,6 +510,18 @@
|
|||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@builder.io/partytown": {
|
||||||
|
"version": "0.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@builder.io/partytown/-/partytown-0.10.2.tgz",
|
||||||
|
"integrity": "sha512-A9U+4PREWcS+CCYzKGIPovtGB/PBgnH/8oQyCE6Nr9drDJk6cMPpLQIEajpGPmG9tYF7N3FkRvhXm/AS9+0iKg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"partytown": "bin/partytown.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@cloudflare/kv-asset-handler": {
|
"node_modules/@cloudflare/kv-asset-handler": {
|
||||||
"version": "0.3.4",
|
"version": "0.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz",
|
||||||
@ -1451,6 +1464,19 @@
|
|||||||
"vue": "^3.3.4"
|
"vue": "^3.3.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@nuxtjs/partytown": {
|
||||||
|
"version": "1.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@nuxtjs/partytown/-/partytown-1.5.0.tgz",
|
||||||
|
"integrity": "sha512-3qJXEXoHydCEEiHZCy4Q80kHTqKD0T9Ryj8kjh0bwTfNHGQ5auC7pqJxy6+CFOqfZZRcGalqGb0MhhRc8GdTdw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@builder.io/partytown": "^0.10.0",
|
||||||
|
"@nuxt/kit": "^3.11.1",
|
||||||
|
"knitwork": "^1.0.0",
|
||||||
|
"serve-static": "^1.15.0",
|
||||||
|
"ufo": "^1.5.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@nuxtjs/tailwindcss": {
|
"node_modules/@nuxtjs/tailwindcss": {
|
||||||
"version": "6.12.2",
|
"version": "6.12.2",
|
||||||
"resolved": "https://registry.npmjs.org/@nuxtjs/tailwindcss/-/tailwindcss-6.12.2.tgz",
|
"resolved": "https://registry.npmjs.org/@nuxtjs/tailwindcss/-/tailwindcss-6.12.2.tgz",
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
"postinstall": "nuxt prepare"
|
"postinstall": "nuxt prepare"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@nuxtjs/partytown": "^1.5.0",
|
||||||
"nuxt": "^3.14.1592",
|
"nuxt": "^3.14.1592",
|
||||||
"vue": "latest",
|
"vue": "latest",
|
||||||
"vue-router": "latest"
|
"vue-router": "latest"
|
||||||
|
@ -1,12 +1,38 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import getProgress from "~/plugins/getProgress";
|
import { fetchWithCache } from '~/utils/cacheUtil';
|
||||||
|
|
||||||
|
const data = ref<ProgressType | null>(null);
|
||||||
|
const loading = ref<boolean>(true);
|
||||||
|
const error = ref<string | null>(null);
|
||||||
|
|
||||||
|
const fetchMyData = async () => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
|
||||||
|
// Use the caching utility
|
||||||
|
data.value = await fetchWithCache<ProgressType>(
|
||||||
|
'Progress',
|
||||||
|
async () => {
|
||||||
|
const response = await fetch('https://proxy.rbwr.dk/progress');
|
||||||
|
if (!response.ok) throw new Error('API fetch failed');
|
||||||
|
return (await response.json()) as ProgressType;
|
||||||
|
},
|
||||||
|
5 // Cache max age in seconds
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
error.value = (err as Error).message;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchMyData();
|
||||||
|
|
||||||
const progress = getProgress();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="h-screen grid place-items-center">
|
<div class="h-screen grid place-items-center">
|
||||||
<div v-if="progress">
|
<div v-if="data">
|
||||||
<table class="table-auto border-gray-300">
|
<table class="table-auto border-gray-300">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
@ -18,31 +44,31 @@ const progress = getProgress();
|
|||||||
<tbody >
|
<tbody >
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2">Percentage of Ipv4 scanned</td>
|
<td class="px-4 py-2">Percentage of Ipv4 scanned</td>
|
||||||
<td class="px-4 py-2">{{progress.percentageOfIpv4Scanned}}</td>
|
<td class="px-4 py-2">{{data.percentageOfIpv4Scanned}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2">Total filtered</td>
|
<td class="px-4 py-2">Total filtered</td>
|
||||||
<td class="px-4 py-2">{{progress.totalFiltered}}</td>
|
<td class="px-4 py-2">{{data.totalFiltered}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2">Total Discarded</td>
|
<td class="px-4 py-2">Total Discarded</td>
|
||||||
<td class="px-4 py-2">{{progress.totalDiscarded}}</td>
|
<td class="px-4 py-2">{{data.totalDiscarded}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2">Amount of Ipv4 left</td>
|
<td class="px-4 py-2">Amount of Ipv4 left</td>
|
||||||
<td class="px-4 py-2">{{progress.amountOfIpv4Left}}</td>
|
<td class="px-4 py-2">{{data.amountOfIpv4Left}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2">Discarded db size</td>
|
<td class="px-4 py-2">Discarded db size</td>
|
||||||
<td class="px-4 py-2">{{progress.discardedDbSize}}</td>
|
<td class="px-4 py-2">{{data.discardedDbSize}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2">Filtered db size</td>
|
<td class="px-4 py-2">Filtered db size</td>
|
||||||
<td class="px-4 py-2">{{progress.filteredDbSize}}</td>
|
<td class="px-4 py-2">{{data.filteredDbSize}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="px-4 py-2">Unfiltered db size</td>
|
<td class="px-4 py-2">Unfiltered db size</td>
|
||||||
<td class="px-4 py-2">{{progress.myDbSize}}</td>
|
<td class="px-4 py-2">{{data.myDbSize}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
export default function getProgress(){
|
|
||||||
|
|
||||||
const progress = ref(null as Progress | null);
|
|
||||||
|
|
||||||
fetch('https://proxy.rbwr.dk/progress', {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {'Content-Type': 'application/json'}
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then((data: Progress) => {
|
|
||||||
if (data && data.percentageOfIpv4Scanned) {
|
|
||||||
progress.value = data;
|
|
||||||
} else {
|
|
||||||
console.error("Invalid data received from API");
|
|
||||||
console.error(data);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return progress;
|
|
||||||
}
|
|
9
frontend/types/global.d.ts
vendored
9
frontend/types/global.d.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
interface Progress {
|
interface ProgressType {
|
||||||
percentageOfIpv4Scanned: number; // assuming this is a number
|
percentageOfIpv4Scanned: number; // assuming this is a number
|
||||||
totalFiltered: bigint;
|
totalFiltered: bigint;
|
||||||
amountOfIpv4Left: bigint;
|
amountOfIpv4Left: bigint;
|
||||||
@ -6,4 +6,9 @@ interface Progress {
|
|||||||
discardedDbSize: bigint;
|
discardedDbSize: bigint;
|
||||||
filteredDbSize: bigint;
|
filteredDbSize: bigint;
|
||||||
myDbSize: bigint;
|
myDbSize: bigint;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CacheEntry<T> = {
|
||||||
|
data: T;
|
||||||
|
timestamp: number;
|
||||||
|
};
|
34
frontend/utils/cacheUtil.ts
Normal file
34
frontend/utils/cacheUtil.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
export function fetchWithCache<Type>(
|
||||||
|
cacheKey: string,
|
||||||
|
fetchFunction: () => Promise<Type>,
|
||||||
|
maxAge: number = 5 // 30 seconds
|
||||||
|
): Promise<Type> {
|
||||||
|
return new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const cachedData = localStorage.getItem(cacheKey);
|
||||||
|
|
||||||
|
if (cachedData) {
|
||||||
|
const { data, timestamp } = JSON.parse(cachedData) as CacheEntry<Type>;
|
||||||
|
const now = Date.now();
|
||||||
|
const ageInSeconds = (now - timestamp) / 1000;
|
||||||
|
|
||||||
|
// Check if cache is still valid
|
||||||
|
if (ageInSeconds < maxAge) {
|
||||||
|
return resolve(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache is missing or expired, fetch fresh data
|
||||||
|
const freshData = await fetchFunction();
|
||||||
|
const cacheEntry: CacheEntry<Type> = {
|
||||||
|
data: freshData,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
};
|
||||||
|
|
||||||
|
localStorage.setItem(cacheKey, JSON.stringify(cacheEntry));
|
||||||
|
resolve(freshData);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user