summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2021-04-07 17:20:40 +0200
committerMatthias Beyer <mail@beyermatthias.de>2021-04-07 17:20:40 +0200
commit857a27350c88fa2b1acd7d8de34214d736b444da (patch)
tree07a0e093b00b4f8df64b0323d67ace1e98527c0d
parente880f99e773512215cc9f695eb2d865af5734d90 (diff)
Split api into modules
Signed-off-by: Matthias Beyer <mail@beyermatthias.de>
-rw-r--r--librepology/src/v1/api.rs265
-rw-r--r--librepology/src/v1/api/client.rs42
-rw-r--r--librepology/src/v1/api/mod.rs12
-rw-r--r--librepology/src/v1/api/request.rs125
-rw-r--r--librepology/src/v1/api/request_builder.rs111
-rw-r--r--librepology/src/v1/api/response.rs12
6 files changed, 302 insertions, 265 deletions
diff --git a/librepology/src/v1/api.rs b/librepology/src/v1/api.rs
deleted file mode 100644
index eb843d6..0000000
--- a/librepology/src/v1/api.rs
+++ /dev/null
@@ -1,265 +0,0 @@
-use crate::endpoint::EndpointUrl;
-use crate::v1::error::Result;
-use crate::v1::error::RepologyError;
-
-static APP_USER_AGENT: &str = concat!(
- env!("CARGO_PKG_NAME"),
- "/",
- env!("CARGO_PKG_VERSION"),
-);
-
-pub struct ApiClient {
- endpoint_url: &'static str,
- client: reqwest::Client,
-}
-
-impl ApiClient {
- pub fn new<EP: EndpointUrl>(timeout: std::time::Duration) -> Result<Self> {
- reqwest::Client::builder()
- .user_agent(APP_USER_AGENT)
- .build()
- .map_err(RepologyError::from)
- .map(|client| ApiClient {
- endpoint_url: EP::endpoint_url(),
- client,
- })
- }
-
- pub fn projects<'a>(&'a self) -> ProjectRequestBuilder<'a> {
- ProjectRequestBuilder(self)
- }
-
-}
-
-pub struct ProjectRequestBuilder<'a>(&'a ApiClient);
-
-impl<'a> ProjectRequestBuilder<'a> {
- pub fn with_name(self, name: String) -> ProjectRequestBuilderWithName<'a> {
- ProjectRequestBuilderWithName(self.0, name)
- }
-
- pub fn filtered(self) -> ProjectRequestFilteredBuilder<'a> {
- ProjectRequestFilteredBuilder {
- client: self.0,
- search: None,
- category: None,
- in_repo_filter: None,
- not_in_repo_filter: None,
- repos_filter: None,
- families_filter: None,
- repos_newest: None,
- families_newest: None,
- newest: None,
- outdated: None,
- problematic: None,
- }
- }
-}
-
-pub trait ToRequest<'a> {
- fn to_request(self) -> Request<'a>;
-}
-
-pub struct Request<'a> {
- client: &'a ApiClient,
- request_string: String
-}
-
-impl<'a> Request<'a> {
- pub async fn perform(self) -> Result<Response> {
- self.client
- .client
- .get(format!("{}{}", self.client.endpoint_url, self.request_string))
- .send()
- .await?
- .text()
- .await
- .map(Response)
- .map_err(RepologyError::from)
- }
-}
-
-pub struct Response(String);
-
-impl Response {
- pub fn deserialize<'de, T: serde::Deserialize<'de>>(&'de self) -> Result<T> {
- serde_json::from_str(&self.0).map_err(RepologyError::from)
- }
-}
-
-pub struct ProjectRequestBuilderWithName<'a>(&'a ApiClient, String);
-
-impl<'a> ToRequest<'a> for ProjectRequestBuilderWithName<'a> {
- fn to_request(self) -> Request<'a> {
- Request {
- client: self.0,
- request_string: format!("projects/{}", self.1),
- }
- }
-}
-
-pub struct ProjectRequestFilteredBuilder<'a> {
- client: &'a ApiClient,
-
- // From the API documentation
-
- search: Option<String>,
- category: Option<String>,
- in_repo_filter: Option<String>,
- not_in_repo_filter: Option<String>,
- repos_filter: Option<NumberOrRange>,
- families_filter: Option<usize>,
- repos_newest: Option<bool>,
- families_newest: Option<bool>,
- newest: Option<bool>,
- outdated: Option<bool>,
- problematic: Option<bool>,
-}
-
-impl<'a> ProjectRequestFilteredBuilder<'a> {
- pub fn with_search(mut self, opt: Option<String>) -> Self {
- self.search = opt;
- self
- }
-
- pub fn with_category(mut self, opt: Option<String>) -> Self {
- self.category = opt;
- self
- }
-
- pub fn with_in_repo_filter(mut self, opt: Option<String>) -> Self {
- self.in_repo_filter = opt;
- self
- }
-
- pub fn with_not_in_repo_filter(mut self, opt: Option<String>) -> Self {
- self.not_in_repo_filter = opt;
- self
- }
-
- pub fn with_repos_filter(mut self, opt: Option<NumberOrRange>) -> Self {
- self.repos_filter = opt;
- self
- }
-
- pub fn with_families_filter(mut self, opt: Option<usize>) -> Self {
- self.families_filter = opt;
- self
- }
-
- pub fn with_repos_newest(mut self, opt: Option<bool>) -> Self {
- self.repos_newest = opt;
- self
- }
-
- pub fn with_families_newest(mut self, opt: Option<bool>) -> Self {
- self.families_newest = opt;
- self
- }
-
- pub fn with_newest(mut self, opt: Option<bool>) -> Self {
- self.newest = opt;
- self
- }
-
- pub fn with_outdated(mut self, opt: Option<bool>) -> Self {
- self.outdated = opt;
- self
- }
-
- pub fn with_problematic(mut self, opt: Option<bool>) -> Self {
- self.problematic = opt;
- self
- }
-
-}
-
-impl<'a> ToRequest<'a> for ProjectRequestFilteredBuilder<'a> {
- fn to_request(self) -> Request<'a> {
- let mut buf = Vec::new();
-
- if let Some(search) = self.search.as_ref() {
- let s = format!("search={}", search);
- buf.push(s);
- }
-
- if let Some(category) = self.category.as_ref() {
- let s = format!("category={}", category);
- buf.push(s);
- }
-
- if let Some(in_repo_filter) = self.in_repo_filter.as_ref() {
- let s = format!("in_repo_filter={}", in_repo_filter);
- buf.push(s);
- }
-
- if let Some(not_in_repo_filter) = self.not_in_repo_filter.as_ref() {
- let s = format!("not_in_repo_filter={}", not_in_repo_filter);
- buf.push(s);
- }
-
- if let Some(repos_filter) = self.repos_filter.as_ref() {
- match repos_filter {
- NumberOrRange::Number(u) => {
- let s = format!("repos={}", u);
- buf.push(s);
- },
- NumberOrRange::Range(None, None) => {
- // nothing, because there is no range
- },
- NumberOrRange::Range(Some(a), None) => {
- let s = format!("repos={}-", a);
- buf.push(s);
- },
- NumberOrRange::Range(None, Some(b)) => {
- let s = format!("repos=-{}", b);
- buf.push(s);
- },
- NumberOrRange::Range(Some(a), Some(b)) => {
- let s = format!("repos={}-{}", a, b);
- buf.push(s);
- },
- }
- }
-
- if let Some(families_filter) = self.families_filter.as_ref() {
- let s = format!("families={}", families_filter);
- buf.push(s);
- }
-
- if let Some(newest) = self.newest.as_ref() {
- if *newest {
- buf.push(String::from("newest=1"));
- } else {
- buf.push(String::from("newest=0"));
- }
- }
-
- if let Some(outdated) = self.outdated.as_ref() {
- if *outdated {
- buf.push(String::from("newest=1"));
- } else {
- buf.push(String::from("newest=0"));
- }
- }
-
- if let Some(problematic) = self.problematic.as_ref() {
- if *problematic {
- buf.push(String::from("newest=1"));
- } else {
- buf.push(String::from("newest=0"));
- }
- }
-
- Request {
- client: self.client,
- request_string: format!("&{}", buf.join("&")),
- }
- }
-}
-
-pub enum NumberOrRange {
- Number(usize),
- Range(Option<usize>, Option<usize>),
-}
-
diff --git a/librepology/src/v1/api/client.rs b/librepology/src/v1/api/client.rs
new file mode 100644
index 0000000..5a4e7f2
--- /dev/null
+++ b/librepology/src/v1/api/client.rs
@@ -0,0 +1,42 @@
+use crate::endpoint::EndpointUrl;
+use crate::v1::error::Result;
+use crate::v1::error::RepologyError;
+use crate::v1::api::ProjectRequestBuilder;
+
+static APP_USER_AGENT: &str = concat!(
+ env!("CARGO_PKG_NAME"),
+ "/",
+ env!("CARGO_PKG_VERSION"),
+);
+
+pub struct ApiClient {
+ pub(super) endpoint_url: &'static str,
+ pub(super) client: reqwest::Client,
+}
+
+impl ApiClient {
+ pub fn new<EP: EndpointUrl>() -> Result<Self> {
+ reqwest::Client::builder()
+ .user_agent(APP_USER_AGENT)
+ .build()
+ .map_err(RepologyError::from)
+ .map(|client| ApiClient {
+ endpoint_url: EP::endpoint_url(),
+ client,
+ })
+ }
+
+ pub fn client(&self) -> &reqwest::Client {
+ &self.client
+ }
+
+ pub fn client_mut(&mut self) -> &reqwest::Client {
+ &mut self.client
+ }
+
+ pub fn projects<'a>(&'a self) -> ProjectRequestBuilder<'a> {
+ ProjectRequestBuilder(self)
+ }
+
+}
+
diff --git a/librepology/src/v1/api/mod.rs b/librepology/src/v1/api/mod.rs
new file mode 100644
index 0000000..34fa9a2
--- /dev/null
+++ b/librepology/src/v1/api/mod.rs
@@ -0,0 +1,12 @@
+mod client;
+pub use client::*;
+
+mod request_builder;
+pub use request_builder::*;
+
+mod request;
+pub use request::*;
+
+mod response;
+pub use response::*;
+
diff --git a/librepology/src/v1/api/request.rs b/librepology/src/v1/api/request.rs
new file mode 100644
index 0000000..fef4385
--- /dev/null
+++ b/librepology/src/v1/api/request.rs
@@ -0,0 +1,125 @@
+use crate::v1::api::ApiClient;
+use crate::v1::api::NumberOrRange;
+use crate::v1::api::ProjectRequestBuilderWithName;
+use crate::v1::api::ProjectRequestFilteredBuilder;
+use crate::v1::api::Response;
+use crate::v1::error::RepologyError;
+use crate::v1::error::Result;
+
+pub struct Request<'a> {
+ client: &'a ApiClient,
+ request_string: String
+}
+
+impl<'a> Request<'a> {
+ pub async fn perform(self) -> Result<Response> {
+ self.client
+ .client
+ .get(format!("{}{}", self.client.endpoint_url, self.request_string))
+ .send()
+ .await?
+ .text()
+ .await
+ .map(Response)
+ .map_err(RepologyError::from)
+ }
+}
+
+pub trait ToRequest<'a> {
+ fn to_request(self) -> Request<'a>;
+}
+
+impl<'a> ToRequest<'a> for ProjectRequestBuilderWithName<'a> {
+ fn to_request(self) -> Request<'a> {
+ Request {
+ client: self.0,
+ request_string: format!("projects/{}", self.1),
+ }
+ }
+}
+
+
+impl<'a> ToRequest<'a> for ProjectRequestFilteredBuilder<'a> {
+ fn to_request(self) -> Request<'a> {
+ let mut buf = Vec::new();
+
+ if let Some(search) = self.search.as_ref() {
+ let s = format!("search={}", search);
+ buf.push(s);
+ }
+
+ if let Some(category) = self.category.as_ref() {
+ let s = format!("category={}", category);
+ buf.push(s);
+ }
+
+ if let Some(in_repo_filter) = self.in_repo_filter.as_ref() {
+ let s = format!("in_repo_filter={}", in_repo_filter);
+ buf.push(s);
+ }
+
+ if let Some(not_in_repo_filter) = self.not_in_repo_filter.as_ref() {
+ let s = format!("not_in_repo_filter={}", not_in_repo_filter);
+ buf.push(s);
+ }
+
+ if let Some(repos_filter) = self.repos_filter.as_ref() {
+ match repos_filter {
+ NumberOrRange::Number(u) => {
+ let s = format!("repos={}", u);
+ buf.push(s);
+ },
+ NumberOrRange::Range(None, None) => {
+ // nothing, because there is no range
+ },
+ NumberOrRange::Range(Some(a), None) => {
+ let s = format!("repos={}-", a);
+ buf.push(s);
+ },
+ NumberOrRange::Range(None, Some(b)) => {
+ let s = format!("repos=-{}", b);
+ buf.push(s);
+ },
+ NumberOrRange::Range(Some(a), Some(b)) => {
+ let s = format!("repos={}-{}", a, b);
+ buf.push(s);
+ },
+ }
+ }
+
+ if let Some(families_filter) = self.families_filter.as_ref() {
+ let s = format!("families={}", families_filter);
+ buf.push(s);
+ }
+
+ if let Some(newest) = self.newest.as_ref() {
+ if *newest {
+ buf.push(String::from("newest=1"));
+ } else {
+ buf.push(String::from("newest=0"));
+ }
+ }
+
+ if let Some(outdated) = self.outdated.as_ref() {
+ if *outdated {
+ buf.push(String::from("newest=1"));
+ } else {
+ buf.push(String::from("newest=0"));
+ }
+ }
+
+ if let Some(problematic) = self.problematic.as_ref() {
+ if *problematic {
+ buf.push(String::from("newest=1"));
+ } else {
+ buf.push(String::from("newest=0"));
+ }
+ }
+
+ Request {
+ client: self.client,
+ request_string: format!("&{}", buf.join("&")),
+ }
+ }
+}
+
diff --git a/librepology/src/v1/api/request_builder.rs b/librepology/src/v1/api/request_builder.rs
new file mode 100644
index 0000000..7218caa
--- /dev/null
+++ b/librepology/src/v1/api/request_builder.rs
@@ -0,0 +1,111 @@
+use crate::v1::api::ApiClient;
+
+pub struct ProjectRequestBuilder<'a>(pub(super) &'a ApiClient);
+
+impl<'a> ProjectRequestBuilder<'a> {
+ pub fn with_name(self, name: String) -> ProjectRequestBuilderWithName<'a> {
+ ProjectRequestBuilderWithName(self.0, name)
+ }
+
+ pub fn filtered(self) -> ProjectRequestFilteredBuilder<'a> {
+ ProjectRequestFilteredBuilder {
+ client: self.0,
+ search: None,
+ category: None,
+ in_repo_filter: None,
+ not_in_repo_filter: None,
+ repos_filter: None,
+ families_filter: None,
+ repos_newest: None,
+ families_newest: None,
+ newest: None,
+ outdated: None,
+ problematic: None,
+ }
+ }
+}
+
+
+pub struct ProjectRequestBuilderWithName<'a>(pub(super) &'a ApiClient, pub(super) String);
+
+pub struct ProjectRequestFilteredBuilder<'a> {
+ pub(super) client: &'a ApiClient,
+
+ // From the API documentation:
+
+ pub(super) search: Option<String>,
+ pub(super) category: Option<String>,
+ pub(super) in_repo_filter: Option<String>,
+ pub(super) not_in_repo_filter: Option<String>,
+ pub(super) repos_filter: Option<NumberOrRange>,
+ pub(super) families_filter: Option<usize>,
+ pub(super) repos_newest: Option<bool>,
+ pub(super) families_newest: Option<bool>,
+ pub(super) newest: Option<bool>,
+ pub(super) outdated: Option<bool>,
+ pub(super) problematic: Option<bool>,
+}
+
+impl<'a> ProjectRequestFilteredBuilder<'a> {
+ pub fn with_search(mut self, opt: Option<String>) -> Self {
+ self.search = opt;
+ self
+ }
+
+ pub fn with_category(mut self, opt: Option<String>) -> Self {
+ self.category = opt;
+ self
+ }
+
+ pub fn with_in_repo_filter(mut self, opt: Option<String>) -> Self {
+ self.in_repo_filter = opt;
+ self
+ }
+
+ pub fn with_not_in_repo_filter(mut self, opt: Option<String>) -> Self {
+ self.not_in_repo_filter = opt;
+ self
+ }
+
+ pub fn with_repos_filter(mut self, opt: Option<NumberOrRange>) -> Self {
+ self.repos_filter = opt;
+ self
+ }
+
+ pub fn with_families_filter(mut self, opt: Option<usize>) -> Self {
+ self.families_filter = opt;
+ self
+ }
+
+ pub fn with_repos_newest(mut self, opt: Option<bool>) -> Self {
+ self.repos_newest = opt;
+ self
+ }
+
+ pub fn with_families_newest(mut self, opt: Option<bool>) -> Self {
+ self.families_newest = opt;
+ self
+ }
+
+ pub fn with_newest(mut self, opt: Option<bool>) -> Self {
+ self.newest = opt;
+ self
+ }
+
+ pub fn with_outdated(mut self, opt: Option<bool>) -> Self {
+ self.outdated = opt;
+ self
+ }
+
+ pub fn with_problematic(mut self, opt: Option<bool>) -> Self {
+ self.problematic = opt;
+ self
+ }
+
+}
+
+pub enum NumberOrRange {
+ Number(usize),
+ Range(Option<usize>, Option<usize>),
+}
+
diff --git a/librepology/src/v1/api/response.rs b/librepology/src/v1/api/response.rs
new file mode 100644
index 0000000..d6a6e6c
--- /dev/null
+++ b/librepology/src/v1/api/response.rs
@@ -0,0 +1,12 @@
+use crate::v1::error::Result;
+use crate::v1::error::RepologyError;
+
+pub struct Response(pub(super) String);
+
+impl Response {
+ pub fn deserialize<'de, T: serde::Deserialize<'de>>(&'de self) -> Result<T> {
+ serde_json::from_str(&self.0).map_err(RepologyError::from)
+ }
+}
+
+