Implement capability HTTP and downloads (#54)
All checks were successful
Native code generation / deterministic (push) Successful in 11m59s
Imaging and meshing gate / native (push) Successful in 3m55s
JPEG 2000 feature / linux (push) Successful in 2m26s
Native Rust workspace compile / compile (push) Successful in 3m58s
Skia feature / linux (push) Successful in 31m44s

This commit is contained in:
2026-08-09 15:44:42 +00:00
parent d298b4f4c4
commit 3032b16e7b
15 changed files with 5833 additions and 668 deletions

View File

@@ -114,12 +114,18 @@ struct ClientRuntime {
cancellation: CancellationTokenSource,
services: Mutex<Vec<ServiceRegistration>>,
agent_throttle_sender: Mutex<Option<Arc<dyn crate::udp_transport::AgentThrottleSender>>>,
http_caps_client: Mutex<crate::caps_http::HttpCapsClient>,
caps_rate_limiter: Mutex<crate::caps_http::CapsRateLimiter>,
shutdown_complete: Condvar,
shutdown_wait: Mutex<()>,
}
impl ClientRuntime {
fn new(services: Vec<Arc<dyn ClientService>>) -> Self {
fn new(
services: Vec<Arc<dyn ClientService>>,
http_caps_client: crate::caps_http::HttpCapsClient,
caps_rate_limiter: crate::caps_http::CapsRateLimiter,
) -> Self {
Self {
state: AtomicU8::new(ClientLifecycleState::Active as u8),
cancellation: CancellationTokenSource::new(),
@@ -134,6 +140,8 @@ impl ClientRuntime {
.collect(),
),
agent_throttle_sender: Mutex::new(None),
http_caps_client: Mutex::new(http_caps_client),
caps_rate_limiter: Mutex::new(caps_rate_limiter),
shutdown_complete: Condvar::new(),
shutdown_wait: Mutex::new(()),
}
@@ -206,6 +214,15 @@ impl ClientRuntime {
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.take();
self.http_caps_client
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.shutdown();
let _ = self
.caps_rate_limiter
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.dispose();
let shutdown_wait = self
.shutdown_wait
.lock()
@@ -309,6 +326,43 @@ impl GridClient {
.clone()
}
pub(crate) fn native_http_caps_client(&self) -> crate::caps_http::HttpCapsClient {
self.runtime
.http_caps_client
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone()
}
pub(crate) fn native_set_http_caps_client(&mut self, value: crate::caps_http::HttpCapsClient) {
*self
.runtime
.http_caps_client
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = value;
}
pub(crate) fn native_caps_rate_limiter(&self) -> crate::caps_http::CapsRateLimiter {
self.runtime
.caps_rate_limiter
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner)
.clone()
}
pub(crate) fn native_set_caps_rate_limiter(
&mut self,
value: crate::caps_http::CapsRateLimiter,
) {
self.native_http_caps_client()
.set_rate_limiter(Some(value.clone()));
*self
.runtime
.caps_rate_limiter
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = value;
}
pub(crate) fn shutdown(&self) -> Result<(), ClientCoreError> {
self.runtime.shutdown()
}
@@ -348,6 +402,10 @@ impl Drop for GridClient {
}
impl crate::IGridClient for GridClient {
fn http_caps_client(&self) -> crate::caps_http::HttpCapsClient {
self.native_http_caps_client()
}
fn settings(&self) -> Settings {
self.settings.clone()
}
@@ -404,10 +462,44 @@ impl GridClientBuilder {
/// Returns the first invalid configuration field.
pub fn build(self) -> Result<GridClient, ClientCoreError> {
self.settings.validate()?;
let caps_rate_limiter = crate::caps_http::CapsRateLimiter::new_with_clock_and_overrides(
self.time_provider.clone(),
None,
)
.map_err(|_| ClientCoreError::InvalidConfiguration {
field: "CapsRateLimiter",
reason: "could not construct the configured token buckets",
})?;
let max_connections = usize::try_from(Settings::max_http_connections()).map_err(|_| {
ClientCoreError::InvalidConfiguration {
field: "Settings.MaxHttpConnections",
reason: "must be positive",
}
})?;
let caps_timeout = u64::try_from(self.settings.timing.caps_timeout).map_err(|_| {
ClientCoreError::InvalidConfiguration {
field: "Timing.CapsTimeout",
reason: "must be positive",
}
})?;
let http_caps_client = crate::caps_http::HttpCapsClient::production(
&Settings::user_agent(),
std::time::Duration::from_millis(caps_timeout),
max_connections,
caps_rate_limiter.clone(),
)
.map_err(|_| ClientCoreError::InvalidConfiguration {
field: "HttpCapsClient",
reason: "could not construct the HTTP transport",
})?;
Ok(GridClient {
settings: self.settings,
time_provider: self.time_provider,
runtime: Arc::new(ClientRuntime::new(self.services)),
runtime: Arc::new(ClientRuntime::new(
self.services,
http_caps_client,
caps_rate_limiter,
)),
})
}
}