11 Commits
21 changed files with 11559 additions and 12 deletions
+28 -11
View File
@@ -1,10 +1,12 @@
using System.Text.Json; using System.Text.Json;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
using MessagePack; using AspNetCoreRateLimit;
using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.Extensions.Caching.Memory;
using Models.Model.External; using Models.Model.External;
using NetMQ; using NetMQ;
using NetMQ.Sockets; using NetMQ.Sockets;
const string myAllowSpecificOrigins = "_myAllowSpecificOrigins";
WebApplicationBuilder builder = WebApplication.CreateSlimBuilder(args); WebApplicationBuilder builder = WebApplication.CreateSlimBuilder(args);
@@ -15,18 +17,29 @@ builder.Services.ConfigureHttpJsonOptions(options =>
builder.Services.AddCors(options => builder.Services.AddCors(options =>
{ {
options.AddPolicy("CorsPolicy", x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().Build()); options.AddPolicy(name: myAllowSpecificOrigins, x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
}); });
builder.Services.AddMemoryCache(options => options.ExpirationScanFrequency = TimeSpan.FromSeconds(5));
WebApplication app = builder.Build(); WebApplication app = builder.Build();
app.UseCors(); app.UseForwardedHeaders(new()
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseCors(myAllowSpecificOrigins);
RouteGroupBuilder progressApi = app.MapGroup("/progress"); RouteGroupBuilder progressApi = app.MapGroup("/progress");
progressApi.AllowAnonymous(); progressApi.MapGet("/", (IMemoryCache memoryCache) =>
progressApi.DisableAntiforgery();
progressApi.MapGet("/", () =>
{ {
const string cacheKey = "progress_status";
if (memoryCache.TryGetValue(cacheKey, out ScanningStatus scanningStatus))
{
return scanningStatus;
}
CommunicationObject communicationObject = new() CommunicationObject communicationObject = new()
{ {
Command = CommunicationCommand.GetScanningProgress Command = CommunicationCommand.GetScanningProgress
@@ -40,11 +53,15 @@ progressApi.MapGet("/", () =>
byte[] msg = client.ReceiveFrameBytes(); byte[] msg = client.ReceiveFrameBytes();
client.Close(); client.Close();
return JsonSerializer.Deserialize<ScanningStatus>(msg); scanningStatus = JsonSerializer.Deserialize<ScanningStatus>(msg);
memoryCache.Set(cacheKey, scanningStatus, DateTimeOffset.Now.AddSeconds(5));
return scanningStatus;
}); });
/*
RouteGroupBuilder searchApi = app.MapGroup("/search"); RouteGroupBuilder searchApi = app.MapGroup("/search");
progressApi.AllowAnonymous();
searchApi.MapGet("/{term}", (string term) => searchApi.MapGet("/{term}", (string term) =>
{ {
CommunicationObject communicationObject = new(); CommunicationObject communicationObject = new();
@@ -61,11 +78,11 @@ searchApi.MapGet("/{term}", (string term) =>
return JsonSerializer.Deserialize<SearchResults?>(msg); return JsonSerializer.Deserialize<SearchResults?>(msg);
}); });
*/
app.Run(); app.Run();
[JsonSerializable(typeof(ScanningStatus))] [JsonSerializable(typeof(ScanningStatus))]
[JsonSerializable(typeof(SearchResults))] //[JsonSerializable(typeof(SearchResults))]
[JsonSerializable(typeof(CommunicationObject))] [JsonSerializable(typeof(CommunicationObject))]
internal partial class AppJsonSerializerContext : JsonSerializerContext internal partial class AppJsonSerializerContext : JsonSerializerContext
{ {
+1
View File
@@ -9,6 +9,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AspNetCoreRateLimit" Version="5.0.0" />
<PackageReference Include="NetMQ" Version="4.0.1.13" /> <PackageReference Include="NetMQ" Version="4.0.1.13" />
</ItemGroup> </ItemGroup>
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {
"Default": "Information", "Default": "Warning",
"Microsoft.AspNetCore": "Warning" "Microsoft.AspNetCore": "Warning"
} }
}, },
+3
View File
@@ -1,6 +1,9 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003A02000002pdb1Low_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003FILViewer_003F51b607df472a454cb6ed940749bbfdfd6000_003Fde_003F2c578873_003F02000002pdb1Low_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003A0200000Cpdb6Low_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003FILViewer_003Fb53c196a821648e4ae3b142a6ae58d7b9400_003Fa8_003F21a43479_003F0200000Cpdb6Low_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003A0200000Cpdb6Low_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FDecompilerCache_003FILViewer_003Fb53c196a821648e4ae3b142a6ae58d7b9400_003Fa8_003F21a43479_003F0200000Cpdb6Low_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<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_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_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_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_003AStartupExtensions_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2024_002E2_003Fresharper_002Dhost_003FSourcesCache_003F3ce5d581dd9cc0e4cdfd914e797ba2da05e894767d76b86f0515ef5226bac_003FStartupExtensions_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> <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
View 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
View 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.
+16
View File
@@ -0,0 +1,16 @@
<script setup lang="ts">
useHead({
title: 'Rasmus Search Engine',
meta: [
{ name: 'description', content: 'Just a search engine for fun' },
{ name: 'lang', content: 'en'}
]
})
</script>
<template>
<NuxtLayout>
<NuxtPage page-key="static" />
</NuxtLayout>
</template>
+3
View File
@@ -0,0 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
+17
View File
@@ -0,0 +1,17 @@
// 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: {},
},
},
modules: ['@nuxtjs/tailwindcss', 'nuxt-purgecss'],
});
+11204
View File
File diff suppressed because it is too large Load Diff
+25
View File
@@ -0,0 +1,25 @@
{
"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",
"nuxt-purgecss": "^2.0.0",
"postcss": "^8.4.49",
"tailwindcss": "^3.4.16"
}
}
+11
View 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
View 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>
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

+1
View File
@@ -0,0 +1 @@
+3
View File
@@ -0,0 +1,3 @@
{
"extends": "../.nuxt/tsconfig.server.json"
}
+16
View 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
View File
@@ -0,0 +1,4 @@
{
// https://nuxt.com/docs/guide/concepts/typescript
"extends": "./.nuxt/tsconfig.json"
}
+19
View 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
View 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);
}
});
}
@@ -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() },
]
}