AirLibrary/Client/AirServiceProvider/mod.rs
1//! # Air::Client::AirServiceProvider
2//!
3//! High-level façade over [`crate::Client::AirClient::AirClient`]. Each
4//! method generates a request id via [`crate::Utility::GenerateRequestId`],
5//! issues the gRPC call, and returns [`crate::AirError`] on failure.
6//! Compared with the raw `AirClient` surface, this layer:
7//!
8//! - hides request-id plumbing from callers,
9//! - returns ergonomic shapes (`CheckForUpdates` collapses `update_available ==
10//! false` into `Ok(None)`),
11//! - keeps a shared `Arc<AirClient>` so all callers reuse the same gRPC
12//! channel.
13//!
14//! ## Layout
15//!
16//! Per-domain methods live one-per-file under this module; each declares
17//! a single `impl AirServiceProvider { … }` block:
18//!
19//! - Authentication: [`Authenticate`]
20//! - Updates: [`CheckForUpdates`], [`DownloadUpdate`], [`ApplyUpdate`]
21//! - Downloads: [`DownloadFile`], [`DownloadStream`]
22//! - Indexing: [`IndexFiles`], [`SearchFiles`], [`GetFileInfo`]
23//! - Status / monitoring: [`GetStatus`], [`GetMetrics`]
24//! - Resources: [`GetResourceUsage`], [`SetResourceLimits`]
25//! - Configuration: [`GetConfiguration`], [`UpdateConfiguration`]
26//!
27//! ## Threading model
28//!
29//! Cheap to clone (Arc ref-count bump). The interior `tokio::sync::Mutex`
30//! on the underlying `AirClient` serialises concurrent RPCs on a single
31//! channel.
32
33// --- Authentication ---
34
35pub mod Authenticate;
36
37pub mod CheckForUpdates;
38
39pub mod DownloadUpdate;
40
41// --- Downloads ---
42
43pub mod DownloadFile;
44
45pub mod DownloadStream;
46
47// --- Indexing ---
48
49pub mod GetFileInfo;
50
51pub mod IndexFiles;
52
53pub mod SearchFiles;
54
55// --- Status + monitoring ---
56
57pub mod GetMetrics;
58
59pub mod GetStatus;
60
61// --- Resource management ---
62
63pub mod GetResourceUsage;
64
65pub mod SetResourceLimits;
66
67// --- Configuration ---
68
69pub mod GetConfiguration;
70
71pub mod UpdateConfiguration;
72
73// --- ApplyUpdate ---
74
75pub mod ApplyUpdate;
76
77// --- Provider core ---
78
79use std::sync::Arc;
80
81use crate::{
82 AirError,
83 Client::AirClient::{AirClient, DEFAULT_AIR_SERVER_ADDRESS},
84 dev_log,
85};
86
87/// High-level provider over [`AirClient`]. Holds the client in an
88/// `Arc` so consumers can share one channel across the application.
89#[derive(Debug, Clone)]
90pub struct AirServiceProvider {
91 /// Shared underlying gRPC client.
92 client:Arc<AirClient>,
93}
94
95impl AirServiceProvider {
96 /// Connects to the Air daemon at `address` and returns a ready-to-use
97 /// provider.
98 ///
99 /// # Errors
100 ///
101 /// Forwards any error from [`AirClient::new`].
102 pub async fn new(address:String) -> Result<Self, AirError> {
103 dev_log!("grpc", "[AirServiceProvider] Creating AirServiceProvider at: {}", address);
104
105 let Client = AirClient::new(&address).await?;
106
107 dev_log!("grpc", "[AirServiceProvider] AirServiceProvider created successfully");
108
109 Ok(Self { client:Arc::new(Client) })
110 }
111
112 /// Connects using [`DEFAULT_AIR_SERVER_ADDRESS`].
113 pub async fn NewDefault() -> Result<Self, AirError> { Self::new(DEFAULT_AIR_SERVER_ADDRESS.to_string()).await }
114
115 /// Wraps an existing [`AirClient`] handle. Useful when the gRPC
116 /// channel is created elsewhere or shared with a non-provider call
117 /// site.
118 pub fn FromClient(Client:Arc<AirClient>) -> Self {
119 dev_log!("grpc", "[AirServiceProvider] Creating AirServiceProvider from existing client");
120
121 Self { client:Client }
122 }
123
124 /// Shared reference to the underlying client.
125 pub fn Client(&self) -> &Arc<AirClient> { &self.client }
126
127 /// Whether the underlying client is connected.
128 pub fn IsConnected(&self) -> bool { self.client.is_connected() }
129
130 /// Address of the Air daemon.
131 pub fn Address(&self) -> &str { self.client.address() }
132}