149 lines
5.4 KiB
QML
149 lines
5.4 KiB
QML
pragma Singleton
|
|
|
|
import QtQuick
|
|
import Quickshell.Io
|
|
import "." as S
|
|
|
|
QtObject {
|
|
id: root
|
|
|
|
property var machines: []
|
|
|
|
// cache: machineName -> {state, units, loading}
|
|
property var _cache: ({})
|
|
|
|
readonly property bool anyUnhealthy: {
|
|
for (const k of Object.keys(_cache)) {
|
|
if ((_cache[k]?.units?.length ?? 0) > 0)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
function machineState(name) {
|
|
return _cache[name]?.state ?? "unknown";
|
|
}
|
|
function machineUnits(name) {
|
|
return _cache[name]?.units ?? [];
|
|
}
|
|
function machineLoading(name) {
|
|
return _cache[name]?.loading ?? false;
|
|
}
|
|
|
|
signal machineReady(string machineName, string state, var units)
|
|
signal machineJournalReady(string machineName, string unitName, string text)
|
|
|
|
function fetchMachine(name) {
|
|
const c = Object.assign({}, _cache);
|
|
c[name] = Object.assign({}, c[name] ?? {}, {
|
|
loading: true
|
|
});
|
|
_cache = c;
|
|
|
|
_machineProc._name = name;
|
|
_machineProc.command = ["sh", "-c", "busctl get-property --json=short --machine=" + name + " org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager SystemState 2>/dev/null || echo '{}'; " + "busctl call --json=short --machine=" + name + " org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager ListUnitsFiltered as 1 failed 2>/dev/null || echo '{}'"];
|
|
if (_machineProc.running)
|
|
_machineProc.running = false;
|
|
_machineProc.running = true;
|
|
}
|
|
|
|
function fetchMachineJournal(machineName, unitName) {
|
|
_machineJournalProc._machine = machineName;
|
|
_machineJournalProc._unit = unitName;
|
|
_machineJournalProc.command = ["journalctl", "-M", machineName, "-u", unitName, "-n", "80", "--no-pager", "--output=short-precise"];
|
|
if (_machineJournalProc.running)
|
|
_machineJournalProc.running = false;
|
|
_machineJournalProc.running = true;
|
|
}
|
|
|
|
function restartMachineUnit(machineName, unitName) {
|
|
_machineRestartProc._machine = machineName;
|
|
_machineRestartProc.command = ["pkexec", "systemctl", "-M", machineName, "restart", unitName];
|
|
if (_machineRestartProc.running)
|
|
_machineRestartProc.running = false;
|
|
_machineRestartProc.running = true;
|
|
}
|
|
|
|
property Timer _poll: Timer {
|
|
interval: S.Modules.machinectl.interval ?? 15000
|
|
running: S.Modules.machinectl.enable
|
|
repeat: true
|
|
triggeredOnStart: true
|
|
onTriggered: if (!_listProc.running)
|
|
_listProc.running = true
|
|
}
|
|
|
|
property Process _listProc: Process {
|
|
command: ["busctl", "call", "--json=short", "org.freedesktop.machine1", "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", "ListMachines"]
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
try {
|
|
const parsed = JSON.parse(text.trim());
|
|
const newMachines = (parsed.data || []).map(m => ({
|
|
name: m[0],
|
|
class: m[1],
|
|
service: m[2]
|
|
}));
|
|
root.machines = newMachines;
|
|
// drop stale cache entries
|
|
const names = new Set(newMachines.map(m => m.name));
|
|
const c = {};
|
|
for (const k of Object.keys(root._cache)) {
|
|
if (names.has(k))
|
|
c[k] = root._cache[k];
|
|
}
|
|
root._cache = c;
|
|
} catch (e) {
|
|
root.machines = [];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2 lines of output: state, failed-units
|
|
property Process _machineProc: Process {
|
|
property string _name: ""
|
|
stdout: StdioCollector {
|
|
onStreamFinished: {
|
|
const lines = text.trim().split("\n");
|
|
let state = "unknown";
|
|
let units = [];
|
|
try {
|
|
state = JSON.parse(lines[0] ?? "").data || "unknown";
|
|
} catch (e) {}
|
|
try {
|
|
const parsed = JSON.parse(lines[1] ?? "");
|
|
units = (parsed.data || []).map(u => ({
|
|
name: u[0],
|
|
description: u[1],
|
|
loadState: u[2],
|
|
activeState: u[3],
|
|
subState: u[4]
|
|
}));
|
|
} catch (e) {}
|
|
const c = Object.assign({}, root._cache);
|
|
c[root._machineProc._name] = {
|
|
state: state,
|
|
units: units,
|
|
loading: false
|
|
};
|
|
root._cache = c;
|
|
root.machineReady(root._machineProc._name, state, units);
|
|
}
|
|
}
|
|
}
|
|
|
|
property Process _machineJournalProc: Process {
|
|
property string _machine: ""
|
|
property string _unit: ""
|
|
stdout: StdioCollector {
|
|
onStreamFinished: root.machineJournalReady(root._machineJournalProc._machine, root._machineJournalProc._unit, text)
|
|
}
|
|
}
|
|
|
|
property Process _machineRestartProc: Process {
|
|
property string _machine: ""
|
|
onRunningChanged: if (!running && _machine !== "")
|
|
root.fetchMachine(_machine)
|
|
}
|
|
}
|