Skip to content

Commit b86fae7

Browse files
authored
Merge pull request #16 from ATLAS-Space-Operations/dev
Add universal headers
2 parents a98e607 + 722c99c commit b86fae7

6 files changed

Lines changed: 73 additions & 16 deletions

File tree

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ moka = { version = "0.12.10", features = ["future"], optional = true }
2828

2929
# ATLAS internal dependencies
3030
freedom-config = { version = "1.0.0", features = ["serde"] }
31-
freedom-models = { version = "2.2.0", features = ["serde"] }
31+
freedom-models = { git = "https://github.com/ATLAS-Space-Operations/rust-freedom-models", branch = "dev", features = ["serde"] }
3232

3333
[dev-dependencies]
3434
futures = { version = "0.3.30" }
@@ -38,6 +38,7 @@ tokio-test = { version = "0.4.4"}
3838
tracing-test = { version = "0.2.4" }
3939

4040
[features]
41+
bundles = ["freedom-models/bundles"]
4142
caching = ["dep:moka", "serde/rc"]
4243

4344
[[example]]

src/api.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ use futures_core::Stream;
3131

3232
use crate::error::Error;
3333

34+
#[cfg(feature = "bundles")]
35+
pub(crate) mod bundle;
3436
pub(crate) mod post;
3537

3638
/// A super trait containing all the requirements for Freedom API Values

src/api/bundle.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
use freedom_models::bundle::fps_task;
2+
use time::{OffsetDateTime, format_description::well_known::Iso8601};
3+
4+
use super::{Api, Error};
5+
6+
/// Adds additional functionality by exposing bundle endpoints.
7+
///
8+
/// These are primarily used internally by the FPS and Gateway but exist in the public API, and are
9+
/// thus included here. In general, use of these should be avoided for customers
10+
pub trait BundleApi: Api {
11+
/// Produces a list of [`fps_task::Bundle`]s within the designated window
12+
///
13+
/// See [`get`](Api::get) documentation for more details about the process and return type
14+
fn get_fps_task_bundle(
15+
&self,
16+
start: OffsetDateTime,
17+
end: OffsetDateTime,
18+
) -> impl Future<Output = Result<Self::Container<Vec<fps_task::Bundle>>, Error>> + Send + Sync
19+
{
20+
async move {
21+
let start = start.format(&Iso8601::DEFAULT).map_err(Error::from)?;
22+
let end = end.format(&Iso8601::DEFAULT).map_err(Error::from)?;
23+
24+
let mut uri = self.path_to_url("fpstaskbundle/search/findByOverlapping");
25+
uri.set_query(Some(&format!("start={}&end={}", start, end)));
26+
27+
self.get_json_map::<Self::Container<Vec<fps_task::Bundle>>>(uri)
28+
.await
29+
}
30+
}
31+
}
32+
33+
impl<T> BundleApi for T where T: Api {}

src/client.rs

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use bytes::Bytes;
22
use freedom_config::Config;
3-
use reqwest::{Response, StatusCode};
3+
use reqwest::{RequestBuilder, Response, StatusCode};
44
use url::Url;
55

66
use crate::api::{Api, Inner, Value};
@@ -13,6 +13,7 @@ use crate::api::{Api, Inner, Value};
1313
pub struct Client {
1414
pub(crate) config: Config,
1515
pub(crate) client: reqwest::Client,
16+
universal_headers: Vec<(String, String)>,
1617
}
1718

1819
impl PartialEq for Client {
@@ -42,6 +43,7 @@ impl Client {
4243
Self {
4344
config,
4445
client: reqwest::Client::new(),
46+
universal_headers: Vec::new(),
4547
}
4648
}
4749

@@ -56,6 +58,23 @@ impl Client {
5658
let config = Config::from_env()?;
5759
Ok(Self::from_config(config))
5860
}
61+
62+
/// Adds a universal header key and value to all GET POST, and DELETEs made with the client
63+
pub fn with_universal_header(
64+
mut self,
65+
key: impl Into<String>,
66+
value: impl Into<String>,
67+
) -> Self {
68+
self.universal_headers.push((key.into(), value.into()));
69+
self
70+
}
71+
72+
fn append_headers(&self, mut req: RequestBuilder) -> RequestBuilder {
73+
for (header, value) in self.universal_headers.iter() {
74+
req = req.header(header, value);
75+
}
76+
req
77+
}
5978
}
6079

6180
impl Api for Client {
@@ -64,9 +83,9 @@ impl Api for Client {
6483
async fn get(&self, url: Url) -> Result<(Bytes, StatusCode), crate::error::Error> {
6584
tracing::trace!("GET to {}", url);
6685

67-
let resp = self
68-
.client
69-
.get(url.clone())
86+
let req = self.append_headers(self.client.get(url.clone()));
87+
88+
let resp = req
7089
.basic_auth(self.config.key(), Some(&self.config.expose_secret()))
7190
.send()
7291
.await?;
@@ -84,9 +103,9 @@ impl Api for Client {
84103
async fn delete(&self, url: Url) -> Result<Response, crate::error::Error> {
85104
tracing::trace!("DELETE to {}", url);
86105

87-
self.client
88-
.delete(url.clone())
89-
.basic_auth(self.config.key(), Some(self.config.expose_secret()))
106+
let req = self.append_headers(self.client.delete(url.clone()));
107+
108+
req.basic_auth(self.config.key(), Some(self.config.expose_secret()))
90109
.send()
91110
.await
92111
.inspect_err(|error| tracing::warn!(%error, %url, "Failed to DELETE"))
@@ -100,9 +119,9 @@ impl Api for Client {
100119
{
101120
tracing::trace!("POST to {}", url);
102121

103-
self.client
104-
.post(url.clone())
105-
.basic_auth(self.config.key(), Some(self.config.expose_secret()))
122+
let req = self.append_headers(self.client.post(url.clone()));
123+
124+
req.basic_auth(self.config.key(), Some(self.config.expose_secret()))
106125
.json(&msg)
107126
.send()
108127
.await
@@ -193,7 +212,7 @@ mod tests {
193212

194213
assert_eq!(response, RESPONSE.as_bytes());
195214
assert_eq!(status, StatusCode::OK);
196-
mock.assert_hits(1);
215+
mock.assert_calls(1);
197216
}
198217

199218
#[tokio::test]
@@ -211,7 +230,7 @@ mod tests {
211230

212231
assert_eq!(response, RESPONSE.as_bytes());
213232
assert_eq!(status, StatusCode::NOT_FOUND);
214-
mock.assert_hits(1);
233+
mock.assert_calls(1);
215234
}
216235

217236
#[tokio::test]
@@ -231,6 +250,6 @@ mod tests {
231250
let url = Url::parse(&format!("http://{}/testing", addr)).unwrap();
232251
client.post(url, &json).await.unwrap();
233252

234-
mock.assert_hits(1);
253+
mock.assert_calls(1);
235254
}
236255
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ pub mod error;
88
pub mod extensions;
99
mod utils;
1010

11+
#[cfg(feature = "bundles")]
12+
pub use self::api::bundle::BundleApi;
1113
pub use self::{
1214
api::{Api, Container, Inner, PaginatedStream, Value},
1315
client::Client,

tests/common.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,11 @@ impl TestingEnv {
4141
}
4242

4343
pub fn get_json_from_file(
44-
&self,
44+
&'_ self,
4545
path: &str,
4646
query: Vec<(&str, &str)>,
4747
file: impl AsRef<Path>,
48-
) -> Mock {
48+
) -> Mock<'_> {
4949
let file = std::fs::read(file).unwrap();
5050
let file = String::from_utf8(file).unwrap();
5151
let file = file.replace("localhost:8080", &format!("localhost:{}", self.port()));

0 commit comments

Comments
 (0)