syoul 0c9277f687 feat(ui): expose full overlay IP on Status page
The /api/v1/admin endpoint only returns the /64 subnet. Users were
copy-pasting the subnet straight into Compose Message and getting
HTTP 422 from the daemon (\"invalid IP address syntax\"). The full
host part (lower 64 bits) is logged once at boot:

    INFO mycelium: Node overlay IP: 43d:956e:7877:d933:eecc:b305:21ff:77f9

Capture it from stdout, surface as a new daemonStatus.overlayIp
field, and render it on Status above the subnet card with the hint
\"use this when sending messages\".

The line carries ANSI colour escapes from tracing's compact format,
so push_log strips SGR sequences before scanning. Hand-rolled to
avoid pulling a regex crate.

Also rebuilds the .deb release artifact.
2026-04-26 02:11:42 +02:00
2026-04-26 01:30:26 +02:00

mycellium-ui

Cross-platform desktop GUI for Mycelium — Threefold's end-to-end encrypted IPv6 overlay network.

The app embeds the official mycelium binary as a Tauri sidecar and pilots it through its HTTP API on a loopback ephemeral port. Root privileges (required to create the TUN interface) are obtained via pkexec.

Status

v1, Linux-only. Implements the full docs/api.yaml surface of mycelium v0.6.1: admin, peers (CRUD), routes (selected/fallback/queried), messages (send/receive/reply/status), topics (default + whitelist + sources + forward), pubkey lookup.

Architecture

┌──────────────────────────────────────────────────────────────┐
│  WebView (Vue 3 + TS + Tailwind + radix-vue + Pinia)         │
│  Status / Peers / Routes / Messages / Topics / Settings      │
└────────────────┬─────────────────────────────────────────────┘
                 │  invoke() / Tauri events
┌────────────────┴─────────────────────────────────────────────┐
│  Tauri core (Rust, tokio + reqwest)                          │
│  • sidecar.rs — supervises mycelium via pkexec               │
│  • api/* — typed REST client                                 │
│  • poller.rs — emits peers://, stats://, routes://, messages://incoming │
└────────────────┬─────────────────────────────────────────────┘
                 │  HTTP loopback :ephemeral
┌────────────────┴─────────────────────────────────────────────┐
│  mycelium daemon (sidecar binary, runs as root via pkexec)   │
│  TUN0 ◄─► overlay network                                    │
└──────────────────────────────────────────────────────────────┘

There is no Unix socket / named pipe IPC — the daemon's own HTTP API is the integration point.

Prerequisites (Debian / Ubuntu)

sudo apt install -y \
  libwebkit2gtk-4.1-dev libjavascriptcoregtk-4.1-dev \
  libsoup-3.0-dev libayatana-appindicator3-dev librsvg2-dev \
  build-essential curl wget file libssl-dev libgtk-3-dev libxdo-dev \
  pkg-config policykit-1
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y

Then Node 20+ and pnpm 10+.

Setup

# 1. Install JS deps
pnpm install

# 2. Fetch the mycelium sidecar binary for your target triple
bash scripts/fetch-mycelium.sh           # uses MYCELIUM_VERSION (default v0.6.1)
# or: MYCELIUM_VERSION=v0.6.1 bash scripts/fetch-mycelium.sh

# 3. Run in dev
pnpm tauri dev

The first start triggers a pkexec dialog asking you to authenticate; the polkit policy installed by the .deb caches the auth for the user session.

Build

pnpm tauri build               # → src-tauri/target/release/bundle/{deb,appimage}/

The .deb declares Depends: policykit-1 and ships the polkit policy under /usr/share/polkit-1/actions/tech.threefold.mycellium-ui.policy. The AppImage relies on pkexec being present on the host — on systems without polkit, fall back to running with sudo after disabling the sidecar's pkexec wrapper.

Layout

src/                     # Vue 3 frontend
  views/                 # one file per nav item
  components/            # shadcn-style UI primitives + dialogs
  stores/                # Pinia: node, peers, routes, messages, topics, config
  lib/                   # api wrapper, events, base64 + format helpers
src-tauri/
  src/
    sidecar.rs           # spawn + supervise mycelium
    elevation.rs         # pkexec command builder
    poller.rs            # 3 background loops (peers, routes, inbox long-poll)
    api/                 # REST client modules (admin, peers, routes,
                         #   messages, topics, pubkey)
    commands.rs          # #[tauri::command] handlers, 1:1 with REST
    error.rs             # AppError + Serialize-as-string for invoke()
  binaries/              # gitignored; populated by scripts/fetch-mycelium.sh
  packaging/polkit/      # XML policy bundled into the .deb
scripts/fetch-mycelium.sh
.github/workflows/ci.yml # pnpm typecheck + cargo fmt/clippy/test

Verification matrix

Test How
Sidecar starts under pkexec pnpm tauri dev, daemon visible in ps, splash disappears in <10 s
Peers connect Add tcp://188.40.132.242:9651 from the Peers page; state turns to alive within ~10 s
Routes propagate Routes/Selected becomes non-empty after ~30 s
Live event stream Sidebar status dot tracks ready/idle, peers table updates without manual refresh
Bidirectional messages Two instances on different VMs, exchange via Compose → Inbox
Identity regen Settings → Regenerate; restart daemon; new IP appears on Status
.deb install Fresh Ubuntu LTS / Debian 12; daemon spawns under polkit on first start

Known limitations (v1)

  • Linux only. Windows is reachable (sidecar via runas / Wintun driver) but not implemented.
  • Auto-start at login isn't wired — the desktop entry installed by the .deb is the manual launcher.
  • The TOML config editor in Settings only exposes peers, tunName, noTun. Other keys (metricsApiAddress, etc.) are passed-through if you edit the file directly at ~/.local/share/tech.threefold.mycellium-ui/mycelium.toml and restart the daemon.
  • message_status is forwarded as opaque JSON; the upstream schema isn't pinned in the spec, so we don't strongly type it.
Description
No description provided
Readme 53 MiB
Languages
Rust 39.8%
Vue 39.3%
TypeScript 17.3%
Shell 2.2%
CSS 1.1%
Other 0.2%