agentmux_srv/broker/mod.rs
1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3
4//! This module hosts two independent brokers, sharing this top-level
5//! namespace deliberately: "broker" is this codebase's general name for
6//! "the one place that owns a fragmented concern and mediates access to
7//! it," applied twice on purpose, not a coincidence of naming.
8//! `broker::process` is the second application of that pattern, per
9//! `docs/specs/REPORT_PROCESS_ARCHITECTURE_STATE_AND_RETHINK_2026_07_22.md`'s
10//! ยง6.6 โ see that module's own doc comment for its scope.
11//!
12//! ## Credential Broker (`scheduler`) โ Phase A of the auth-architecture consolidation
13//!
14//! See `docs/specs/REPORT_AUTH_ARCHITECTURE_STATE_AND_RETHINK_2026_07_21.md`
15//! for the full rationale. AgentMux runs three independent OAuth/credential
16//! systems today (provider-CLI identity, MuxBus cloud login, an unused
17//! service-account OAuth scaffold) with no shared refresh or storage model.
18//! This module is the consolidation point: a single, generic,
19//! single-flight-guarded, proactively-scheduled refresher (`scheduler`),
20//! with each credential system registering its own load/refresh/save
21//! behavior against its own real backing store.
22//!
23//! **Phase A scope:** MuxBus is the only registered source (it's the only
24//! system that already does active token refresh today, so it's the
25//! smallest, lowest-risk slice to prove the broker out on). CLI-provider
26//! credentials and the service-account OAuth scaffold are future backends
27//! (Phase C+), not touched here.
28
29pub mod process;
30pub mod scheduler;
31pub mod state;
32
33pub use process::ProcessBroker;
34pub use scheduler::RefreshScheduler;
35pub use state::{CredentialState, RefreshErrorKind};
36
37use std::sync::{Arc, OnceLock};
38
39static GLOBAL_SCHEDULER: OnceLock<Arc<RefreshScheduler>> = OnceLock::new();
40
41/// Initialize the global **credential** broker scheduler and start its
42/// background sweep. Idempotent โ the sweep loop is spawned exactly once no
43/// matter how many times this is called; later calls just return the
44/// existing scheduler. Not to be confused with `process::set_global`/
45/// `process::global` (the unrelated Process Broker, see module doc above).
46pub fn init_global(sweep_interval: std::time::Duration) -> Arc<RefreshScheduler> {
47 GLOBAL_SCHEDULER
48 .get_or_init(|| {
49 let scheduler = Arc::new(RefreshScheduler::new());
50 tokio::spawn(scheduler.clone().run_sweep_loop(sweep_interval));
51 scheduler
52 })
53 .clone()
54}
55
56/// The global credential-broker scheduler, if `init_global` has already run.
57pub fn get_global() -> Option<Arc<RefreshScheduler>> {
58 GLOBAL_SCHEDULER.get().cloned()
59}