Compare commits

...
Sign in to create a new pull request.

1 commit

Author SHA1 Message Date
2c2807d15c added promstats backend with charts 2025-06-16 20:29:41 +02:00
10 changed files with 308 additions and 373 deletions

View file

@ -2,5 +2,5 @@
export default defineNuxtConfig({ export default defineNuxtConfig({
compatibilityDate: '2024-11-01', compatibilityDate: '2024-11-01',
devtools: { enabled: true }, devtools: { enabled: true },
modules: ['@nuxtjs/tailwindcss'], modules: ['@nuxtjs/tailwindcss', 'nuxt-charts'],
}) })

View file

@ -11,16 +11,18 @@
"password_gen": "node .password_hash_gen/generator.js" "password_gen": "node .password_hash_gen/generator.js"
}, },
"dependencies": { "dependencies": {
"nuxt": "^3.15.4",
"vue": "latest",
"vue-router": "latest",
"@nuxtjs/tailwindcss": "^6.13.1", "@nuxtjs/tailwindcss": "^6.13.1",
"axios": "^1.7.9", "axios": "^1.7.9",
"bcryptjs": "^3.0.0", "bcryptjs": "^3.0.0",
"daisyui": "^4.12.23", "daisyui": "^4.12.23",
"dotenv": "^16.4.7", "dotenv": "^16.4.7",
"jsonwebtoken": "^9.0.2", "jsonwebtoken": "^9.0.2",
"systeminformation": "^5.25.11" "nuxt": "^3.15.4",
"nuxt-charts": "^0.1.10",
"promstats": "^1.0.1",
"systeminformation": "^5.25.11",
"vue": "latest",
"vue-router": "latest"
}, },
"devDependencies": { "devDependencies": {
"@types/jsonwebtoken": "^9.0.8" "@types/jsonwebtoken": "^9.0.8"

View file

@ -1,248 +1,116 @@
<script setup lang="ts"> <script setup lang="ts">
import type { VM } from '~/types/VM'; import { ref, computed, onMounted, onUnmounted } from 'vue'
import { reactive, ref } from 'vue'; import axios from "axios";
import axios from 'axios';
import type {networkInterface} from "~/types/networkInterface";
import type {serviceInterface} from "~/types/serviceInterface";
import {checkAuth} from "~/util/auth";
const startVm = async (vm: any) => {
const POLL_INTERVAL_MS = 30000
const MAX_POINTS = 10
interface AreaChartItem {
date: string
value: number
pinned: number
}
const cpuLoadData = ref<AreaChartItem[]>([])
const cpuClockData = ref<AreaChartItem[]>([])
const cpuTempData = ref<AreaChartItem[]>([])
const ramLoadData = ref<AreaChartItem[]>([])
let intervalId: number | undefined
let isUpdating = false
async function updateMetrics() {
if (isUpdating) return
isUpdating = true
try { try {
const response = await axios.post('/api/controlVM', {
action: 'start',
token: useCookie('token').value,
vm: vm
});
console.log(response.data);
if(response.data.status == 'success') {
vmInfo.vms.forEach(vm_list => {
if(vm.name == vm_list.name) {
vm_list.state = "on";
}
})
}
} catch (error) {
console.error(`Error starting VM: ${vm.name}`, error);
}
};
const shutdownVm = async (vm: any) => {
try {
const response = await axios.post('/api/controlVM', {
action: 'shutdown',
force: settings.force_shutdown,
token: useCookie('token').value,
vm: vm
});
console.log(response.data);
if(response.data.status == 'success') {
vmInfo.vms.forEach(vm_list => {
if(vm.name == vm_list.name) {
vm_list.state = "off";
}
})
}
} catch (error) {
console.error(`Error shutting down VM: ${vm.name}`, error);
}
};
const settings = reactive({
ignoreCache: false,
enable_services: false,
enable_qemu_controls: false,
force_shutdown: false
});
const vmInfo = reactive({ const token = useCookie('token').value
isLoaded: false, const response = await axios.post('/api/getMetrics', { token })
vms: [] as VM[],
const load = response.data.cpu?.load || 0
const curClock = response.data.cpu?.currentClock || 0
const maxClock = response.data.cpu?.maxClock || 0
const cpuTemp = response.data.cpu?.temp || 0
const ramLoad = response.data.ram?.used || 0
const ramTotal = response.data.ram?.total || 0
const now = new Date().toLocaleTimeString()
cpuLoadData.value = [...cpuLoadData.value, { date: now, value: load, pinned: 100 }].slice(-MAX_POINTS)
cpuClockData.value = [...cpuClockData.value, { date: now, value: curClock, pinned: maxClock }].slice(-MAX_POINTS)
cpuTempData.value = [...cpuTempData.value, { date: now, value: cpuTemp, pinned: 100 }].slice(-MAX_POINTS)
ramLoadData.value = [...ramLoadData.value, { date: now, value: ramLoad, pinned: ramTotal }].slice(-MAX_POINTS)
} finally {
isUpdating = false
}
}
onMounted(() => {
const empty1 = Array(MAX_POINTS).fill({ date: '', value: 0, pinned: 100 })
//cpuLoadData.value = [...empty1]
updateMetrics()
setTimeout(() => {
updateMetrics(); // Second call after 2 seconds
}, 1010);
intervalId = window.setInterval(updateMetrics, POLL_INTERVAL_MS)
}) })
const osInfo = reactive({ onUnmounted(() => {
isLoaded: false, if (intervalId) clearInterval(intervalId)
name: '',
version: '',
kernel: '',
architecture: ''
});
const serviceInfo = reactive({
isLoaded: false,
services: [] as serviceInterface[],
});
const cpuInfo = reactive({
isLoaded: false,
manufacturer: '',
model: '',
cores: 0,
speed: 0,
mainTemp: 0,
maxTemp: 0
});
const memoryInfo = reactive({
isLoaded: false,
total: 0,
free: 0,
used: 0
});
const networkInfo = reactive({
isLoaded: true,
interfacesList:[] as networkInterface[]
})
const fetchServiceInfo = async () => {
try{
//let services = await $fetch('/api/getServices')
const response = await axios.post('/api/getServices', {
token: useCookie('token').value
});
let services = response.data;
services?.forEach((interface_obj: serviceInterface) => {
serviceInfo.services.push(interface_obj)
});
serviceInfo.isLoaded = true;
}catch(error){
console.error(`Error fetchOsInfo: ${error}`);
}
}
const fetchNetworkInfo = async () => {
try{
const response = await axios.post('/api/getNetworkInterfaces', {
token: useCookie('token').value
});
let networkInfoFetch = response.data;
networkInfoFetch?.forEach((interface_obj: networkInterface) => {
networkInfo.interfacesList.push(interface_obj)
});
networkInfo.isLoaded = true
}catch(error){
console.error(`Error fetchOsInfo: ${error}`);
}
}
const fetchOsInfo = async () => {
try{
const response = await axios.post('/api/getSystem', {
token: useCookie('token').value
});
let systemInfoFetch = response.data;
console.log(systemInfoFetch)
osInfo.name = systemInfoFetch?.platform || 'N/A'
osInfo.version = systemInfoFetch?.distro || 'N/A'
osInfo.kernel = systemInfoFetch?.kernel || 'N/A'
osInfo.architecture = systemInfoFetch?.arch || 'N/A'
osInfo.isLoaded = true
}catch(error){
console.error(`Error fetchOsInfo: ${error}`);
}
}
const fetchCpuTemp = async () => {
try {
const response = await axios.post('/api/getCpu', {
token: useCookie('token').value
});
let cpuInfoFetch = response.data;
console.log(cpuInfoFetch)
cpuInfo.manufacturer = cpuInfoFetch?.info.manufacturer || 'N/A'
cpuInfo.model = cpuInfoFetch?.info.brand || 'N/A'
cpuInfo.cores = cpuInfoFetch?.info.cores || 0
cpuInfo.speed = cpuInfoFetch?.info.speed || 0
cpuInfo.mainTemp = cpuInfoFetch?.temps.main || 0
cpuInfo.maxTemp = cpuInfoFetch?.temps.max || 0
} catch (error) {
console.error('Error fetching CPU temperature:', error);
}
};
const fetchMemoryInfo = async () => {
try{
const response = await axios.post('/api/getMemory', {
token: useCookie('token').value
});
let memoryInfoFetch = response.data;
console.log(memoryInfoFetch)
let ram_cache = settings.ignoreCache ? (memoryInfoFetch?.cached ?? 0) : 0;
if(memoryInfoFetch?.total != null)
memoryInfo.total = Math.round( memoryInfoFetch?.total/ (1024 * 1024 * 1024)) || 0
if(memoryInfoFetch?.free != null)
memoryInfo.free = Math.round( (memoryInfoFetch?.free + ram_cache) / (1024 * 1024 * 1024)) || 0
if(memoryInfoFetch?.used != null)
memoryInfo.used = Math.round( (memoryInfoFetch?.used - ram_cache) / (1024 * 1024 * 1024)) || 0
memoryInfo.isLoaded = true
}catch(error){
console.error(`Error fetchOsInfo: ${error}`);
}
}
const fetchVMs = async () => {
try{
const response = await axios.post('/api/getVMs', {
token: useCookie('token').value
});
let vmInfoFetch = response.data;
console.log(vmInfoFetch)
vmInfoFetch?.forEach((vm: VM) => {
vmInfo.vms.push(vm)
})
vmInfo.isLoaded = true
}catch(error){
console.error(`Error fetchOsInfo: ${error}`);
}
}
const fetchSettings = async () => {
try {
const response = await axios.post('/api/getSettings', {
token: useCookie('token').value
});
let settingsFetch = response.data;
console.log(settingsFetch)
settings.ignoreCache = settingsFetch?.ignoreCache || false
settings.enable_qemu_controls = settingsFetch?.enable_qemu_controls || false
settings.enable_services = settingsFetch?.enable_services || false
} catch (error) {
console.error('Error fetching CPU temperature:', error);
}
}
let intervalId: NodeJS.Timeout;
onMounted(async () => {
let isAuthed = await checkAuth(useRouter())
if(isAuthed){
await fetchSettings()
if(settings.enable_qemu_controls) await fetchVMs()
await fetchOsInfo()
await fetchCpuTemp()
cpuInfo.isLoaded = true
await fetchMemoryInfo()
await fetchNetworkInfo()
if(settings.enable_services) await fetchServiceInfo()
intervalId = setInterval(fetchCpuTemp, 7000);
}
}) })
onBeforeUnmount(()=>{
clearInterval(intervalId);
})
const chartDataCpuUsage = computed(() => cpuLoadData.value)
const chartCategoriesCpuUsage = computed(() => ({
value: { name: 'CPU Load (%)', color: '#863bf6' },
pinned: { name: 'Limit (100%)', color: 'rgba(0,0,0,0.01)' },
}))
const xFormatterCpuUsage = (i: number) => chartDataCpuUsage.value[i]?.date || ''
const chartDataCpuClock = computed(() => cpuClockData.value)
const chartCategoriesCpuClock = computed(() => ({
value: { name: 'CPU Clock (Ghz)', color: '#9cf63b' },
pinned: { name: 'CPU Max Clock (Ghz)', color: 'rgba(0,0,0,0.01)' },
}))
const xFormatterCpuClock = (i: number) => chartDataCpuClock.value[i]?.date || ''
const chartDataCpuTemp = computed(() => cpuTempData.value)
const chartCategoriesCpuTemp = computed(() => ({
value: { name: 'CPU Temp (°C)', color: '#f63b3b' },
pinned: { name: 'Max Temp (°C)', color: 'rgba(0,0,0,0.01)' },
}))
const xFormatterCpuTemp = (i: number) => chartDataCpuTemp.value[i]?.date || ''
const chartDataRamUsage = computed(() => ramLoadData.value)
const chartCategoriesRamUsage = computed(() => ({
value: { name: 'RAM Used (Gb)', color: '#f63b6d' },
pinned: { name: 'RAM Total (Gb)', color: 'rgba(0,0,0,0.01)' },
}))
const xFormatterRamUsage = (i: number) => chartDataRamUsage.value[i]?.date || ''
@ -252,111 +120,167 @@ onBeforeUnmount(()=>{
<template> <template>
<div class="flex flex-col items-center justify-center py-16 px-6"> <div class="flex flex-col items-center justify-center py-16 px-6">
<div class="grid md:grid-cols-3 gap-6 w-full max-w-5xl mb-8"> <div class="grid md:grid-cols-3 gap-6 w-full max-w-5xl mb-8">
<div class="card bg-base-100 shadow-2xl p-6 transition-opacity duration-500 ease-in-out">
<div class="card bg-base-100 shadow-2xl p-6 opacity-0 transition-opacity duration-500 ease-in-out"
:class="{'opacity-100': osInfo.isLoaded}">
<h2 class="text-xl font-bold text-center">OS Info</h2>
<div class="mt-4 text-sm">
<p><strong>Operating System:</strong> {{ osInfo.name }}</p>
<p><strong>Version:</strong> {{ osInfo.version }}</p>
<p><strong>Kernel:</strong> {{ osInfo.kernel }}</p>
<p><strong>Architecture:</strong> {{ osInfo.architecture }}</p>
</div>
</div>
<div class="card bg-base-100 shadow-2xl p-6 opacity-0 transition-opacity duration-500 ease-in-out"
:class="{'opacity-100': cpuInfo.isLoaded}">
<h2 class="text-xl font-bold text-center">CPU Info</h2> <h2 class="text-xl font-bold text-center">CPU Info</h2>
<div class="mt-4 text-sm"> <div class="mt-4 text-sm">
<p><strong>Manufacturer:</strong> {{ cpuInfo.manufacturer }}</p> <p><strong>Manufacturer:</strong> cpuInfo.manufacturer</p>
<p><strong>Model:</strong> {{ cpuInfo.model }}</p> <p><strong>Model:</strong> cpuInfo.model</p>
<p><strong>Core Count:</strong> {{ cpuInfo.cores }}</p> <p><strong>Core Count:</strong> cpuInfo.cores</p>
<p><strong>Speed:</strong> {{ cpuInfo.speed }} GHz</p> <p><strong>Speed:</strong> puInfo.speed GHz</p>
<p><strong>Main Temp:</strong> {{ cpuInfo.mainTemp }} °C</p> <p><strong>Main Temp:</strong> cpuInfo.mainTemp °C</p>
<p><strong>Max Temp:</strong> {{ cpuInfo.maxTemp }} °C</p> <p><strong>Max Temp:</strong> cpuInfo.maxTemp °C</p>
</div>
</div>
<div class="card bg-base-100 shadow-2xl p-6 opacity-0 transition-opacity duration-500 ease-in-out"
:class="{'opacity-100': memoryInfo.isLoaded}">
<h2 class="text-xl font-bold text-center">Memory Info</h2>
<div class="mt-4 text-sm">
<p><strong>Total Memory:</strong> {{ memoryInfo.total }} GB</p>
<p><strong>Free Memory:</strong> {{ memoryInfo.free }} GB</p>
<p><strong>Used Memory:</strong> {{ memoryInfo.used }} GB</p>
</div>
</div>
<div v-for="ifs in networkInfo.interfacesList" class="card bg-base-100 shadow-2xl p-6">
<h2 :class="{
'text-green-500': ifs.state === 'up',
'text-red-500': ifs.state === 'down',
'text-yellow-500': ifs.state === 'unknown'
}"
class="text-xl font-bold text-center">Interface: {{ ifs.name }}</h2>
<div class="mt-4 text-sm">
<p><strong>Interface Name:</strong> {{ ifs.name }}</p>
<p><strong>IPv4:</strong> {{ ifs.ip4 }} / {{ ifs.ip4subnet }}</p>
<p><strong>IPv6:</strong> {{ ifs.ip6 }}</p>
<p><strong>State:</strong> {{ ifs.state }}</p>
</div>
</div> </div>
</div> </div>
<h1 v-if="settings.enable_qemu_controls" class="text-4xl font-bold text-center mb-6">QEMU Virtual Machines</h1> <div class="card bg-base-100 shadow-2xl p-6 transition-opacity duration-500 ease-in-out">
<div v-if="settings.enable_qemu_controls" class="form-control flex flex-row gap-2 mb-6"> <h2 class="text-xl font-bold text-center">CPU Info</h2>
<label class="label cursor-pointer flex items-center gap-2"> <div class="mt-4 text-sm">
<span class="label-text">Force Shutdown</span> <p><strong>Manufacturer:</strong> cpuInfo.manufacturer</p>
<input <p><strong>Model:</strong> cpuInfo.model</p>
type="checkbox" <p><strong>Core Count:</strong> cpuInfo.cores</p>
class="checkbox checkbox-primary" <p><strong>Speed:</strong> puInfo.speed GHz</p>
v-model="settings.force_shutdown" <p><strong>Main Temp:</strong> cpuInfo.mainTemp °C</p>
<p><strong>Max Temp:</strong> cpuInfo.maxTemp °C</p>
</div>
</div>
<div class="card bg-base-100 shadow-2xl p-6 transition-opacity duration-500 ease-in-out">
<h2 class="text-xl font-bold text-center">CPU Info</h2>
<div class="mt-4 text-sm">
<p><strong>Manufacturer:</strong> cpuInfo.manufacturer</p>
<p><strong>Model:</strong> cpuInfo.model</p>
<p><strong>Core Count:</strong> cpuInfo.cores</p>
<p><strong>Speed:</strong> puInfo.speed GHz</p>
<p><strong>Main Temp:</strong> cpuInfo.mainTemp °C</p>
<p><strong>Max Temp:</strong> cpuInfo.maxTemp °C</p>
</div>
</div>
<div class="card bg-base-100 shadow-2xl p-6 transition-opacity duration-500 ease-in-out">
<h2 class="text-xl font-bold text-center">CPU Usage</h2>
<LineChart
:data="chartDataCpuUsage"
data-key-x="date"
data-key-y="value"
:height="250"
:categories="chartCategoriesCpuUsage"
:x-formatter="xFormatterCpuUsage"
:curve-type="CurveType.MonotoneX"
:legend-position="LegendPosition.Top"
:hide-legend="true"
:y-min="0"
:y-max="100"
:x-num-ticks='5'
:y-num-ticks='5'
:x-grid-line='false'
:y-grid-line='false'
:x-domain-line='true'
:y-domain-line='true'
:x-tick-line='false'
:y-tick-line='true'
/> />
</label>
</div>
<div v-if="settings.enable_qemu_controls" class="grid md:grid-cols-3 gap-6 w-full max-w-5xl mb-8">
<div
v-for="vm in vmInfo.vms"
class="card bg-base-100 shadow-2xl p-6"
>
<h2 :class="vm.state === 'on' ? 'text-green-500' : 'text-red-500'" class="text-xl font-bold text-center">
{{ vm.name }}
</h2>
<div class="mt-2 text-sm">
<p><strong>OS:</strong> {{ vm.os }}</p>
<p><strong>CPU(s):</strong> {{ vm.vCpuCount }}</p>
<p><strong>Max Memory:</strong> {{ vm.maxMemory }} MB</p>
<p><strong>Autostart:</strong> {{ vm.autostart ? 'Enabled' : 'Disabled' }}</p>
</div> </div>
<div class="form-control mt-4 flex flex-row gap-2"> <div class="card bg-base-100 shadow-2xl p-6 transition-opacity duration-500 ease-in-out">
<button @click="startVm(vm)" class="btn btn-primary w-1/2">Start</button> <h2 class="text-xl font-bold text-center">CPU Clock</h2>
<button <LineChart
@click="shutdownVm(vm)" :data="chartDataCpuClock"
:class="settings.force_shutdown ? 'btn btn-error w-1/2' : 'btn btn-warning w-1/2'" data-key-x="date"
class="w-1/2"> data-key-y="value"
{{ settings.force_shutdown ? 'Kill' : 'Shutdown' }} :height="250"
</button> :categories="chartCategoriesCpuClock"
:x-formatter="xFormatterCpuClock"
:curve-type="CurveType.MonotoneX"
:legend-position="LegendPosition.Top"
:hide-legend="true"
:y-min="0"
:y-max="100"
:x-num-ticks='5'
:y-num-ticks='5'
:x-grid-line='false'
:y-grid-line='false'
:x-domain-line='true'
:y-domain-line='true'
:x-tick-line='false'
:y-tick-line='true'
/>
</div> </div>
<div class="card bg-base-100 shadow-2xl p-6 transition-opacity duration-500 ease-in-out">
<h2 class="text-xl font-bold text-center">CPU Temp</h2>
<LineChart
:data="chartDataCpuTemp"
data-key-x="date"
data-key-y="value"
:height="250"
:categories="chartCategoriesCpuTemp"
:x-formatter="xFormatterCpuTemp"
:curve-type="CurveType.MonotoneX"
:legend-position="LegendPosition.Top"
:hide-legend="true"
:y-min="0"
:y-max="100"
:x-num-ticks='5'
:y-num-ticks='5'
:x-grid-line='false'
:y-grid-line='false'
:x-domain-line='true'
:y-domain-line='true'
:x-tick-line='false'
:y-tick-line='true'
/>
</div> </div>
<div class="card bg-base-100 shadow-2xl p-6 transition-opacity duration-500 ease-in-out">
<h2 class="text-xl font-bold text-center">Ram Usage</h2>
<LineChart
:data="chartDataRamUsage"
data-key-x="date"
data-key-y="value"
:height="250"
:categories="chartCategoriesRamUsage"
:x-formatter="xFormatterRamUsage"
:curve-type="CurveType.MonotoneX"
:legend-position="LegendPosition.Top"
:hide-legend="true"
:y-min="0"
:y-max="100"
:x-num-ticks='5'
:y-num-ticks='5'
:x-grid-line='false'
:y-grid-line='false'
:x-domain-line='true'
:y-domain-line='true'
:x-tick-line='false'
:y-tick-line='true'
/>
</div> </div>
<h1 v-if="serviceInfo.isLoaded" class="text-4xl font-bold text-center mb-6">Services</h1>
<div v-if="serviceInfo.isLoaded" class="grid md:grid-cols-3 gap-6 w-full max-w-5xl">
<div
v-for="service in serviceInfo.services"
class="card bg-base-100 shadow-2xl p-6">
<h2 :class="service.state === true ? 'text-green-500' : 'text-red-500'" class="text-xl font-bold text-center">
{{ service.name }}
</h2>
<div class="mt-2 text-sm">
<p><strong>Name:</strong> {{ service.name }}</p>
<p><strong>State:</strong> {{ service.state ? "Running" : "Not Running" }}</p>
</div>
</div>
</div> </div>
</div> </div>
</template> </template>

View file

@ -24,5 +24,5 @@ export const settings = reactive({
"libvirt", "libvirt",
"frp" "frp"
], ],
password_hash: "" password_hash: "$2b$10$UO1FyIPODvf.VpGwHBvlq.RfVWOSJYRp/Hh88L306P/fNcXTG9WAC"
}); });

View file

@ -1,22 +0,0 @@
import { defineEventHandler, getCookie, createError } from 'h3';
import si from 'systeminformation';
import {checkValidJwtToken} from "~/core/command_auth";
export default defineEventHandler(async (event) => {
try {
const body = await readBody(event);
const { token } = body;
checkValidJwtToken(token)
const cpuData = await si.cpu();
const cpuTemp = await si.cpuTemperature();
return {
info: cpuData, // `info` is the key, `cpuData` is the value
temps: cpuTemp // `temps` is the key, `cpuTemp` is the value
};
} catch (error) {
console.error('Error fetching CPU info:', error);
}
});

View file

@ -1,17 +0,0 @@
import si from 'systeminformation';
import {checkValidJwtToken} from "~/core/command_auth";
import { defineEventHandler, getCookie, createError } from 'h3';
export default defineEventHandler(async (event) => {
try {
const body = await readBody(event);
const { token } = body;
checkValidJwtToken(token)
const memoryData = await si.mem();
return memoryData;
} catch (error) {
console.error('Error fetching CPU info:', error);
}
});

26
server/api/getMetrics.ts Normal file
View file

@ -0,0 +1,26 @@
import { defineEventHandler, getCookie, createError } from 'h3';
import si from 'systeminformation';
import {checkValidJwtToken} from "~/core/command_auth";
import {CPU, RAM} from "promstats";
export default defineEventHandler(async (event) => {
try {
//console.log("metrics called")
return {
cpu: {
load: await CPU.getCpuLoad(),
maxClock: await CPU.getMaxCpuClockGHz(),
minClock: await CPU.getMinCpuClockGHz(),
currentClock: await CPU.getCurrentCpuClockGHz(),
temp: await CPU.getAverageTemp(),
},
ram:{
used: await RAM.getUsedMemory(),
total: await RAM.getTotalMemory()
}
}
} catch (error) {
console.error('Error fetching CPU info:', error);
}
});

View file

@ -1,14 +1,21 @@
import si from 'systeminformation'; import si from 'systeminformation';
import {checkValidJwtToken} from "~/core/command_auth"; import {checkValidJwtToken} from "~/core/command_auth";
import { defineEventHandler, getCookie, createError } from 'h3'; import { defineEventHandler, getCookie, createError } from 'h3';
import {System} from "promstats";
export default defineEventHandler(async (event) => { export default defineEventHandler(async (event) => {
try { try {
const body = await readBody(event); const body = await readBody(event);
const { token } = body; const { token } = body;
checkValidJwtToken(token) checkValidJwtToken(token)
const systemData = await si.osInfo(); const osName = await System.getOsName();
const osVersion = await System.getKernelVersion();
const osArch = await System.getMachineArchitecture()
return systemData; return {
name: osName,
version: osVersion,
arch: osArch,
};
} catch (error) { } catch (error) {
console.error('Error fetching CPU info:', error); console.error('Error fetching CPU info:', error);

View file

@ -4,9 +4,11 @@ import * as crypto from 'crypto';
import {jwt_globals} from "~/core/globals"; import {jwt_globals} from "~/core/globals";
import Logger from "~/core/logger"; import Logger from "~/core/logger";
import {settings} from "~/panel.config"; import {settings} from "~/panel.config";
import {setUrlEndpoint} from "promstats";
export default defineNitroPlugin((nitroApp) => { export default defineNitroPlugin((nitroApp) => {
Logger.info("Running init..."); Logger.info("Running init...");
setUrlEndpoint("http://192.168.178.128:9595")
if(settings.password_hash == ""){ if(settings.password_hash == ""){
throw new Error("The password hash is missing. Please use \"npm run password_gen <password>\" to set the password and then \"npm run build\" rebuild the server files"); throw new Error("The password hash is missing. Please use \"npm run password_gen <password>\" to set the password and then \"npm run build\" rebuild the server files");
} }

13
types/MetricsResponse.ts Normal file
View file

@ -0,0 +1,13 @@
interface MetricsResponse {
cpu: {
load: number
maxClock: number
minClock: number
currentClock: number
temp: number
}
ram: {
used: number
total: number
}
}