eb86fdd182
Backend - regenerate_identity command stops the daemon, deletes priv_key.bin, leaves the user to restart for a fresh identity; falls back to the canonical XDG path when sidecar.key_path() isn't populated yet - tauri.conf.json ships the polkit policy via deb.files mapping; src-tauri/packaging/polkit/tech.threefold.mycellium-ui.policy declares the spawn action with auth_admin_keep so the dialog appears once per session Frontend - config store persists SidecarConfig (peers, tunName, noTun) through tauri-plugin-store; App.vue reads it and forwards to start_daemon, replacing the hard-coded defaults - Settings view: daemon-config form, identity panel with the destructive regenerate button, sidecar log viewer, About - README rewritten end-to-end: HTTP-loopback architecture, polkit install path, build commands, verification matrix, and a honest "known limitations" section
101 lines
2.4 KiB
TypeScript
101 lines
2.4 KiB
TypeScript
import { defineStore } from "pinia";
|
|
import { ref } from "vue";
|
|
import { api, type DaemonStatus, type NodeInfo, type SidecarConfig } from "@/lib/api";
|
|
import { Events, on } from "@/lib/events";
|
|
|
|
export type Phase = "idle" | "starting" | "ready" | "error";
|
|
|
|
export const useNodeStore = defineStore("node", () => {
|
|
const phase = ref<Phase>("idle");
|
|
const status = ref<DaemonStatus | null>(null);
|
|
const info = ref<NodeInfo | null>(null);
|
|
const error = ref<string | null>(null);
|
|
|
|
let exitedUnlisten: (() => void) | null = null;
|
|
let readyUnlisten: (() => void) | null = null;
|
|
|
|
async function bootstrap() {
|
|
if (!exitedUnlisten) {
|
|
exitedUnlisten = await on<number>(Events.SidecarExited, (e) => {
|
|
error.value = `daemon exited (code ${e.payload})`;
|
|
phase.value = "error";
|
|
status.value = { running: false, apiUrl: null, keyPath: null, configPath: null };
|
|
info.value = null;
|
|
});
|
|
}
|
|
if (!readyUnlisten) {
|
|
readyUnlisten = await on<string>(Events.SidecarReady, async () => {
|
|
await refresh();
|
|
});
|
|
}
|
|
|
|
const cur = await api.daemonStatus();
|
|
status.value = cur;
|
|
if (cur.running) {
|
|
phase.value = "ready";
|
|
try {
|
|
info.value = await api.nodeInfo();
|
|
} catch (e) {
|
|
error.value = String(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
async function start(config?: SidecarConfig) {
|
|
phase.value = "starting";
|
|
error.value = null;
|
|
try {
|
|
const s = await api.startDaemon(config);
|
|
status.value = s;
|
|
info.value = await api.nodeInfo();
|
|
phase.value = "ready";
|
|
} catch (e) {
|
|
error.value = String(e);
|
|
phase.value = "error";
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function stop() {
|
|
try {
|
|
const s = await api.stopDaemon();
|
|
status.value = s;
|
|
info.value = null;
|
|
phase.value = "idle";
|
|
} catch (e) {
|
|
error.value = String(e);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
async function refresh() {
|
|
status.value = await api.daemonStatus();
|
|
if (status.value.running) {
|
|
info.value = await api.nodeInfo();
|
|
phase.value = "ready";
|
|
} else {
|
|
info.value = null;
|
|
phase.value = "idle";
|
|
}
|
|
}
|
|
|
|
function dispose() {
|
|
exitedUnlisten?.();
|
|
readyUnlisten?.();
|
|
exitedUnlisten = null;
|
|
readyUnlisten = null;
|
|
}
|
|
|
|
return {
|
|
phase,
|
|
status,
|
|
info,
|
|
error,
|
|
bootstrap,
|
|
start,
|
|
stop,
|
|
refresh,
|
|
dispose,
|
|
};
|
|
});
|