UseDictionary #34
@ -1,8 +1,9 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2024-11-01',
|
||||
compatibilityDate: '2024-12-16',
|
||||
ssr: true,
|
||||
devtools: { enabled: false },
|
||||
|
||||
devtools: { enabled: true },
|
||||
css: ['@/assets/css/main.css'],
|
||||
|
||||
postcss: {
|
||||
@ -12,5 +13,10 @@ export default defineNuxtConfig({
|
||||
},
|
||||
},
|
||||
|
||||
routeRules: {
|
||||
"/": {isr: true},
|
||||
"/progress": {isr: true},
|
||||
},
|
||||
|
||||
modules: ['@nuxtjs/tailwindcss'],
|
||||
})
|
26
frontend/package-lock.json
generated
26
frontend/package-lock.json
generated
@ -7,6 +7,7 @@
|
||||
"name": "nuxt-app",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"@nuxtjs/partytown": "^1.5.0",
|
||||
"nuxt": "^3.14.1592",
|
||||
"vue": "latest",
|
||||
"vue-router": "latest"
|
||||
@ -509,6 +510,18 @@
|
||||
"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": {
|
||||
"version": "0.3.4",
|
||||
"resolved": "https://registry.npmjs.org/@cloudflare/kv-asset-handler/-/kv-asset-handler-0.3.4.tgz",
|
||||
@ -1451,6 +1464,19 @@
|
||||
"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": {
|
||||
"version": "6.12.2",
|
||||
"resolved": "https://registry.npmjs.org/@nuxtjs/tailwindcss/-/tailwindcss-6.12.2.tgz",
|
||||
|
@ -10,6 +10,7 @@
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxtjs/partytown": "^1.5.0",
|
||||
"nuxt": "^3.14.1592",
|
||||
"vue": "latest",
|
||||
"vue-router": "latest"
|
||||
|
@ -1,12 +1,38 @@
|
||||
<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>
|
||||
|
||||
<template>
|
||||
<div class="h-screen grid place-items-center">
|
||||
<div v-if="progress">
|
||||
<div v-if="data">
|
||||
<table class="table-auto border-gray-300">
|
||||
<thead>
|
||||
<tr>
|
||||
@ -18,31 +44,31 @@ const progress = getProgress();
|
||||
<tbody >
|
||||
<tr>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
</tbody>
|
||||
</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
|
||||
totalFiltered: bigint;
|
||||
amountOfIpv4Left: bigint;
|
||||
@ -6,4 +6,9 @@ interface Progress {
|
||||
discardedDbSize: bigint;
|
||||
filteredDbSize: 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