commit dd3c21375d3d5a74c4058c5017cd7b4e32039fe1 Author: Adam Veldhousen <adamveld12@gmail.com> Date: Sun May 30 20:02:07 2021 -0500 added manifest file, cleaned up search and time chart commit 75bb4e2ed29aae571853d7ae8815b4b80b5a2a40 Author: Adam Veldhousen <adamveld12@gmail.com> Date: Sat May 29 21:46:47 2021 -0500 some big updates to how the pages are set up commit 66611d5b2a0b338c11010a189a6e12264186e560 Author: Adam Veldhousen <adamveld12@gmail.com> Date: Sat May 29 16:49:25 2021 -0500 cleanup, better dev experience, got recursors to show commit c9b4a30d05d5f3be9ed3754051d2a26b905f5940 Author: Adam Veldhousen <adam.veldhousen@liveauctioneers.com> Date: Sat May 29 15:33:02 2021 -0500 checkpoint commit f8dc94effcbab16f1811c7ed313beb9b2834d3ed Author: Adam Veldhousen <adam.veldhousen@liveauctioneers.com> Date: Sat May 29 13:46:18 2021 -0500 add env vars to globals commit acd44f7e53b62e3c673800423300cfdcaada6ee9 Author: Adam Veldhousen <adam.veldhousen@liveauctioneers.com> Date: Sat May 29 13:39:25 2021 -0500 update build for frontend commit 9ed14e0574c335645883f8151919e488b36f5a5a Author: Adam Veldhousen <adamveld12@gmail.com> Date: Fri May 28 18:20:34 2021 -0500 got go embed working with frontend commit 56fe5d371fe6451e818ba65c2e2716b86c27eb91 Author: Adam Veldhousen <adamveld12@gmail.com> Date: Thu May 27 16:27:58 2021 -0500 trying to add goembedpull/1/head
parent
b102e17f72
commit
8b76101107
File diff suppressed because it is too large
Load Diff
@ -1,42 +1,45 @@
|
||||
{
|
||||
"name": "svelte-app",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "NODE_ENV=production rollup -c",
|
||||
"dev": "rollup -c -w",
|
||||
"start": "sirv public",
|
||||
"validate": "svelte-check"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^17.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.0.0",
|
||||
"@rollup/plugin-typescript": "^8.1.0",
|
||||
"@tsconfig/svelte": "^1.0.0",
|
||||
"autoprefixer": "^10.2.3",
|
||||
"postcss": "^8.2.4",
|
||||
"rollup": "^2.3.4",
|
||||
"rollup-plugin-css-only": "^3.1.0",
|
||||
"rollup-plugin-livereload": "^2.0.0",
|
||||
"rollup-plugin-svelte": "^7.0.0",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
"svelte": "^3.38.2",
|
||||
"svelte-check": "^1.0.0",
|
||||
"svelte-preprocess": "^4.6.3",
|
||||
"tailwindcss": "^2.0.2",
|
||||
"tslib": "^2.0.0",
|
||||
"typescript": "^4.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"bootstrap": "^5.0.0",
|
||||
"chart.js": "^3.2.1",
|
||||
"date-fns": "^2.21.3",
|
||||
"fa-svelte": "^3.1.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"sirv-cli": "^1.0.0",
|
||||
"svelte-awesome": "^2.3.1",
|
||||
"svelte-chartjs": "^1.0.1",
|
||||
"svelte-routing": "^1.6.0",
|
||||
"sveltestrap": "^4.2.1"
|
||||
}
|
||||
"name": "svelte-app",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "NODE_ENV=production rollup -c",
|
||||
"dev": "NODE_ENV=development rollup -c -w",
|
||||
"start": "sirv public --single -G -D",
|
||||
"validate": "svelte-check"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-commonjs": "^17.0.0",
|
||||
"@rollup/plugin-node-resolve": "^11.0.0",
|
||||
"@rollup/plugin-replace": "^2.4.2",
|
||||
"@rollup/plugin-typescript": "^8.1.0",
|
||||
"@tsconfig/svelte": "^1.0.0",
|
||||
"@types/node": "^15.6.1",
|
||||
"autoprefixer": "^10.2.3",
|
||||
"postcss": "^8.2.4",
|
||||
"rollup": "^2.3.4",
|
||||
"rollup-plugin-css-only": "^3.1.0",
|
||||
"rollup-plugin-livereload": "^2.0.0",
|
||||
"rollup-plugin-svelte": "^7.0.0",
|
||||
"rollup-plugin-terser": "^7.0.0",
|
||||
"sirv-cli": "^1.0.0",
|
||||
"svelte": "^3.38.2",
|
||||
"svelte-check": "^1.0.0",
|
||||
"svelte-preprocess": "^4.6.3",
|
||||
"tailwindcss": "^2.0.2",
|
||||
"tslib": "^2.0.0",
|
||||
"typescript": "^4.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
||||
"bootstrap": "^5.0.0",
|
||||
"chart.js": "^3.2.1",
|
||||
"date-fns": "^2.21.3",
|
||||
"fa-svelte": "^3.1.0",
|
||||
"normalize.css": "^8.0.1",
|
||||
"randomcolor": "^0.6.2",
|
||||
"svelte-awesome": "^2.3.1",
|
||||
"svelte-chartjs": "^1.0.1",
|
||||
"svelte-routing": "^1.6.0",
|
||||
"sveltestrap": "^4.2.1"
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,47 @@
|
||||
{
|
||||
"name": "Gopherhole Dashboard",
|
||||
"short_name": "Gopherhole",
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"background_color": "white",
|
||||
"theme_color": "rgb(55, 65, 81)",
|
||||
"description": "A DNS server that help's you take back control of your network",
|
||||
"icons": [
|
||||
{
|
||||
"src": "images/touch/homescreen48.png",
|
||||
"sizes": "48x48",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "images/touch/homescreen72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "images/touch/homescreen96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "images/touch/homescreen144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "images/touch/homescreen168.png",
|
||||
"sizes": "168x168",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "images/touch/homescreen192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"related_applications": [
|
||||
{
|
||||
"platform": "play",
|
||||
"url": "https://play.google.com/store/apps/details?id=cheeaun.hackerweb"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package public
|
||||
|
||||
import "embed"
|
||||
|
||||
//go:embed *
|
||||
var Assets embed.FS
|
@ -0,0 +1,94 @@
|
||||
import { apiCall } from './util'
|
||||
import { getUnixTime, sub } from 'date-fns';
|
||||
|
||||
export interface Recursor {
|
||||
ipAddress: string
|
||||
timeoutMs: number
|
||||
weight: number
|
||||
}
|
||||
|
||||
export const getRecursors = async () => await apiCall<Recursor>('recursors')
|
||||
|
||||
|
||||
export interface Log {
|
||||
Started: string
|
||||
Domain: string
|
||||
ClientIP: string
|
||||
Status: string
|
||||
Protocol: string
|
||||
Error: string
|
||||
RecurseUpstreamIP: string
|
||||
RecurseRoundTripTimeMs: number
|
||||
TotalTimeMs: number
|
||||
};
|
||||
|
||||
export interface LogSearchOptions {
|
||||
start: Date
|
||||
end: Date
|
||||
page: number
|
||||
filter: string
|
||||
}
|
||||
|
||||
export const getLogs = async({
|
||||
start = sub(new Date(), { hours: 24 }),
|
||||
end = new Date(),
|
||||
page = 0,
|
||||
filter = ""
|
||||
}: LogSearchOptions) => await apiCall<Log>('metrics/log', 'GET', {
|
||||
filter,
|
||||
page,
|
||||
start: getUnixTime(start),
|
||||
end: getUnixTime(end),
|
||||
});
|
||||
|
||||
export interface StatsSearchOptions {
|
||||
start: Date
|
||||
end: Date
|
||||
key: StatSearchKey
|
||||
interval: number
|
||||
}
|
||||
|
||||
export enum StatSearchKey {
|
||||
Domain = "domain",
|
||||
ClientIp = "clientIp",
|
||||
Status = "status",
|
||||
Protocol = "protocol"
|
||||
}
|
||||
|
||||
export interface Stat {
|
||||
Header: string
|
||||
AverageTotalTime: Number
|
||||
Count: number,
|
||||
Time: string
|
||||
};
|
||||
|
||||
export const getStats = async ({
|
||||
start = sub(new Date(), { hours: 24 }),
|
||||
end = new Date(),
|
||||
key = StatSearchKey.Domain,
|
||||
interval = 30,
|
||||
}: StatsSearchOptions) => await apiCall<Stat>('metrics/stats', 'GET', {
|
||||
start: getUnixTime(start),
|
||||
end: getUnixTime(end),
|
||||
key,
|
||||
interval
|
||||
});
|
||||
|
||||
|
||||
export interface RuleAnswer {
|
||||
type: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface Rule {
|
||||
id: number
|
||||
weight: number
|
||||
enabled: boolean
|
||||
created: string
|
||||
name: string
|
||||
value: string
|
||||
answer: RuleAnswer
|
||||
ttl: number
|
||||
}
|
||||
|
||||
export const getRules = () => apiCall<Rule>('rules');
|
@ -1,26 +0,0 @@
|
||||
import { sub, getUnixTime } from 'date-fns'
|
||||
import { API_HOST } from './util';
|
||||
|
||||
|
||||
export const getLogs = async function ({
|
||||
start = sub(new Date(), { hours: 12 }),
|
||||
end = new Date(),
|
||||
page = 0,
|
||||
filter = ""
|
||||
} = {}) {
|
||||
try {
|
||||
const data = await fetch(API_HOST(`metrics/log?filter=${filter}&start=${getUnixTime(start)}&end=${getUnixTime(end)}&page=${page}`), {
|
||||
"method": "GET",
|
||||
"headers": { "Accept": "application/json" }
|
||||
});
|
||||
|
||||
const { success, payload } = await data.json();
|
||||
if (success) {
|
||||
return { payload, start, end, filter };
|
||||
}
|
||||
return { error: payload };
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return { error };
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
import { getUnixTime, sub, format } from 'date-fns';
|
||||
import { readable } from "svelte/store";
|
||||
import { API_HOST } from './util';
|
||||
|
||||
export const SearchDateFormatStr = "yyyy-MM-dd HH:mm:ss.SSS";
|
||||
export const formatDateForSearch = date => format(date, SearchDateFormatStr);
|
||||
|
||||
/*
|
||||
take something like `clientIp:127.0.0.1 protocol:udp domain:google.com`
|
||||
`(prop:expr)*
|
||||
*/
|
||||
export const parseTerms = (terms: string = "") :[string] | [] => {
|
||||
|
||||
const matches = terms.match(/([a-z]+[:>][\w\.]+)*/ig);
|
||||
|
||||
const exprs = matches.reduce((agg, term) => {
|
||||
|
||||
}, []);
|
||||
return [];
|
||||
};
|
||||
|
||||
export const fetchMetrics = async function ({
|
||||
start = sub(new Date(), { hours: 8 }),
|
||||
end = new Date(),
|
||||
key = "domain",
|
||||
interval = "30",
|
||||
} = {}) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
API_HOST(`metrics/stats?start=${getUnixTime(
|
||||
start
|
||||
)}&end=${getUnixTime(end)}&key=${key}&interval=${interval}`),
|
||||
{
|
||||
method: "GET",
|
||||
headers: { Accept: "application/json" }
|
||||
}
|
||||
);
|
||||
|
||||
const { success, payload } = await response.json();
|
||||
|
||||
if (!success) {
|
||||
return { error: payload };
|
||||
}
|
||||
|
||||
return { payload, interval, start, end, key };
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return { error: e };
|
||||
}
|
||||
};
|
||||
|
||||
export const metricsStore = readable([], (set) => {
|
||||
const interval = setInterval(async () => {
|
||||
const { error, payload } = await fetchMetrics({});
|
||||
if (error) {
|
||||
console.error(error);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(payload);
|
||||
set(payload);
|
||||
}, 15 * 1000);
|
||||
return () => clearInterval(interval);
|
||||
});
|
@ -1,9 +0,0 @@
|
||||
import { apiCall } from './util'
|
||||
|
||||
export interface Recursor {
|
||||
ipAddress: string
|
||||
timeoutMs: number
|
||||
weight: number
|
||||
}
|
||||
|
||||
export const getRecursors = () => apiCall<Recursor>('recursors')
|
@ -1,19 +0,0 @@
|
||||
import { apiCall } from './util'
|
||||
|
||||
export interface RuleAnswer {
|
||||
type: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface Rule {
|
||||
id: number
|
||||
weight: number
|
||||
enabled: boolean
|
||||
created: string
|
||||
name: string
|
||||
value: string
|
||||
answer: RuleAnswer
|
||||
ttl: number
|
||||
}
|
||||
|
||||
export const getRules = () => apiCall<Rule>('rules');
|
@ -1,19 +1,128 @@
|
||||
<script lang="ts">
|
||||
import LogViewer from "../components/LogViewer.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { navigate } from "svelte-routing";
|
||||
import { getUnixTime, isEqual, sub } from "date-fns";
|
||||
|
||||
import { buildQueryParams, fromUnixTimeSafe } from "../api/util";
|
||||
import { getLogs, getStats, StatSearchKey } from "../api";
|
||||
import type { Stat, Log } from "../api";
|
||||
|
||||
import PageContainer from "./PageContainer.svelte";
|
||||
import SearchOptions from "../components/SearchOptions.svelte";
|
||||
import TimeChart from "../components/TimeChart.svelte";
|
||||
import PageContainer from "./PageContainer.svelte";
|
||||
import LogViewer from "../components/LogViewer.svelte";
|
||||
|
||||
export let location: Location;
|
||||
|
||||
const { search } = location;
|
||||
let params = new URLSearchParams(search.substring(1));
|
||||
|
||||
export let start: Date =
|
||||
fromUnixTimeSafe(params.get("start")) || sub(new Date(), { hours: 24 });
|
||||
export let end: Date = fromUnixTimeSafe(params.get("end")) || new Date();
|
||||
|
||||
export let filter: string = params.get("filter") || "";
|
||||
export let chartKey: StatSearchKey =
|
||||
StatSearchKey[params.get("key")] || StatSearchKey.Domain;
|
||||
export let chartInterval: number = 30;
|
||||
export let logPage: number = 0;
|
||||
|
||||
let logErrorMsg: string = null;
|
||||
let chartErrorMsg: string = null;
|
||||
let chartDataLoading: Boolean = true;
|
||||
let logDataLoading: Boolean = true;
|
||||
|
||||
let chartData: Stat[] = [];
|
||||
let logData: Log[] = [];
|
||||
|
||||
const fetchLogs = async () => {
|
||||
if (logDataLoading) {
|
||||
console.warn("tried loading logs while already loading");
|
||||
}
|
||||
logErrorMsg = null;
|
||||
logDataLoading = true;
|
||||
const { error, payload } = await getLogs({
|
||||
start,
|
||||
end,
|
||||
page: logPage,
|
||||
filter,
|
||||
});
|
||||
logDataLoading = false;
|
||||
|
||||
if (error) {
|
||||
logErrorMsg = error;
|
||||
return [];
|
||||
}
|
||||
|
||||
return payload;
|
||||
};
|
||||
|
||||
const fetchStats = async () => {
|
||||
if (chartDataLoading) {
|
||||
console.warn("tried loading stats while already loading");
|
||||
}
|
||||
chartErrorMsg = null;
|
||||
chartDataLoading = true;
|
||||
const { error, payload } = await getStats({
|
||||
start,
|
||||
end,
|
||||
key: chartKey,
|
||||
interval: chartInterval,
|
||||
});
|
||||
chartDataLoading = false;
|
||||
|
||||
if (error) {
|
||||
chartErrorMsg = error;
|
||||
return [];
|
||||
}
|
||||
|
||||
return payload;
|
||||
};
|
||||
|
||||
const updateData = async (evt) => {
|
||||
console.groupCollapsed("Stats Data Update");
|
||||
const { filter: eFilter, start: eStart, end: eEnd, key: eKey } = evt;
|
||||
|
||||
navigate(
|
||||
`${location?.pathname}${buildQueryParams({
|
||||
start: getUnixTime(eStart),
|
||||
end: getUnixTime(eEnd),
|
||||
filter: eFilter,
|
||||
key: eKey,
|
||||
})}`,
|
||||
{ replace: true }
|
||||
);
|
||||
|
||||
[logData, chartData] = await Promise.all([fetchLogs(), fetchStats()]);
|
||||
console.info("handled search, fetching new data:", evt);
|
||||
console.groupEnd();
|
||||
};
|
||||
|
||||
$: updateData({ start, end, key: chartKey, filter });
|
||||
</script>
|
||||
|
||||
<PageContainer
|
||||
{location}
|
||||
header="Stats"
|
||||
description="Server performance stats and activity log"
|
||||
>
|
||||
<SearchOptions />
|
||||
<section class="my-5">
|
||||
<TimeChart />
|
||||
<SearchOptions bind:start bind:end bind:filter bind:key={chartKey} />
|
||||
<section style="height: 384px;" class="my-5">
|
||||
{#if chartDataLoading}
|
||||
<p>Loading chart</p>
|
||||
{:else if chartErrorMsg}
|
||||
<p>{chartErrorMsg}</p>
|
||||
{:else}
|
||||
<TimeChart stats={chartData} />
|
||||
{/if}
|
||||
</section>
|
||||
<section class="my-5">
|
||||
<LogViewer />
|
||||
{#if logDataLoading}
|
||||
<p>Loading logs</p>
|
||||
{:else if logErrorMsg}
|
||||
<p>{logErrorMsg}</p>
|
||||
{:else}
|
||||
<LogViewer logs={logData} />
|
||||
{/if}
|
||||
</section>
|
||||
</PageContainer>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"extends": "@tsconfig/svelte/tsconfig.json",
|
||||
|
||||
"types": ["node"],
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules/*", "__sapper__/*", "public/*"]
|
||||
}
|
||||
}
|
||||
|
Binary file not shown.
Loading…
Reference in new issue