Extract the connect/reconnect decision into a Qt-free module #123

Closed
opened 2026-08-22 23:01:12 -04:00 by mysticalsoap · 2 comments
Owner

After #111 the reconnect is the last piece of network-change handling still living in the gui: connect_last_server (plus what it reaches — choose_random_server, connect_profile, last_server.json handling) is policy any client should be able to run, but it is welded into AqomuiGui.

That points at the working metric for what belongs outside the gui: if a feature would have to be recreated for the cli, it does not belong in the gui. Ideally cli and gui expose the same features, the gui being a front end for editing configuration and choosing servers.

Scope

A Qt-free module owning the reconnect/connect decision — read last_server.json, resolve random/profile/favourite modes into concrete server dicts, honour autoconnect — per the #83 placement rule that modules a cli entry point imports stay Qt-free.

  • Gui is the first consumer, behaviour-preserving: connect_last_server maps the decision onto its own connect actions. Progress bars and status handling stay with the gui.
  • Cli gains selection options on connect (random, random favourite, profile): the same decision, invoked once.

Tangled with the #83 seam-3 server-catalog model, since random/profile resolution needs the catalog.

Not in scope

When the decision fires. The cli is a one-shot process and can never watch for network changes, and the trigger currently exists only in the gui — so autoconnect silently does nothing without a gui running. That is an ownership question, split out as #191, which consumes this module rather than replacing it.

Follow-up to #111; fits the #83 decomposition series.

After #111 the reconnect is the last piece of network-change handling still living in the gui: `connect_last_server` (plus what it reaches — `choose_random_server`, `connect_profile`, `last_server.json` handling) is policy any client should be able to run, but it is welded into AqomuiGui. That points at the working metric for what belongs outside the gui: **if a feature would have to be recreated for the cli, it does not belong in the gui.** Ideally cli and gui expose the same features, the gui being a front end for editing configuration and choosing servers. ## Scope A Qt-free module owning the reconnect/connect **decision** — read `last_server.json`, resolve random/profile/favourite modes into concrete server dicts, honour autoconnect — per the #83 placement rule that modules a cli entry point imports stay Qt-free. - **Gui is the first consumer, behaviour-preserving**: `connect_last_server` maps the decision onto its own connect actions. Progress bars and status handling stay with the gui. - **Cli gains selection options on connect** (random, random favourite, profile): the same decision, invoked once. Tangled with the #83 seam-3 server-catalog model, since random/profile resolution needs the catalog. ## Not in scope *When* the decision fires. The cli is a one-shot process and can never watch for network changes, and the trigger currently exists only in the gui — so autoconnect silently does nothing without a gui running. That is an ownership question, split out as #191, which consumes this module rather than replacing it. Follow-up to #111; fits the #83 decomposition series.
Author
Owner

Design investigation before starting. Two findings narrow this issue and split a second one out of it (#191).

The cli can never own a reconnect trigger

It is a one-shot process. Most commands sys.exit(0) immediately, and even --connect enters the Qt event loop only until connection_established or conn_attempt_failed arrives, then calls app.quit() (aqomui_cli.py:283-295). Nothing in the cli is alive when a network change happens later.

So "the cli cannot offer autoconnect" conflates three separable things:

  1. The decision — resolve last_server.json + settings + catalog into a concrete server dict. Pure, Qt-free, genuinely shared. This is what the issue describes and what stays here.
  2. The trigger — requires a long-lived process. Gui startup, or the network-change signal. The cli can never own it.
  3. The execution — progress bars and status (gui) vs print-and-exit (cli).

For the cli, (1) plus a one-shot (3) is the whole feature: selection options on connect (random, random favourite, profile), each running the decision once.

The gap underneath

The trigger only exists in the gui, and autoconnect is a global setting in ROOTDIR/config.json that the cli can toggle. So the setting silently does nothing without a gui running: connect via the cli, or close the gui, and a network change tears the tunnel down (#111) with nothing to bring it back. A Qt-free module does not fix that — it is an ownership question, now #191.

What other clients do

Checked because it bears directly on where the trigger belongs. Across Tailscale, NetworkManager, wg-quick/openvpn units and Mullvad, the daemon is the real app and the gui is a thin client — closing the gui never disables autoconnect. qomui's gui-owned design is the outlier. Details and the security constraint that comes with it (the state a daemon acts on unattended must be daemon-owned) are in #191.

That does not change this issue's scope: the decision module is wanted either way, and #191 gives it a third consumer rather than replacing it.

Design investigation before starting. Two findings narrow this issue and split a second one out of it (#191). ## The cli can never own a reconnect trigger It is a one-shot process. Most commands `sys.exit(0)` immediately, and even `--connect` enters the Qt event loop only until `connection_established` or `conn_attempt_failed` arrives, then calls `app.quit()` (aqomui_cli.py:283-295). Nothing in the cli is alive when a network change happens later. So "the cli cannot offer autoconnect" conflates three separable things: 1. **The decision** — resolve `last_server.json` + settings + catalog into a concrete server dict. Pure, Qt-free, genuinely shared. This is what the issue describes and what stays here. 2. **The trigger** — requires a long-lived process. Gui startup, or the network-change signal. The cli can never own it. 3. **The execution** — progress bars and status (gui) vs print-and-exit (cli). For the cli, (1) plus a one-shot (3) is the whole feature: selection options on connect (random, random favourite, profile), each running the decision once. ## The gap underneath The trigger only exists in the gui, and `autoconnect` is a *global* setting in `ROOTDIR/config.json` that the cli can toggle. So the setting silently does nothing without a gui running: connect via the cli, or close the gui, and a network change tears the tunnel down (#111) with nothing to bring it back. A Qt-free module does not fix that — it is an ownership question, now #191. ## What other clients do Checked because it bears directly on where the trigger belongs. Across Tailscale, NetworkManager, wg-quick/openvpn units and Mullvad, the daemon is the real app and the gui is a thin client — closing the gui never disables autoconnect. qomui's gui-owned design is the outlier. Details and the security constraint that comes with it (the state a daemon acts on unattended must be daemon-owned) are in #191. That does not change this issue's scope: the decision module is wanted either way, and #191 gives it a third consumer rather than replacing it.
mysticalsoap changed title from Extract reconnect/autoconnect into a Qt-free class the cli can use to Extract the connect/reconnect decision into a Qt-free module 2026-08-28 11:43:05 -04:00
Author
Owner

Done across PRs #192 (module + gui consumer + cli selection modes) and the follow-up parity fixes in #193. Trigger ownership continues in #191.

Done across PRs #192 (module + gui consumer + cli selection modes) and the follow-up parity fixes in #193. Trigger ownership continues in #191.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
mysticalsoap/aqomui#123
No description provided.