burn_central_client/fleet/
mod.rs1pub mod request;
4pub mod response;
5
6use crate::ClientError;
7use crate::Env;
8use crate::client::ResponseExt;
9use crate::request::ExchangeFleetDeviceTokenRequest;
10use crate::response::FleetDeviceAuthTokenResponse;
11use request::{
12 DownloadModelRequest, IngestTelemetryRequest, SyncDeviceRequest, TelemetryIngestionEvents,
13};
14use reqwest::Url;
15use response::{FleetModelDownloadResponse, FleetSyncSnapshotResponse};
16
17#[derive(Debug, Clone)]
19pub struct FleetClient {
20 http_client: reqwest::blocking::Client,
21 base_url: Url,
22}
23
24impl FleetClient {
25 pub fn new(env: Env) -> Self {
27 FleetClient {
28 http_client: reqwest::blocking::Client::new(),
29 base_url: env.get_url(),
30 }
31 }
32
33 pub fn from_url(url: Url) -> Self {
35 FleetClient {
36 http_client: reqwest::blocking::Client::new(),
37 base_url: url,
38 }
39 }
40
41 pub fn register(
43 &self,
44 registration_token: impl Into<String>,
45 identity_key: impl Into<String>,
46 metadata: Option<serde_json::Value>,
47 ) -> Result<FleetDeviceAuthTokenResponse, ClientError> {
48 let request = ExchangeFleetDeviceTokenRequest {
49 registration_token: registration_token.into(),
50 identity_key: identity_key.into(),
51 metadata,
52 };
53
54 self.post_json("fleets/device/register", Some(request))
55 }
56
57 pub fn sync(
59 &self,
60 token: impl AsRef<str>,
61 metadata: Option<serde_json::Value>,
62 ) -> Result<FleetSyncSnapshotResponse, ClientError> {
63 let request = SyncDeviceRequest { metadata };
64
65 self.post_auth_json("fleets/device/sync", Some(request), token)
66 }
67
68 pub fn model_download(
70 &self,
71 auth_token: impl AsRef<str>,
72 ) -> Result<FleetModelDownloadResponse, ClientError> {
73 let request = DownloadModelRequest {};
74
75 self.post_auth_json("fleets/device/model/download", Some(request), auth_token)
76 }
77
78 pub fn ingest_telemetry(
80 &self,
81 auth_token: impl AsRef<str>,
82 events: TelemetryIngestionEvents,
83 ) -> Result<(), ClientError> {
84 let request = IngestTelemetryRequest { events };
85
86 self.post_auth("fleets/device/telemetry", Some(request), auth_token)
87 }
88
89 fn post_auth<T>(
90 &self,
91 path: impl AsRef<str>,
92 body: Option<T>,
93 auth_token: impl AsRef<str>,
94 ) -> Result<(), ClientError>
95 where
96 T: serde::Serialize,
97 {
98 self.req(reqwest::Method::POST, path, body, Some(auth_token.as_ref()))
99 .map(|_| ())
100 }
101
102 fn post_json<T, R>(&self, path: impl AsRef<str>, body: Option<T>) -> Result<R, ClientError>
103 where
104 T: serde::Serialize,
105 R: for<'de> serde::Deserialize<'de>,
106 {
107 let response = self.req(reqwest::Method::POST, path, body, None)?;
108 let bytes = response.bytes()?;
109 let json = serde_json::from_slice::<R>(&bytes)?;
110 Ok(json)
111 }
112
113 fn post_auth_json<T, R>(
114 &self,
115 path: impl AsRef<str>,
116 body: Option<T>,
117 auth_token: impl AsRef<str>,
118 ) -> Result<R, ClientError>
119 where
120 T: serde::Serialize,
121 R: for<'de> serde::Deserialize<'de>,
122 {
123 let response = self.req(reqwest::Method::POST, path, body, Some(auth_token.as_ref()))?;
124 let bytes = response.bytes()?;
125 let json = serde_json::from_slice::<R>(&bytes)?;
126 Ok(json)
127 }
128
129 fn req<T: serde::Serialize>(
130 &self,
131 method: reqwest::Method,
132 path: impl AsRef<str>,
133 body: Option<T>,
134 auth_token: Option<&str>,
135 ) -> Result<reqwest::blocking::Response, ClientError> {
136 let url = self.join(path.as_ref());
137 let request_builder = self.http_client.request(method, url);
138
139 let mut request_builder = if let Some(body) = body {
140 request_builder
141 .body(serde_json::to_vec(&body)?)
142 .header(reqwest::header::CONTENT_TYPE, "application/json")
143 } else {
144 request_builder
145 };
146
147 if let Some(token) = auth_token {
148 request_builder = request_builder.bearer_auth(token);
149 }
150
151 let request_builder = request_builder.header("X-SDK-Version", env!("CARGO_PKG_VERSION"));
152
153 tracing::debug!("Sending fleet request: {:?}", request_builder);
154
155 let response = request_builder.send()?.map_to_burn_central_err()?;
156
157 tracing::debug!("Received fleet response: {:?}", response);
158
159 Ok(response)
160 }
161
162 fn join(&self, path: &str) -> Url {
163 self.join_versioned(path, 1)
164 }
165
166 fn join_versioned(&self, path: &str, version: u8) -> Url {
167 self.base_url
168 .join(&format!("v{version}/"))
169 .unwrap()
170 .join(path)
171 .expect("Should be able to join url")
172 }
173}