added promstats backend with charts
This commit is contained in:
parent
e8f09f7777
commit
2c2807d15c
10 changed files with 308 additions and 373 deletions
|
@ -2,5 +2,5 @@
|
|||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2024-11-01',
|
||||
devtools: { enabled: true },
|
||||
modules: ['@nuxtjs/tailwindcss'],
|
||||
modules: ['@nuxtjs/tailwindcss', 'nuxt-charts'],
|
||||
})
|
10
package.json
10
package.json
|
@ -11,16 +11,18 @@
|
|||
"password_gen": "node .password_hash_gen/generator.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"nuxt": "^3.15.4",
|
||||
"vue": "latest",
|
||||
"vue-router": "latest",
|
||||
"@nuxtjs/tailwindcss": "^6.13.1",
|
||||
"axios": "^1.7.9",
|
||||
"bcryptjs": "^3.0.0",
|
||||
"daisyui": "^4.12.23",
|
||||
"dotenv": "^16.4.7",
|
||||
"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": {
|
||||
"@types/jsonwebtoken": "^9.0.8"
|
||||
|
|
574
pages/index.vue
574
pages/index.vue
|
@ -1,248 +1,116 @@
|
|||
<script setup lang="ts">
|
||||
import type { VM } from '~/types/VM';
|
||||
import { reactive, ref } from 'vue';
|
||||
import axios from 'axios';
|
||||
import type {networkInterface} from "~/types/networkInterface";
|
||||
import type {serviceInterface} from "~/types/serviceInterface";
|
||||
import {checkAuth} from "~/util/auth";
|
||||
import { ref, computed, onMounted, onUnmounted } from 'vue'
|
||||
import axios from "axios";
|
||||
|
||||
|
||||
|
||||
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 {
|
||||
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 token = useCookie('token').value
|
||||
const response = await axios.post('/api/getMetrics', { token })
|
||||
|
||||
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
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
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({
|
||||
isLoaded: false,
|
||||
vms: [] as VM[],
|
||||
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({
|
||||
isLoaded: false,
|
||||
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);
|
||||
|
||||
}
|
||||
onUnmounted(() => {
|
||||
if (intervalId) clearInterval(intervalId)
|
||||
})
|
||||
|
||||
|
||||
|
||||
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>
|
||||
<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="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}">
|
||||
<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> {{ cpuInfo.speed }} GHz</p>
|
||||
<p><strong>Main Temp:</strong> {{ cpuInfo.mainTemp }} °C</p>
|
||||
<p><strong>Max Temp:</strong> {{ cpuInfo.maxTemp }} °C</p>
|
||||
<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 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>
|
||||
|
||||
<h1 v-if="settings.enable_qemu_controls" class="text-4xl font-bold text-center mb-6">QEMU Virtual Machines</h1>
|
||||
<div v-if="settings.enable_qemu_controls" class="form-control flex flex-row gap-2 mb-6">
|
||||
<label class="label cursor-pointer flex items-center gap-2">
|
||||
<span class="label-text">Force Shutdown</span>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="checkbox checkbox-primary"
|
||||
v-model="settings.force_shutdown"
|
||||
<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 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 class="form-control mt-4 flex flex-row gap-2">
|
||||
<button @click="startVm(vm)" class="btn btn-primary w-1/2">Start</button>
|
||||
<button
|
||||
@click="shutdownVm(vm)"
|
||||
:class="settings.force_shutdown ? 'btn btn-error w-1/2' : 'btn btn-warning w-1/2'"
|
||||
class="w-1/2">
|
||||
{{ settings.force_shutdown ? 'Kill' : 'Shutdown' }}
|
||||
</button>
|
||||
</div>
|
||||
</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 Clock</h2>
|
||||
<LineChart
|
||||
:data="chartDataCpuClock"
|
||||
data-key-x="date"
|
||||
data-key-y="value"
|
||||
:height="250"
|
||||
: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'
|
||||
|
||||
|
||||
<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>
|
||||
:x-tick-line='false'
|
||||
:y-tick-line='true'
|
||||
/>
|
||||
</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 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>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -24,5 +24,5 @@ export const settings = reactive({
|
|||
"libvirt",
|
||||
"frp"
|
||||
],
|
||||
password_hash: ""
|
||||
password_hash: "$2b$10$UO1FyIPODvf.VpGwHBvlq.RfVWOSJYRp/Hh88L306P/fNcXTG9WAC"
|
||||
});
|
|
@ -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);
|
||||
}
|
||||
});
|
|
@ -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
26
server/api/getMetrics.ts
Normal 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);
|
||||
}
|
||||
});
|
|
@ -1,14 +1,21 @@
|
|||
import si from 'systeminformation';
|
||||
import {checkValidJwtToken} from "~/core/command_auth";
|
||||
import { defineEventHandler, getCookie, createError } from 'h3';
|
||||
import {System} from "promstats";
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
const body = await readBody(event);
|
||||
const { token } = body;
|
||||
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) {
|
||||
console.error('Error fetching CPU info:', error);
|
||||
|
|
|
@ -4,9 +4,11 @@ import * as crypto from 'crypto';
|
|||
import {jwt_globals} from "~/core/globals";
|
||||
import Logger from "~/core/logger";
|
||||
import {settings} from "~/panel.config";
|
||||
import {setUrlEndpoint} from "promstats";
|
||||
|
||||
export default defineNitroPlugin((nitroApp) => {
|
||||
Logger.info("Running init...");
|
||||
setUrlEndpoint("http://192.168.178.128:9595")
|
||||
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");
|
||||
}
|
||||
|
|
13
types/MetricsResponse.ts
Normal file
13
types/MetricsResponse.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
interface MetricsResponse {
|
||||
cpu: {
|
||||
load: number
|
||||
maxClock: number
|
||||
minClock: number
|
||||
currentClock: number
|
||||
temp: number
|
||||
}
|
||||
ram: {
|
||||
used: number
|
||||
total: number
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue