mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 00:02:23 +00:00
refactor(ui): rename RemoteConnections to HostLinks
Purely mechanical, plus the doc sentences that carry the model: the table holds one control link per machine, and the local machine is a machine like any other — its link just lives in its own global (LocalLink) because it is in-process rather than wire-backed. The old name framed the table as remote-only plumbing, which the tree migration made false in spirit: local and remote windows speak the same operations over whichever link their machine answers on.
This commit is contained in:
+1
-1
@@ -216,7 +216,7 @@ impl WorkspaceStore {
|
||||
let Some(host) = Self::remote_ref(cx, id) else {
|
||||
return true;
|
||||
};
|
||||
crate::ui::remote_connect::RemoteConnections::get(cx, host.host_id()).is_some()
|
||||
crate::ui::remote_connect::HostLinks::get(cx, host.host_id()).is_some()
|
||||
}
|
||||
|
||||
/// The client-side entry for `host` — the existing one if this machine has
|
||||
|
||||
@@ -308,10 +308,10 @@ fn probe_host(cx: &mut App, host: HostId, workspace: WorkspaceId) {
|
||||
//
|
||||
// Recorded as a landed failure rather than returned from: a bare `return`
|
||||
// would leave `needs_probe` true, so the next frame would re-decide this,
|
||||
// and `RemoteConnections::get` reaches its global mutably — which notifies,
|
||||
// and `HostLinks::get` reaches its global mutably — which notifies,
|
||||
// which repaints, which sweeps. Storing the answer puts the decision behind
|
||||
// the same TTL as every other one.
|
||||
if !host.is_local() && crate::ui::remote_connect::RemoteConnections::get(cx, host).is_none() {
|
||||
if !host.is_local() && crate::ui::remote_connect::HostLinks::get(cx, host).is_none() {
|
||||
cx.update_global::<PaneLivenessCache, _>(|cache, _| cache.finish_probe(host, None));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1599,7 +1599,7 @@ impl TerminalView {
|
||||
/// machine.** The host id comes off the workspace's own `RemoteTarget`,
|
||||
/// through the same `connection_key` the connection was opened under — so
|
||||
/// the id resolves to the very host object
|
||||
/// [`RemoteConnections::insert`](crate::ui::remote_connect::RemoteConnections::insert)
|
||||
/// [`HostLinks::insert`](crate::ui::remote_connect::HostLinks::insert)
|
||||
/// registered, with no second source of truth to drift from it. Setting the
|
||||
/// route and setting the host is one operation because a pane that ran its
|
||||
/// shell on one machine and its `git` on another would be worse than
|
||||
@@ -8053,7 +8053,7 @@ mod tests {
|
||||
/// (which needs a window, a daemon and a pane): the derivation under test is
|
||||
/// the target → `HostId` one, and pinning it here is what catches a future
|
||||
/// `set_workspace` that forgets the host half. The ids must agree with what
|
||||
/// `RemoteConnections::insert` registered — same `connection_key`, checked
|
||||
/// `HostLinks::insert` registered — same `connection_key`, checked
|
||||
/// by `connection_keys_match_the_contract_table` in `tty7-core`.
|
||||
#[test]
|
||||
fn a_panes_host_is_its_workspaces_machine() {
|
||||
|
||||
+1
-1
@@ -5894,7 +5894,7 @@ impl Tty7App {
|
||||
if !host.is_connected() {
|
||||
return None;
|
||||
}
|
||||
let home = crate::ui::remote_connect::RemoteConnections::home(cx, host_id)?;
|
||||
let home = crate::ui::remote_connect::HostLinks::home(cx, host_id)?;
|
||||
Some((host, Some(home)))
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
//! The GUI's control link to **this machine's own daemon**.
|
||||
//!
|
||||
//! Local and remote machines are the same thing seen from different distances:
|
||||
//! one machine, one daemon, one workspace tree, served over the control
|
||||
//! dialect. The remote half of that has always held a `ControlClient` per
|
||||
//! machine ([`crate::ui::remote_connect::RemoteConnections`]); this module is
|
||||
//! the local half — the link over which the GUI receives the local daemon's
|
||||
//! pushes (`ControlEvent::Layout` deltas, `Preempted`) and sends its semantic
|
||||
//! tree operations.
|
||||
//! one machine, one daemon, one workspace tree, one control link. The remote
|
||||
//! machines' links live in [`crate::ui::remote_connect::HostLinks`]; this
|
||||
//! module is the local machine's — the link over which the GUI receives the
|
||||
//! local daemon's pushes (`ControlEvent::Layout` deltas, `Preempted`) and
|
||||
//! sends its semantic tree operations.
|
||||
//!
|
||||
//! # Not a `RemoteConnections` entry
|
||||
//! # Not a `HostLinks` entry
|
||||
//!
|
||||
//! `RemoteConnections` doubles as the [`crate::ui::host_registry::HostRegistry`]
|
||||
//! `HostLinks` doubles as the [`crate::ui::host_registry::HostRegistry`]
|
||||
//! feeder: inserting there would register a *wire-backed* `Host` for this
|
||||
//! machine, while the local file tree and git must keep going through the
|
||||
//! in-process [`LocalHost`](tty7_core::host::local::LocalHost) — a socket
|
||||
|
||||
+22
-23
@@ -15,7 +15,7 @@
|
||||
//! | 2 | Resolve one into a self-contained SSH spec | [`spec_for`] |
|
||||
//! | 3 | Open a routed control connection through the local daemon | [`connect_blocking`] |
|
||||
//! | 4 | Read the machine's own workspace list | [`rows_from_list`] |
|
||||
//! | 5 | Hold the connection for the workspaces bound to it | [`RemoteConnections`] |
|
||||
//! | 5 | Hold the connection for the workspaces bound to it | [`HostLinks`] |
|
||||
//!
|
||||
//! ## Machines are configured once
|
||||
//!
|
||||
@@ -471,16 +471,21 @@ pub fn rows_from_machine(machine: &tty7_core::core::machine::Machine) -> Vec<Rem
|
||||
// 5. Holding the connections
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// The live remote machines, by [`HostId`].
|
||||
/// The live control links, by [`HostId`] — one per machine, one machine per
|
||||
/// entry.
|
||||
///
|
||||
/// One entry per *machine*, not per workspace — the same granularity the SSH
|
||||
/// connection is pooled at and the same one [`crate::ui::host_registry`] uses,
|
||||
/// so two windows on one box share a connection, a host object and a git-status
|
||||
/// cache. This table holds the concrete [`RemoteHost`] because pushing a layout
|
||||
/// needs its control client; `HostRegistry` holds the same object erased to
|
||||
/// `dyn Host` for the panels.
|
||||
/// The name says the model: every machine this client talks to is reached
|
||||
/// over exactly one control link, and the local machine is a machine like any
|
||||
/// other — its link simply lives in its own global
|
||||
/// ([`LocalLink`](crate::ui::local_link::LocalLink)) because it is in-process
|
||||
/// rather than wire-backed. One entry per *machine*, not per workspace — the
|
||||
/// same granularity the SSH connection is pooled at and the same one
|
||||
/// [`crate::ui::host_registry`] uses, so two windows on one box share a
|
||||
/// connection, a host object and a git-status cache. This table holds the
|
||||
/// concrete [`RemoteHost`] because pushing a layout needs its control client;
|
||||
/// `HostRegistry` holds the same object erased to `dyn Host` for the panels.
|
||||
#[derive(Default)]
|
||||
pub struct RemoteConnections {
|
||||
pub struct HostLinks {
|
||||
hosts: HashMap<HostId, Arc<RemoteHost>>,
|
||||
/// Each machine's `$HOME`, as its handshake reported it.
|
||||
///
|
||||
@@ -496,24 +501,18 @@ pub struct RemoteConnections {
|
||||
homes: HashMap<HostId, PathBuf>,
|
||||
}
|
||||
|
||||
impl Global for RemoteConnections {}
|
||||
impl Global for HostLinks {}
|
||||
|
||||
impl RemoteConnections {
|
||||
impl HostLinks {
|
||||
/// The connection to `id`, if this process has one.
|
||||
pub fn get(cx: &mut App, id: HostId) -> Option<Arc<RemoteHost>> {
|
||||
cx.default_global::<RemoteConnections>()
|
||||
.hosts
|
||||
.get(&id)
|
||||
.cloned()
|
||||
cx.default_global::<HostLinks>().hosts.get(&id).cloned()
|
||||
}
|
||||
|
||||
/// Where a *new* workspace on `id` would start: that machine's own `$HOME`,
|
||||
/// never this client's.
|
||||
pub fn home(cx: &mut App, id: HostId) -> Option<PathBuf> {
|
||||
cx.default_global::<RemoteConnections>()
|
||||
.homes
|
||||
.get(&id)
|
||||
.cloned()
|
||||
cx.default_global::<HostLinks>().homes.get(&id).cloned()
|
||||
}
|
||||
|
||||
/// Record a connection, and register the same object with the host registry
|
||||
@@ -525,14 +524,14 @@ impl RemoteConnections {
|
||||
pub fn insert(cx: &mut App, host: Arc<RemoteHost>, home: PathBuf) {
|
||||
let id = host.id();
|
||||
crate::ui::host_registry::HostRegistry::insert(cx, Arc::clone(&host).into_shared());
|
||||
let table = cx.default_global::<RemoteConnections>();
|
||||
let table = cx.default_global::<HostLinks>();
|
||||
table.hosts.insert(id, host);
|
||||
table.homes.insert(id, home);
|
||||
}
|
||||
|
||||
/// Drop a machine's connection once nothing is using it.
|
||||
pub fn remove(cx: &mut App, id: HostId) {
|
||||
let table = cx.default_global::<RemoteConnections>();
|
||||
let table = cx.default_global::<HostLinks>();
|
||||
table.hosts.remove(&id);
|
||||
table.homes.remove(&id);
|
||||
crate::ui::host_registry::HostRegistry::remove(cx, id);
|
||||
@@ -540,7 +539,7 @@ impl RemoteConnections {
|
||||
|
||||
/// Machines currently connected. Diagnostics and teardown.
|
||||
pub fn len(cx: &mut App) -> usize {
|
||||
cx.default_global::<RemoteConnections>().hosts.len()
|
||||
cx.default_global::<HostLinks>().hosts.len()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,7 +720,7 @@ pub fn register(cx: &mut App) {
|
||||
crate::daemon::router::set_route_auth_responder(Arc::new(GuiRouteAuth));
|
||||
// Touch the globals so the first connect isn't also the first allocation of
|
||||
// the table it writes into, on a thread that is holding a socket open.
|
||||
let _ = RemoteConnections::len(cx);
|
||||
let _ = HostLinks::len(cx);
|
||||
}
|
||||
|
||||
/// The oldest install waiting for an answer, if any.
|
||||
|
||||
+11
-11
@@ -661,10 +661,10 @@ impl Tty7App {
|
||||
rows: rows.clone(),
|
||||
},
|
||||
);
|
||||
remote_connect::RemoteConnections::insert(cx, connected.host, home.clone());
|
||||
remote_connect::HostLinks::insert(cx, connected.host, home.clone());
|
||||
self.prompt_remote_daemon_mismatch_later(cx);
|
||||
// Nothing left to *show* about the attempt: the machine is now
|
||||
// in `RemoteConnections` and its group in the switcher fills
|
||||
// in `HostLinks` and its group in the switcher fills
|
||||
// itself from there and from the snapshot above.
|
||||
self.connect = None;
|
||||
}
|
||||
@@ -762,7 +762,7 @@ impl Tty7App {
|
||||
return;
|
||||
};
|
||||
remote_connect::register(cx);
|
||||
if remote_connect::RemoteConnections::get(cx, host.host_id()).is_some() {
|
||||
if remote_connect::HostLinks::get(cx, host.host_id()).is_some() {
|
||||
// Another window on the same machine got there first. One connection
|
||||
// per machine is the point — D7's "connect immediately" is about the
|
||||
// *machine*, and a second link to it would be a second SSH session
|
||||
@@ -1038,7 +1038,7 @@ pub(crate) const PUMP_TICK: Duration = Duration::from_millis(250);
|
||||
/// One machine's link, as the supervisor sees it.
|
||||
///
|
||||
/// Per **machine**, not per workspace, because that is the granularity a
|
||||
/// connection actually has (`RemoteConnections` is keyed by [`HostId`], and two
|
||||
/// connection actually has (`HostLinks` is keyed by [`HostId`], and two
|
||||
/// windows on one box share a link). Preemption is the one thing that is
|
||||
/// per-workspace, and it is kept separately for exactly that reason.
|
||||
struct MachineLink {
|
||||
@@ -1234,7 +1234,7 @@ impl RemoteLinks {
|
||||
.preempted
|
||||
.remove(&workspace);
|
||||
}
|
||||
remote_connect::RemoteConnections::remove(cx, host);
|
||||
remote_connect::HostLinks::remove(cx, host);
|
||||
cx.default_global::<RemoteLinks>().machines.remove(&host);
|
||||
log::info!("disconnected from a machine at the user's request");
|
||||
cx.refresh_windows();
|
||||
@@ -1295,8 +1295,8 @@ fn pump_tick(cx: &mut gpui::App) -> bool {
|
||||
if suspended.contains(&host) {
|
||||
continue;
|
||||
}
|
||||
let live = remote_connect::RemoteConnections::get(cx, host)
|
||||
.is_some_and(|h| h.client().is_connected());
|
||||
let live =
|
||||
remote_connect::HostLinks::get(cx, host).is_some_and(|h| h.client().is_connected());
|
||||
let attempting = cx
|
||||
.try_global::<RemoteLinks>()
|
||||
.and_then(|l| l.machines.get(&host))
|
||||
@@ -1326,8 +1326,8 @@ fn pump_tick(cx: &mut gpui::App) -> bool {
|
||||
// The link is down. Drop the dead host object so nothing keeps calling
|
||||
// into it — a control connection that has gone is the whole
|
||||
// workspace's lifeline, not one failed request.
|
||||
if remote_connect::RemoteConnections::get(cx, host).is_some() {
|
||||
remote_connect::RemoteConnections::remove(cx, host);
|
||||
if remote_connect::HostLinks::get(cx, host).is_some() {
|
||||
remote_connect::HostLinks::remove(cx, host);
|
||||
log::info!("lost the control connection to {target}; reconnecting");
|
||||
}
|
||||
|
||||
@@ -1473,7 +1473,7 @@ fn reconnect_after_restart(origin: &str, cx: &mut gpui::App) {
|
||||
let Some(host) = remote_connect::origin_host(origin) else {
|
||||
return;
|
||||
};
|
||||
remote_connect::RemoteConnections::remove(cx, host);
|
||||
remote_connect::HostLinks::remove(cx, host);
|
||||
for (workspace, _) in workspaces_on(cx, host) {
|
||||
RemoteLinks::retry_now(cx, workspace);
|
||||
}
|
||||
@@ -1569,7 +1569,7 @@ fn finish_attempt(
|
||||
// comes back on after a restart or a dropped link, and dropping it
|
||||
// here is what left "New Workspace" missing on a machine the panel
|
||||
// was quite happily calling connected.
|
||||
remote_connect::RemoteConnections::insert(cx, connected.host, connected.home);
|
||||
remote_connect::HostLinks::insert(cx, connected.host, connected.home);
|
||||
for (id, _key) in workspaces_on(cx, host) {
|
||||
cx.default_global::<RemoteLinks>().preempted.remove(&id);
|
||||
if restarted {
|
||||
|
||||
+3
-3
@@ -218,7 +218,7 @@ pub(crate) struct HostSnapshot {
|
||||
/// it could never be given a group to appear in.
|
||||
pub target: RemoteTarget,
|
||||
/// What the remote said it had. The machine's `$HOME` is deliberately *not*
|
||||
/// here — it lives in `RemoteConnections`, app-wide, because every window
|
||||
/// here — it lives in `HostLinks`, app-wide, because every window
|
||||
/// needs it and only one of them ever did the connecting.
|
||||
pub rows: Vec<RemoteWorkspaceRow>,
|
||||
}
|
||||
@@ -454,7 +454,7 @@ impl Tty7App {
|
||||
// connect, and every reconnect, records the machine's `$HOME` — and
|
||||
// that row is the only way to make a workspace on a machine, so it
|
||||
// has no business depending on which window did the connecting.
|
||||
group.home = remote_connect::RemoteConnections::home(cx, id);
|
||||
group.home = remote_connect::HostLinks::home(cx, id);
|
||||
if let Some(snapshot) = self.host_snapshots.get(&id) {
|
||||
group.merge(&snapshot.rows, now);
|
||||
}
|
||||
@@ -489,7 +489,7 @@ impl Tty7App {
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
match remote_connect::RemoteConnections::get(cx, target.host_id()) {
|
||||
match remote_connect::HostLinks::get(cx, target.host_id()) {
|
||||
Some(_) => Link::Connected,
|
||||
None => Link::Offline,
|
||||
}
|
||||
|
||||
+2
-2
@@ -66,7 +66,7 @@ use crate::ui::pane::{Pane, PaneSlot};
|
||||
///
|
||||
/// The unification the whole design leans on: the local machine's link lives in
|
||||
/// [`LocalLink`](crate::ui::local_link::LocalLink), a remote machine's in
|
||||
/// [`RemoteConnections`](crate::ui::remote_connect::RemoteConnections), and
|
||||
/// [`HostLinks`](crate::ui::remote_connect::HostLinks), and
|
||||
/// everything above this function stops caring which. `None` is always
|
||||
/// transient (both holders have supervisors reconnecting), so callers treat it
|
||||
/// as "not now": mark dirty and let the re-pull that follows reconnection
|
||||
@@ -75,7 +75,7 @@ pub(crate) fn control_for(cx: &mut App, host: HostId) -> Option<Arc<ControlClien
|
||||
if host.is_local() {
|
||||
crate::ui::local_link::LocalLink::client(cx)
|
||||
} else {
|
||||
crate::ui::remote_connect::RemoteConnections::get(cx, host)
|
||||
crate::ui::remote_connect::HostLinks::get(cx, host)
|
||||
.map(|h| Arc::clone(h.client()))
|
||||
.filter(|c| c.is_connected())
|
||||
}
|
||||
|
||||
+1
-1
@@ -570,7 +570,7 @@ fn release_unused_hosts(cx: &mut App) {
|
||||
.collect();
|
||||
for id in crate::ui::host_registry::HostRegistry::ids(cx) {
|
||||
if !id.is_local() && !live.contains(&id) {
|
||||
crate::ui::remote_connect::RemoteConnections::remove(cx, id);
|
||||
crate::ui::remote_connect::HostLinks::remove(cx, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user