Added footer and memory usage.
This commit is contained in:
parent
a7be040dea
commit
859f17ccc5
|
@ -9,6 +9,7 @@
|
||||||
"d2sqlite3": "~>1.0.0",
|
"d2sqlite3": "~>1.0.0",
|
||||||
"handy-httpd": "~>7.9.3",
|
"handy-httpd": "~>7.9.3",
|
||||||
"jwt": "~>0.4.0",
|
"jwt": "~>0.4.0",
|
||||||
|
"resusage": "~>0.3.2",
|
||||||
"slf4d": "~>2.4.2"
|
"slf4d": "~>2.4.2"
|
||||||
},
|
},
|
||||||
"description": "API for the litelist application.",
|
"description": "API for the litelist application.",
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"httparsed": "1.2.1",
|
"httparsed": "1.2.1",
|
||||||
"jwt": "0.4.0",
|
"jwt": "0.4.0",
|
||||||
"memutils": "1.0.9",
|
"memutils": "1.0.9",
|
||||||
|
"resusage": "0.3.2",
|
||||||
"slf4d": "2.4.2",
|
"slf4d": "2.4.2",
|
||||||
"streams": "3.5.0"
|
"streams": "3.5.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,9 +57,7 @@ private HttpServer initServer() {
|
||||||
immutable string API_PATH = "/api";
|
immutable string API_PATH = "/api";
|
||||||
|
|
||||||
auto mainHandler = new PathDelegatingHandler();
|
auto mainHandler = new PathDelegatingHandler();
|
||||||
mainHandler.addMapping(Method.GET, API_PATH ~ "/status", (ref HttpRequestContext ctx) {
|
mainHandler.addMapping(Method.GET, API_PATH ~ "/status", &handleStatus);
|
||||||
ctx.response.writeBodyString("online");
|
|
||||||
});
|
|
||||||
|
|
||||||
auto optionsHandler = toHandler((ref HttpRequestContext ctx) {
|
auto optionsHandler = toHandler((ref HttpRequestContext ctx) {
|
||||||
ctx.response.setStatus(HttpStatus.OK);
|
ctx.response.setStatus(HttpStatus.OK);
|
||||||
|
@ -82,3 +80,16 @@ private HttpServer initServer() {
|
||||||
|
|
||||||
return new HttpServer(mainHandler, config);
|
return new HttpServer(mainHandler, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleStatus(ref HttpRequestContext ctx) {
|
||||||
|
import resusage;
|
||||||
|
import std.process;
|
||||||
|
import std.json;
|
||||||
|
|
||||||
|
immutable int pId = thisProcessID();
|
||||||
|
ProcessMemInfo procInfo = processMemInfo(pId);
|
||||||
|
JSONValue data = JSONValue(string[string].init);
|
||||||
|
data.object["virtualMemory"] = JSONValue(procInfo.usedVirtMem);
|
||||||
|
data.object["physicalMemory"] = JSONValue(procInfo.usedRAM);
|
||||||
|
ctx.response.writeBodyString(data.toString(), "application/json");
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1,20 @@
|
||||||
export const API_URL = import.meta.env.VITE_API_URL
|
export const API_URL = import.meta.env.VITE_API_URL
|
||||||
|
|
||||||
|
export interface StatusInfo {
|
||||||
|
virtualMemory: number
|
||||||
|
physicalMemory: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getStatus(): Promise<StatusInfo | null> {
|
||||||
|
try {
|
||||||
|
const response = await fetch(API_URL + "/status")
|
||||||
|
if (response.ok) {
|
||||||
|
return await response.json()
|
||||||
|
}
|
||||||
|
console.warn("Non-OK status response: ", response.status)
|
||||||
|
return null
|
||||||
|
} catch (error: any) {
|
||||||
|
console.error(error)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,11 +3,37 @@ This is a generic container to wrap around a page's content to keep it within
|
||||||
a mobile-friendly width.
|
a mobile-friendly width.
|
||||||
-->
|
-->
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import type {Ref} from "vue";
|
||||||
|
import {onMounted, ref} from "vue";
|
||||||
|
import type {StatusInfo} from "@/api/base";
|
||||||
|
import {getStatus} from "@/api/base";
|
||||||
|
import {humanFileSize} from "@/util";
|
||||||
|
|
||||||
|
const statusInfo: Ref<StatusInfo | null> = ref(null)
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
statusInfo.value = await getStatus()
|
||||||
|
setInterval(async () => {
|
||||||
|
statusInfo.value = await getStatus()
|
||||||
|
}, 5000)
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="page-container">
|
<div class="page-container">
|
||||||
<slot/>
|
<slot/>
|
||||||
|
<!-- Each contained page also gets a nice little footer! -->
|
||||||
|
<footer style="text-align: center">
|
||||||
|
<p style="font-size: smaller">
|
||||||
|
LiteList created with ❤️ by
|
||||||
|
<a href="https://andrewlalis.com" target="_blank">Andrew Lalis</a>
|
||||||
|
using <a href="https://vuejs.org/" target="_blank">🌿 Vue 3</a> and
|
||||||
|
<a href="https://github.com/andrewlalis/handy-httpd" target="_blank">🌎 Handy-Httpd</a>.
|
||||||
|
</p>
|
||||||
|
<p v-if="statusInfo" style="font-size: smaller; font-family: monospace;">
|
||||||
|
Memory used: <span v-text="humanFileSize(statusInfo.physicalMemory, true, 1)"></span>
|
||||||
|
</p>
|
||||||
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
|
@ -25,3 +25,35 @@ export function getSecondsTilExpire(token: string): number {
|
||||||
const decoded = parseJwt(token)
|
const decoded = parseJwt(token)
|
||||||
return decoded.exp - now
|
return decoded.exp - now
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format bytes as human-readable text.
|
||||||
|
*
|
||||||
|
* @param bytes Number of bytes.
|
||||||
|
* @param si True to use metric (SI) units, aka powers of 1000. False to use
|
||||||
|
* binary (IEC), aka powers of 1024.
|
||||||
|
* @param dp Number of decimal places to display.
|
||||||
|
*
|
||||||
|
* @return Formatted string.
|
||||||
|
*/
|
||||||
|
export function humanFileSize(bytes, si=false, dp=1) {
|
||||||
|
const thresh = si ? 1000 : 1024;
|
||||||
|
|
||||||
|
if (Math.abs(bytes) < thresh) {
|
||||||
|
return bytes + ' B';
|
||||||
|
}
|
||||||
|
|
||||||
|
const units = si
|
||||||
|
? ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
|
||||||
|
: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB'];
|
||||||
|
let u = -1;
|
||||||
|
const r = 10**dp;
|
||||||
|
|
||||||
|
do {
|
||||||
|
bytes /= thresh;
|
||||||
|
++u;
|
||||||
|
} while (Math.round(Math.abs(bytes) * r) / r >= thresh && u < units.length - 1);
|
||||||
|
|
||||||
|
|
||||||
|
return bytes.toFixed(dp) + ' ' + units[u];
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue