diff --git a/Cargo.lock b/Cargo.lock index 43de093..33e2510 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3151,6 +3151,7 @@ dependencies = [ "elevated-command", "event-listener 5.4.0", "futures-concurrency", + "futures-intrusive", "futures-util", "geph5-broker-protocol", "geph5-misc-rpc", diff --git a/binaries/geph5-client/Cargo.toml b/binaries/geph5-client/Cargo.toml index 862db2c..37a3412 100644 --- a/binaries/geph5-client/Cargo.toml +++ b/binaries/geph5-client/Cargo.toml @@ -87,6 +87,7 @@ async-broadcast = "0.7.1" crossbeam-queue = "0.3.11" async-event = "0.2.1" ctrlc = {version="3.4.5", features=["termination"]} +futures-intrusive = "0.5.0" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = ["minwindef", "mmsystem", "timeapi", "std"] } diff --git a/binaries/geph5-client/src/refresh_cell.rs b/binaries/geph5-client/src/refresh_cell.rs index 3f9a62f..b16e602 100644 --- a/binaries/geph5-client/src/refresh_cell.rs +++ b/binaries/geph5-client/src/refresh_cell.rs @@ -4,12 +4,13 @@ use std::{ time::{Duration, SystemTime}, }; +use futures_intrusive::sync::ManualResetEvent; use parking_lot::Mutex; use smol::{channel::Sender, future::FutureExt}; use smolscale::immortal::Immortal; pub struct RefreshCell { - inner: Arc>, + inner: Arc>>, last_refresh_start: Arc>, _task: Immortal, interval: Duration, @@ -21,17 +22,18 @@ impl RefreshCell { interval: Duration, refresh: impl Fn() -> Fut + Send + Sync + 'static, ) -> Self { - let inner = Arc::new(Mutex::new(refresh().await)); + let inner = Arc::new(Mutex::new(None)); let last_refresh_start = Arc::new(Mutex::new(SystemTime::now())); let inner2 = inner.clone(); let refresh = Arc::new(move || refresh().boxed()); let (force_refresh, recv_force_refresh) = smol::channel::unbounded(); + let ready_event = Arc::new(ManualResetEvent::new(false)); let task = { let refresh = refresh.clone(); let recv_force_refresh = recv_force_refresh.clone(); let last_refresh_start = last_refresh_start.clone(); + let ready_event = ready_event.clone(); Immortal::spawn(async move { - smol::Timer::after(interval).await; loop { *last_refresh_start.lock() = SystemTime::now(); let refresh = refresh.clone(); @@ -43,7 +45,8 @@ impl RefreshCell { "RefreshCell refreshed properly" ); let mut inner = inner2.lock(); - *inner = new_value; + *inner = Some(new_value); + ready_event.set(); true }; let timeout = async { @@ -73,6 +76,7 @@ impl RefreshCell { } }) }; + ready_event.wait().await; Self { inner, _task: task, @@ -95,6 +99,6 @@ impl RefreshCell { *last_refresh_start = SystemTime::now(); } } - self.inner.lock().clone() + self.inner.lock().clone().unwrap() } } diff --git a/binaries/geph5-client/src/route.rs b/binaries/geph5-client/src/route.rs index 79d592a..7bfd9ee 100644 --- a/binaries/geph5-client/src/route.rs +++ b/binaries/geph5-client/src/route.rs @@ -1,4 +1,7 @@ -use std::{net::SocketAddr, time::Duration}; +use std::{ + net::SocketAddr, + time::{Duration, SystemTime}, +}; use anyctx::AnyCtx; use anyhow::Context; @@ -11,6 +14,7 @@ use geph5_broker_protocol::{ use isocountry::CountryCode; use moka::sync::Cache; use once_cell::sync::Lazy; +use parking_lot::Mutex; use rand::seq::SliceRandom; use serde::{Deserialize, Serialize}; use sillad::{ @@ -20,7 +24,10 @@ use sillad::{ use sillad_sosistab3::{dialer::SosistabDialer, Cookie}; use crate::{ - auth::get_connect_token, broker::broker_client, client::Config, client_inner::CONCURRENCY, + auth::get_connect_token, + broker::broker_client, + client::{Config, CtxField}, + client_inner::CONCURRENCY, vpn::vpn_whitelist, }; @@ -50,6 +57,21 @@ pub enum ExitConstraint { CountryCity(CountryCode, String), } +type DialerWithInfo = (VerifyingKey, ExitDescriptor, DynDialer); + +pub async fn get_cached_dialer(ctx: &AnyCtx) -> anyhow::Result { + static LAST_DIALER: CtxField>> = + |_| Mutex::new(None); + if let Some(last_time) = ctx.get(LAST_DIALER).lock().as_ref().map(|s| s.1) { + if let Ok(elapsed) = last_time.elapsed() { + if elapsed < Duration::from_secs(60) { + return Ok(ctx.get(LAST_DIALER).lock().as_ref().unwrap().0.clone()); + } + } + } + todo!() +} + /// Gets a sillad Dialer that produces a single, pre-authentication pipe, as well as the public key. pub async fn get_dialer( ctx: &AnyCtx,