UseDictionary #34
@ -1,10 +1,11 @@
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using MessagePack;
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
using AspNetCoreRateLimit;
|
||||
using Microsoft.AspNetCore.HttpOverrides;
|
||||
using Models.Model.External;
|
||||
using NetMQ;
|
||||
using NetMQ.Sockets;
|
||||
const string myAllowSpecificOrigins = "_myAllowSpecificOrigins";
|
||||
|
||||
WebApplicationBuilder builder = WebApplication.CreateSlimBuilder(args);
|
||||
|
||||
@ -15,16 +16,40 @@ builder.Services.ConfigureHttpJsonOptions(options =>
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
options.AddPolicy("CorsPolicy", x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().Build());
|
||||
options.AddPolicy(name: myAllowSpecificOrigins, x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
|
||||
});
|
||||
|
||||
// Add memory cache and rate limiting services
|
||||
builder.Services.AddMemoryCache();
|
||||
builder.Services.Configure<IpRateLimitOptions>(options =>
|
||||
{
|
||||
options.GeneralRules =
|
||||
[
|
||||
new()
|
||||
{
|
||||
Endpoint = "*", // Apply to all endpoints
|
||||
Period = "10s", // Rate limiting window of 10 second
|
||||
Limit = 5 // Maximum 5 requests per 10 seconds
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
builder.Services.AddInMemoryRateLimiting();
|
||||
builder.Services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
|
||||
|
||||
WebApplication app = builder.Build();
|
||||
|
||||
app.UseCors();
|
||||
app.UseForwardedHeaders(new()
|
||||
{
|
||||
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
|
||||
});
|
||||
|
||||
|
||||
app.UseIpRateLimiting(); // Apply IP-based rate limiting middleware
|
||||
|
||||
app.UseCors(myAllowSpecificOrigins);
|
||||
|
||||
RouteGroupBuilder progressApi = app.MapGroup("/progress");
|
||||
progressApi.AllowAnonymous();
|
||||
progressApi.DisableAntiforgery();
|
||||
progressApi.MapGet("/", () =>
|
||||
{
|
||||
CommunicationObject communicationObject = new()
|
||||
@ -43,8 +68,8 @@ progressApi.MapGet("/", () =>
|
||||
return JsonSerializer.Deserialize<ScanningStatus>(msg);
|
||||
});
|
||||
|
||||
/*
|
||||
RouteGroupBuilder searchApi = app.MapGroup("/search");
|
||||
progressApi.AllowAnonymous();
|
||||
searchApi.MapGet("/{term}", (string term) =>
|
||||
{
|
||||
CommunicationObject communicationObject = new();
|
||||
@ -61,11 +86,11 @@ searchApi.MapGet("/{term}", (string term) =>
|
||||
|
||||
return JsonSerializer.Deserialize<SearchResults?>(msg);
|
||||
});
|
||||
|
||||
*/
|
||||
app.Run();
|
||||
|
||||
[JsonSerializable(typeof(ScanningStatus))]
|
||||
[JsonSerializable(typeof(SearchResults))]
|
||||
//[JsonSerializable(typeof(SearchResults))]
|
||||
[JsonSerializable(typeof(CommunicationObject))]
|
||||
internal partial class AppJsonSerializerContext : JsonSerializerContext
|
||||
{
|
||||
|
@ -9,6 +9,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
|
||||
<PackageReference Include="NetMQ" Version="4.0.1.13" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Default": "Warning",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
|
@ -3,4 +3,5 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003A02000011pdb3Low_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003FILViewer_003F7c3ed02c2ce44598b7f304f8ac45e58f8600_003F6d_003F99b875d1_003F02000011pdb3Low_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ADirectoryInfo_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003Fe4ec446cfe0489bc3ef68a45c6766d183e999ebdc657e94fb1ad059de2bb9_003FDirectoryInfo_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AHttpResponseMessage_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F85e97f467d698c9e98eae9e3a1b39d58541173e57992d8f7111eabdd3db3526_003FHttpResponseMessage_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ARateLimitRule_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F8fbca8b1bca27d45830c443b2c773d979015ea216430366f285514a39fc0b9_003FRateLimitRule_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThread_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F693e634d7742afaf486acd69d84fe2a9e1ee1b11ba84f29cd1d67668d20dd59_003FThread_002Ecs/@EntryIndexedValue">ForceIncluded</s:String></wpf:ResourceDictionary>
|
24
frontend/.gitignore
vendored
Normal file
24
frontend/.gitignore
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
75
frontend/README.md
Normal file
75
frontend/README.md
Normal file
@ -0,0 +1,75 @@
|
||||
# Nuxt Minimal Starter
|
||||
|
||||
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
Make sure to install dependencies:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
|
||||
# pnpm
|
||||
pnpm install
|
||||
|
||||
# yarn
|
||||
yarn install
|
||||
|
||||
# bun
|
||||
bun install
|
||||
```
|
||||
|
||||
## Development Server
|
||||
|
||||
Start the development server on `http://localhost:3000`:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run dev
|
||||
|
||||
# pnpm
|
||||
pnpm dev
|
||||
|
||||
# yarn
|
||||
yarn dev
|
||||
|
||||
# bun
|
||||
bun run dev
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
Build the application for production:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run build
|
||||
|
||||
# pnpm
|
||||
pnpm build
|
||||
|
||||
# yarn
|
||||
yarn build
|
||||
|
||||
# bun
|
||||
bun run build
|
||||
```
|
||||
|
||||
Locally preview production build:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run preview
|
||||
|
||||
# pnpm
|
||||
pnpm preview
|
||||
|
||||
# yarn
|
||||
yarn preview
|
||||
|
||||
# bun
|
||||
bun run preview
|
||||
```
|
||||
|
||||
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
7
frontend/app.vue
Normal file
7
frontend/app.vue
Normal file
@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<NuxtRouteAnnouncer />
|
||||
|
||||
</div>
|
||||
<NuxtPage />
|
||||
</template>
|
3
frontend/assets/css/main.css
Normal file
3
frontend/assets/css/main.css
Normal file
@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
22
frontend/nuxt.config.ts
Normal file
22
frontend/nuxt.config.ts
Normal file
@ -0,0 +1,22 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2024-12-16',
|
||||
ssr: true,
|
||||
|
||||
devtools: { enabled: true },
|
||||
css: ['@/assets/css/main.css'],
|
||||
|
||||
postcss: {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
},
|
||||
|
||||
routeRules: {
|
||||
"/": {isr: true},
|
||||
"/progress": {isr: true},
|
||||
},
|
||||
|
||||
modules: ['@nuxtjs/tailwindcss'],
|
||||
})
|
10904
frontend/package-lock.json
generated
Normal file
10904
frontend/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
24
frontend/package.json
Normal file
24
frontend/package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "nuxt-app",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare"
|
||||
},
|
||||
"dependencies": {
|
||||
"@nuxtjs/partytown": "^1.5.0",
|
||||
"nuxt": "^3.14.1592",
|
||||
"vue": "latest",
|
||||
"vue-router": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxtjs/tailwindcss": "^6.12.2",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"postcss": "^8.4.49",
|
||||
"tailwindcss": "^3.4.16"
|
||||
}
|
||||
}
|
11
frontend/pages/index.vue
Normal file
11
frontend/pages/index.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<script setup lang="ts">
|
||||
const route = useRoute()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<h1>Nuxt Routing set up successfully!</h1>
|
||||
<p>Current route: {{ route.path }}</p>
|
||||
<a href="https://nuxt.com/docs/getting-started/routing" target="_blank">Learn more about Nuxt Routing</a>
|
||||
</div>
|
||||
</template>
|
63
frontend/pages/progress.vue
Normal file
63
frontend/pages/progress.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<script setup lang="ts">
|
||||
import { fetchWithCache } from '~/utils/cacheUtil';
|
||||
import { progressTypeToDictionary } from '~/utils/convertProgressTypeToDictionary';
|
||||
|
||||
const data = ref<ProgressType | null>(null);
|
||||
const loading = ref<boolean>(true);
|
||||
const error = ref<string | null>(null);
|
||||
let dict = ref<ProgressDictionary[] | 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;
|
||||
|
||||
if (data.value !== null) {
|
||||
dict.value = progressTypeToDictionary(data.value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
fetchMyData();
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="h-screen grid place-items-center">
|
||||
<div v-if="dict">
|
||||
<table class="table-auto border-gray-300">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-4 py-2">Metric</th>
|
||||
<th class="px-4 py-2">Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr v-for="d in dict">
|
||||
<td class="px-4 py-2">{{d.description}}</td>
|
||||
<td class="px-4 py-2">{{d.value}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
BIN
frontend/public/favicon.ico
Normal file
BIN
frontend/public/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.2 KiB |
1
frontend/public/robots.txt
Normal file
1
frontend/public/robots.txt
Normal file
@ -0,0 +1 @@
|
||||
|
3
frontend/server/tsconfig.json
Normal file
3
frontend/server/tsconfig.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"extends": "../.nuxt/tsconfig.server.json"
|
||||
}
|
16
frontend/tailwind.config.js
Normal file
16
frontend/tailwind.config.js
Normal file
@ -0,0 +1,16 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./components/**/*.{js,vue,ts}",
|
||||
"./layouts/**/*.vue",
|
||||
"./pages/**/*.vue",
|
||||
"./plugins/**/*.{js,ts}",
|
||||
"./app.vue",
|
||||
"./error.vue",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
4
frontend/tsconfig.json
Normal file
4
frontend/tsconfig.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"extends": "./.nuxt/tsconfig.json"
|
||||
}
|
19
frontend/types/global.d.ts
vendored
Normal file
19
frontend/types/global.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
interface ProgressType {
|
||||
percentageOfIpv4Scanned: number; // assuming this is a number
|
||||
totalFiltered: bigint;
|
||||
amountOfIpv4Left: bigint;
|
||||
totalDiscarded: bigint;
|
||||
discardedDbSize: bigint;
|
||||
filteredDbSize: bigint;
|
||||
myDbSize: bigint;
|
||||
}
|
||||
|
||||
interface ProgressDictionary {
|
||||
description: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
11
frontend/utils/convertProgressTypeToDictionary.ts
Normal file
11
frontend/utils/convertProgressTypeToDictionary.ts
Normal file
@ -0,0 +1,11 @@
|
||||
export function progressTypeToDictionary(progress: ProgressType) {
|
||||
return [
|
||||
{ description: "Percentage of Ipv4 scanned", value: progress.percentageOfIpv4Scanned.toString() },
|
||||
{ description: "Total filtered", value: progress.totalFiltered.toString() },
|
||||
{ description: "Total Discarded", value: progress.totalDiscarded.toString() },
|
||||
{ description: "Amount of Ipv4 left", value: progress.amountOfIpv4Left.toString() },
|
||||
{ description: "Discarded db size", value: progress.discardedDbSize.toString() },
|
||||
{ description: "Filtered db size", value: progress.filteredDbSize.toString() },
|
||||
{ description: "Unfiltered db size", value: progress.myDbSize.toString() },
|
||||
]
|
||||
}
|
Loading…
Reference in New Issue
Block a user