Skip to content

Commit c242f00

Browse files
committed
feat(ui): add heartbeat agent with auth gating
1 parent fc9a263 commit c242f00

File tree

6 files changed

+422
-7
lines changed

6 files changed

+422
-7
lines changed

cli/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,4 @@ humantime = "2.1.0"
1919
hickory-server = "0.25.2"
2020
hickory-proto = "0.25.2"
2121
iroh-base.workspace = true
22-
z32 = "1.0.3"
22+
z32 = "1.0.3"

lib/src/config.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub enum GatewayMode {
2727
Forward,
2828
}
2929

30-
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
30+
#[derive(Debug, Clone, Serialize, Deserialize)]
3131
#[serde(rename_all = "snake_case")]
3232
pub struct Config {
3333
/// The IPv4 address that the endpoint will listen on.
@@ -58,6 +58,9 @@ pub struct Config {
5858
#[serde(default)]
5959
pub dns_resolver: Option<SocketAddr>,
6060

61+
/// Enable the heartbeat agent for connector lease maintenance.
62+
#[serde(default = "default_heartbeat_enabled")]
63+
pub heartbeat_enabled: bool,
6164
}
6265

6366
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
@@ -70,6 +73,23 @@ pub struct GatewayConfig {
7073
pub gateway_mode: GatewayMode,
7174
}
7275

76+
fn default_heartbeat_enabled() -> bool {
77+
true
78+
}
79+
80+
impl Default for Config {
81+
fn default() -> Self {
82+
Self {
83+
ipv4_addr: None,
84+
ipv6_addr: None,
85+
discovery_mode: DiscoveryMode::default(),
86+
dns_origin: None,
87+
dns_resolver: None,
88+
heartbeat_enabled: default_heartbeat_enabled(),
89+
}
90+
}
91+
}
92+
7393
impl Config {
7494
pub async fn from_file(path: PathBuf) -> Result<Self> {
7595
let config = tokio::fs::read_to_string(path)

lib/src/datum_cloud/auth.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use openidconnect::{
1010
core::{CoreAuthenticationFlow, CoreClient, CoreProviderMetadata},
1111
};
1212
use serde::{Deserialize, Serialize};
13+
use tokio::sync::watch;
1314
use tracing::{debug, error, info, warn};
1415

1516
use crate::Repo;
@@ -327,37 +328,54 @@ impl MaybeAuth {
327328
struct AuthStateWrapper {
328329
inner: Arc<ArcSwap<MaybeAuth>>,
329330
repo: Option<Repo>,
331+
login_state_tx: watch::Sender<LoginState>,
330332
}
331333

332334
impl AuthStateWrapper {
333335
fn empty() -> Self {
336+
let (login_state_tx, _) = watch::channel(LoginState::Missing);
334337
Self {
335338
inner: Arc::new(ArcSwap::new(Default::default())),
336339
repo: None,
340+
login_state_tx,
337341
}
338342
}
339343

340344
async fn from_repo(repo: Repo) -> Result<Self> {
341345
let state = repo.read_oauth().await?;
346+
let (login_state_tx, _) = watch::channel(login_state_for(state.as_ref()));
342347
Ok(Self {
343348
inner: Arc::new(ArcSwap::new(Arc::new(MaybeAuth(state)))),
344349
repo: Some(repo),
350+
login_state_tx,
345351
})
346352
}
347353

348354
fn load(&self) -> Arc<MaybeAuth> {
349355
self.inner.load_full()
350356
}
351357

358+
fn subscribe_login_state(&self) -> watch::Receiver<LoginState> {
359+
self.login_state_tx.subscribe()
360+
}
361+
352362
async fn set(&self, auth: Option<AuthState>) -> Result<()> {
353363
if let Some(repo) = self.repo.as_ref() {
354364
repo.write_oauth(auth.as_ref()).await?;
355365
}
356366
self.inner.store(Arc::new(MaybeAuth(auth)));
367+
let _ = self.login_state_tx.send(login_state_for(self.load().get().ok()));
357368
Ok(())
358369
}
359370
}
360371

372+
fn login_state_for(auth: Option<&AuthState>) -> LoginState {
373+
match auth {
374+
None => LoginState::Missing,
375+
Some(state) => state.tokens.login_state(),
376+
}
377+
}
378+
361379
#[derive(derive_more::Debug, Clone)]
362380
pub struct AuthClient {
363381
state: AuthStateWrapper,
@@ -394,6 +412,10 @@ impl AuthClient {
394412
self.state.load()
395413
}
396414

415+
pub fn login_state_watch(&self) -> watch::Receiver<LoginState> {
416+
self.state.subscribe_login_state()
417+
}
418+
397419
pub async fn load_refreshed(&self) -> Result<Arc<MaybeAuth>> {
398420
let state = self.state.load();
399421
match state.get() {

0 commit comments

Comments
 (0)