Added footer and memory usage.
This commit is contained in:
parent
a7be040dea
commit
859f17ccc5
|
@ -9,6 +9,7 @@
|
|||
"d2sqlite3": "~>1.0.0",
|
||||
"handy-httpd": "~>7.9.3",
|
||||
"jwt": "~>0.4.0",
|
||||
"resusage": "~>0.3.2",
|
||||
"slf4d": "~>2.4.2"
|
||||
},
|
||||
"description": "API for the litelist application.",
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
"httparsed": "1.2.1",
|
||||
"jwt": "0.4.0",
|
||||
"memutils": "1.0.9",
|
||||
"resusage": "0.3.2",
|
||||
"slf4d": "2.4.2",
|
||||
"streams": "3.5.0"
|
||||
}
|
||||
|
|
|
@ -57,9 +57,7 @@ private HttpServer initServer() {
|
|||
immutable string API_PATH = "/api";
|
||||
|
||||
auto mainHandler = new PathDelegatingHandler();
|
||||
mainHandler.addMapping(Method.GET, API_PATH ~ "/status", (ref HttpRequestContext ctx) {
|
||||
ctx.response.writeBodyString("online");
|
||||
});
|
||||
mainHandler.addMapping(Method.GET, API_PATH ~ "/status", &handleStatus);
|
||||
|
||||
auto optionsHandler = toHandler((ref HttpRequestContext ctx) {
|
||||
ctx.response.setStatus(HttpStatus.OK);
|
||||
|
@ -82,3 +80,16 @@ private HttpServer initServer() {
|
|||
|
||||
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 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.
|
||||
-->
|
||||
<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>
|
||||
|
||||
<template>
|
||||
<div class="page-container">
|
||||
<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>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -25,3 +25,35 @@ export function getSecondsTilExpire(token: string): number {
|
|||
const decoded = parseJwt(token)
|
||||
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