Wrap Client internals in Arc for cheap cloning

This commit is contained in:
Joakim Hulthe
2026-04-14 14:43:28 +00:00
parent 0d8042287c
commit 6820dd765d

View File

@@ -2,6 +2,7 @@
use crate::apis::{AlbumsApi, AssetsApi, ServerApi, TimelineApi};
use crate::error::{ImmichError, Result};
use std::sync::Arc;
use std::time::Duration;
/// Configuration for the Immich client
@@ -56,13 +57,22 @@ impl Config {
}
}
/// Client for making requests to the Immich API
#[derive(Debug, Clone)]
pub struct Client {
/// Internal client data wrapped in Arc for cheap cloning
#[derive(Debug)]
struct ClientInner {
config: Config,
http: reqwest::Client,
}
/// Client for making requests to the Immich API
///
/// This struct is cheap to clone - it uses an internal Arc to share the underlying
/// HTTP client and configuration.
#[derive(Debug, Clone)]
pub struct Client {
inner: Arc<ClientInner>,
}
impl Client {
/// Create a new client with the given configuration
pub fn new(config: Config) -> Result<Self> {
@@ -86,8 +96,10 @@ impl Client {
.build()?;
Ok(Self {
config: Config { base_url, ..config },
http,
inner: Arc::new(ClientInner {
config: Config { base_url, ..config },
http,
}),
})
}
@@ -97,38 +109,46 @@ impl Client {
}
/// Set the API key
pub fn with_api_key(mut self, api_key: impl Into<String>) -> Self {
self.config.api_key = Some(api_key.into());
self
pub fn with_api_key(self, api_key: impl Into<String>) -> Self {
// We need to create a new ClientInner since we can't modify Arc contents
let mut config = self.inner.config.clone();
config.api_key = Some(api_key.into());
Self {
inner: Arc::new(ClientInner {
config,
http: self.inner.http.clone(),
}),
}
}
/// Get the configuration
pub fn config(&self) -> &Config {
&self.config
&self.inner.config
}
/// Get the base URL
pub fn base_url(&self) -> &str {
&self.config.base_url
&self.inner.config.base_url
}
/// Check if the client has an API key configured
pub fn has_api_key(&self) -> bool {
self.config.api_key.is_some()
self.inner.config.api_key.is_some()
}
/// Get the underlying HTTP client
pub fn http(&self) -> &reqwest::Client {
&self.http
&self.inner.http
}
/// Create an authenticated request builder
pub fn request(&self, method: reqwest::Method, path: &str) -> reqwest::RequestBuilder {
let url = format!("{}/api{}", self.config.base_url, path);
let mut builder = self.http.request(method, &url);
let url = format!("{}/api{}", self.inner.config.base_url, path);
let mut builder = self.inner.http.request(method, &url);
// Add API key authentication
if let Some(ref api_key) = self.config.api_key {
if let Some(ref api_key) = self.inner.config.api_key {
builder = builder.header("x-api-key", api_key);
}
@@ -137,7 +157,7 @@ impl Client {
/// Execute a request and handle common error cases
pub async fn execute(&self, request: reqwest::Request) -> Result<reqwest::Response> {
let response = self.http.execute(request).await?;
let response = self.inner.http.execute(request).await?;
if response.status().is_success() {
Ok(response)