Files
Mycell-UI/src/stores/node.ts
T
syoul eb86fdd182 P5: settings, persistence, polkit packaging, README
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
2026-04-25 23:15:35 +02:00

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,
};
});