1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#![allow(clippy::tabs_in_doc_comments)]
pub mod pager;
pub mod requests;
pub mod responses;
pub mod util;
use std::fmt::Debug;
use isahc::{
http::{
header::ACCEPT, request::Builder as RequestBuilder, Method as HttpMethod, Request,
Response, Uri,
},
AsyncBody as IsahcBody, Body as IsahcBodySync, HttpClient, HttpClientBuilder,
};
use crate::pager::Pager;
type IsahcRequest<B> = Request<B>;
type IsahcResponse = Response<IsahcBody>;
type IsahcResponseSync = Response<IsahcBodySync>;
type IsahcResult<T> = Result<T, isahc::Error>;
pub trait GithubApi<B>: Clone + Debug
where
Self: Clone + Debug,
{
const HTTP_METHOD: HttpMethod;
const PATH: &'static str;
const ACCEPT: &'static str;
fn build_uri(&self) -> Uri;
fn build_body(&self) -> B;
fn build_request(&self) -> IsahcRequest<B> {
RequestBuilder::new()
.method(Self::HTTP_METHOD)
.header(ACCEPT, Self::ACCEPT)
.uri(self.build_uri())
.body(self.build_body())
.unwrap()
}
fn build_request_with_extra_queries(&self, extra_queries: impl AsRef<str>) -> IsahcRequest<B> {
let uri = self.build_uri();
let uri = if uri.query().is_none() {
format!("{}?{}", uri, extra_queries.as_ref())
} else {
format!("{}&{}", uri, extra_queries.as_ref())
};
RequestBuilder::new()
.method(Self::HTTP_METHOD)
.header(ACCEPT, Self::ACCEPT)
.uri(uri)
.body(self.build_body())
.unwrap()
}
}
#[derive(Clone, Debug)]
pub struct Githuber {
pub http_client: HttpClient,
}
impl Githuber {
pub const API_BASE_URL: &'static str = "https://api.github.com";
pub fn new(oauth_token: impl AsRef<str>) -> Self {
let http_client = HttpClientBuilder::new()
.default_header("Authorization", &format!("token {}", oauth_token.as_ref()))
.build()
.unwrap();
tracing::trace!("{:#?}", http_client);
Self { http_client }
}
pub async fn download(&self, url: impl AsRef<str>) -> IsahcResult<IsahcResponse> {
let response = self.http_client.get_async(url.as_ref()).await?;
tracing::trace!("{:#?}", response);
Ok(response)
}
pub async fn send<B>(&self, request: impl GithubApi<B>) -> IsahcResult<IsahcResponse>
where
B: Into<IsahcBody>,
{
let request = request.build_request();
tracing::trace!("{}", request.uri());
self.http_client.send_async(request).await
}
pub fn send_sync<B>(&self, request: impl GithubApi<B>) -> IsahcResult<IsahcResponseSync>
where
B: Into<IsahcBodySync>,
{
let request = request.build_request();
tracing::trace!("{}", request.uri());
self.http_client.send(request)
}
pub async fn send_with_pager<B>(
&self,
request: impl GithubApi<B>,
pager: &mut Pager,
) -> IsahcResult<IsahcResponse>
where
B: Into<IsahcBody>,
{
let request = request.build_request_with_extra_queries(pager.query());
tracing::trace!("{}", request.uri());
pager.page += 1;
self.http_client.send_async(request).await
}
}