mirror of
https://github.com/kunkunsh/kunkun-ext-neohtop.git
synced 2025-04-03 17:36:41 +00:00
feat: Fully converted to kunkun extension
This commit is contained in:
parent
b3775dea23
commit
65baa6d367
2925
package-lock.json
generated
2925
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@
|
||||
"https://i.imgur.com/z2XWAPi.jpeg"
|
||||
],
|
||||
"permissions": [
|
||||
"system-info:process"
|
||||
"system-info:all"
|
||||
],
|
||||
"icon": {
|
||||
"type": "remote-url",
|
||||
@ -44,6 +44,7 @@
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.6.0",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.6.0",
|
||||
"@kksh/api": "^0.1.6",
|
||||
"@tauri-apps/api": "^2.0.3",
|
||||
"@tauri-apps/plugin-os": "^2.0.0",
|
||||
"@tauri-apps/plugin-shell": "^2.0.1",
|
||||
|
@ -1,12 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { getVersion } from "@tauri-apps/api/app";
|
||||
// import { getVersion } from "@tauri-apps/api/app";
|
||||
// import { version } from "../../../package.json";
|
||||
import { onMount } from "svelte";
|
||||
import { ThemeSwitcher } from "$lib/components";
|
||||
import { faInfo } from "@fortawesome/free-solid-svg-icons";
|
||||
import Fa from "svelte-fa";
|
||||
import { ASCII_ART, APP_INFO } from "$lib/constants";
|
||||
|
||||
let version = "";
|
||||
// @ts-ignore
|
||||
let version = __APP_VERSION__;
|
||||
let latestVersion = "";
|
||||
let showInfo = false;
|
||||
let hasUpdate = false;
|
||||
@ -48,11 +50,11 @@
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
version = await getVersion();
|
||||
await checkLatestVersion();
|
||||
// version = await getVersion();
|
||||
// await checkLatestVersion();
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize version info:", error);
|
||||
version = "";
|
||||
// console.error("Failed to initialize version info:", error);
|
||||
// version = "";
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
@ -7,21 +7,19 @@
|
||||
faChevronDown,
|
||||
faChevronRight,
|
||||
} from "@fortawesome/free-solid-svg-icons";
|
||||
import { platform } from "@tauri-apps/plugin-os";
|
||||
// import { platform } from "@tauri-apps/plugin-os";
|
||||
import { THEME_GROUPS } from "$lib/constants";
|
||||
|
||||
let showMenu = false;
|
||||
|
||||
const themeGroups = [
|
||||
...THEME_GROUPS,
|
||||
...(platform() === "windows" || platform() === "macos"
|
||||
? [
|
||||
...[
|
||||
{
|
||||
label: "Glassy",
|
||||
themes: ["glassy"],
|
||||
},
|
||||
]
|
||||
: []),
|
||||
],
|
||||
];
|
||||
</script>
|
||||
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { writable, derived } from "svelte/store";
|
||||
import type { Process, SystemStats } from "$lib/types";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { sysInfo } from "@kksh/api/ui/custom";
|
||||
import { processMonitor } from "$lib/utils/processMonitor";
|
||||
import { systemMonitor } from "$lib/utils/systemMonitor";
|
||||
|
||||
interface ProcessStore {
|
||||
processes: Process[];
|
||||
@ -53,18 +56,21 @@ function createProcessStore() {
|
||||
|
||||
const getProcesses = async () => {
|
||||
try {
|
||||
const result = await invoke<[Process[], SystemStats]>("get_processes");
|
||||
// const result = await invoke<[Process[], SystemStats]>("get_processes");
|
||||
const processes = await processMonitor.collectProcesses();
|
||||
const systemStats = await systemMonitor.collectStats();
|
||||
await sysInfo.refreshAll();
|
||||
update((state) => {
|
||||
let updatedSelectedProcess = state.selectedProcess;
|
||||
if (state.selectedProcessPid) {
|
||||
updatedSelectedProcess =
|
||||
result[0].find((p) => p.pid === state.selectedProcessPid) || null;
|
||||
processes.find((p) => p.pid === state.selectedProcessPid) || null;
|
||||
}
|
||||
|
||||
return {
|
||||
...state,
|
||||
processes: result[0],
|
||||
systemStats: result[1],
|
||||
processes,
|
||||
systemStats,
|
||||
error: null,
|
||||
selectedProcess: updatedSelectedProcess,
|
||||
};
|
||||
|
113
src/lib/utils/processMonitor.ts
Normal file
113
src/lib/utils/processMonitor.ts
Normal file
@ -0,0 +1,113 @@
|
||||
import type { Process } from "$lib/types";
|
||||
import { shell, sysInfo } from "@kksh/api/ui/custom";
|
||||
|
||||
type ProcessStaticInfo = {
|
||||
name: string;
|
||||
command: string;
|
||||
user: string;
|
||||
};
|
||||
|
||||
type ProcessStatus = Awaited<ReturnType<typeof sysInfo.processes>>[0]["status"];
|
||||
type DiskUsage = Awaited<ReturnType<typeof sysInfo.processes>>[0]["disk_usage"];
|
||||
|
||||
type ProcessData = {
|
||||
pid: number;
|
||||
name: string;
|
||||
cmd: string[];
|
||||
user_id: string | null;
|
||||
cpu_usage: number;
|
||||
memory: number;
|
||||
status: ProcessStatus;
|
||||
ppid: number | null;
|
||||
environ: string[];
|
||||
root: string;
|
||||
virtual_memory: number;
|
||||
start_time: number;
|
||||
run_time: number;
|
||||
disk_usage: DiskUsage;
|
||||
session_id: number | null;
|
||||
};
|
||||
|
||||
export class ProcessMonitor {
|
||||
process_cache: Map<number, ProcessStaticInfo>;
|
||||
|
||||
constructor() {
|
||||
this.process_cache = new Map();
|
||||
}
|
||||
|
||||
async collectProcesses(): Promise<Process[]> {
|
||||
const current_time = this.getCurrentTime();
|
||||
const processesData = await this.collectProcessData(current_time);
|
||||
return this.buildProcessInfo(processesData);
|
||||
}
|
||||
|
||||
async collectProcessData(current_time: number): Promise<ProcessData[]> {
|
||||
const processes = await sysInfo.processes();
|
||||
return processes.map((process) => {
|
||||
let start_time = process.start_time;
|
||||
return {
|
||||
pid: process.pid,
|
||||
name: process.name,
|
||||
cmd: process.cmd,
|
||||
user_id: process.user_id,
|
||||
cpu_usage: process.cpu_usage,
|
||||
memory: process.memory,
|
||||
status: process.status,
|
||||
ppid: process.parent,
|
||||
environ: process.environ,
|
||||
root: process.root ?? "",
|
||||
virtual_memory: process.virtual_memory,
|
||||
start_time: process.start_time,
|
||||
run_time: start_time > 0 ? current_time - start_time : 0,
|
||||
disk_usage: process.disk_usage,
|
||||
session_id: process.session_id,
|
||||
} satisfies ProcessData;
|
||||
});
|
||||
}
|
||||
|
||||
getCurrentTime(): number {
|
||||
return Math.floor(Date.now() / 1000); // Get current time in seconds since UNIX epoch
|
||||
}
|
||||
|
||||
killProcess(pid: number) {
|
||||
return shell.killPid(pid);
|
||||
}
|
||||
|
||||
buildProcessInfo(processesData: ProcessData[]): Process[] {
|
||||
return processesData.map((data) => {
|
||||
let cached_info = this.process_cache.get(data.pid);
|
||||
|
||||
if (!cached_info) {
|
||||
this.process_cache.set(data.pid, {
|
||||
name: data.name,
|
||||
command: data.cmd.join(" "),
|
||||
user: data.user_id || "-",
|
||||
});
|
||||
cached_info = this.process_cache.get(data.pid);
|
||||
}
|
||||
if (!cached_info) {
|
||||
throw new Error("Process info not found");
|
||||
}
|
||||
return {
|
||||
pid: data.pid,
|
||||
ppid: data.ppid || 0,
|
||||
name: cached_info.name,
|
||||
cpu_usage: data.cpu_usage,
|
||||
memory_usage: data.memory,
|
||||
status: data.status as string,
|
||||
user: cached_info.user,
|
||||
command: cached_info.command,
|
||||
threads: undefined,
|
||||
environ: data.environ,
|
||||
root: data.root,
|
||||
virtual_memory: data.virtual_memory,
|
||||
start_time: data.start_time,
|
||||
run_time: data.run_time,
|
||||
disk_usage: [data.disk_usage.read_bytes, data.disk_usage.written_bytes],
|
||||
session_id: data.session_id ?? undefined,
|
||||
} satisfies Process;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const processMonitor = new ProcessMonitor();
|
93
src/lib/utils/systemMonitor.ts
Normal file
93
src/lib/utils/systemMonitor.ts
Normal file
@ -0,0 +1,93 @@
|
||||
import type { SystemStats } from "$lib/types";
|
||||
import { sysInfo } from "@kksh/api/ui/custom";
|
||||
|
||||
export class SystemMonitor {
|
||||
last_network_update: [Date, number, number];
|
||||
|
||||
constructor() {
|
||||
this.last_network_update = [new Date(), 0, 0];
|
||||
}
|
||||
|
||||
async init() {
|
||||
await sysInfo.refreshAll();
|
||||
const networks = await sysInfo.networks();
|
||||
const initial_rx = networks.reduce(
|
||||
(acc, network) => acc + network.total_received,
|
||||
0,
|
||||
);
|
||||
const initial_tx = networks.reduce(
|
||||
(acc, network) => acc + network.total_transmitted,
|
||||
0,
|
||||
);
|
||||
this.last_network_update = [new Date(), initial_rx, initial_tx];
|
||||
}
|
||||
|
||||
async collectStats(): Promise<SystemStats> {
|
||||
let { rx_rate, tx_rate } = await this.calculateNetworkStats();
|
||||
let { disk_total, disk_used, disk_free } = await this.calculateDiskStats();
|
||||
const cpus = await sysInfo.cpus();
|
||||
const memory_total = await sysInfo.totalMemory();
|
||||
const memory_used = await sysInfo.usedMemory();
|
||||
const memory_free = memory_total - memory_used;
|
||||
const memory_cached =
|
||||
memory_total - (memory_used + (memory_total - memory_used));
|
||||
const uptime = await sysInfo.uptime();
|
||||
const load_avg = await sysInfo.loadAverage();
|
||||
return {
|
||||
cpu_usage: cpus.map((cpu) => cpu.cpu_usage),
|
||||
memory_total,
|
||||
memory_used,
|
||||
memory_free,
|
||||
memory_cached,
|
||||
uptime,
|
||||
load_avg: [load_avg.one, load_avg.five, load_avg.fifteen],
|
||||
network_rx_bytes: rx_rate,
|
||||
network_tx_bytes: tx_rate,
|
||||
disk_total_bytes: disk_total,
|
||||
disk_used_bytes: disk_used,
|
||||
disk_free_bytes: disk_free,
|
||||
};
|
||||
}
|
||||
|
||||
async calculateNetworkStats() {
|
||||
const networks = await sysInfo.networks();
|
||||
let current_rx = networks.reduce(
|
||||
(acc, network) => acc + network.total_received,
|
||||
0,
|
||||
);
|
||||
let current_tx = networks.reduce(
|
||||
(acc, network) => acc + network.total_transmitted,
|
||||
0,
|
||||
);
|
||||
|
||||
const elapsed =
|
||||
new Date().getTime() - this.last_network_update[0].getTime();
|
||||
const rx_rate =
|
||||
((current_rx - this.last_network_update[1]) / elapsed) * 1000;
|
||||
const tx_rate =
|
||||
((current_tx - this.last_network_update[2]) / elapsed) * 1000;
|
||||
|
||||
this.last_network_update = [new Date(), current_rx, current_tx];
|
||||
|
||||
return { rx_rate, tx_rate };
|
||||
}
|
||||
|
||||
async calculateDiskStats() {
|
||||
let disks = await sysInfo.disks();
|
||||
disks = disks.filter((disk) => disk.mount_point === "/");
|
||||
const disk_total = disks.reduce((acc, disk) => acc + disk.total_space, 0);
|
||||
const disk_used = disks.reduce(
|
||||
(acc, disk) => acc + disk.total_space - disk.available_space,
|
||||
0,
|
||||
);
|
||||
const disk_free = disks.reduce(
|
||||
(acc, disk) => acc + disk.available_space,
|
||||
0,
|
||||
);
|
||||
|
||||
return { disk_total, disk_used, disk_free };
|
||||
}
|
||||
}
|
||||
|
||||
export const systemMonitor = new SystemMonitor();
|
||||
systemMonitor.init();
|
@ -29,7 +29,7 @@
|
||||
sortConfig,
|
||||
} = $processStore);
|
||||
|
||||
let intervalId: number;
|
||||
let intervalId: number | NodeJS.Timeout;
|
||||
|
||||
$: columns = column_definitions.map((col) => ({
|
||||
...col,
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { defineConfig } from "vite";
|
||||
import { sveltekit } from "@sveltejs/kit/vite";
|
||||
import pkg from "./package.json";
|
||||
|
||||
const host = process.env.TAURI_DEV_HOST;
|
||||
|
||||
@ -32,4 +33,7 @@ export default defineConfig(async () => ({
|
||||
ignored: ["**/src-tauri/**"],
|
||||
},
|
||||
},
|
||||
define: {
|
||||
__APP_VERSION__: JSON.stringify(pkg.version),
|
||||
},
|
||||
}));
|
||||
|
Loading…
x
Reference in New Issue
Block a user