1mod commit;
2mod common;
3mod isssue;
4mod middleware;
5mod org;
6mod release;
7mod repo;
8mod user;
9
10use crate::{
11 commit::GitHubCommit,
12 isssue::GitHubIssue,
13 middleware::{HeaderMiddleware, ResponseMiddleware},
14 org::GitHubOrg,
15 release::GitHubRelease,
16 repo::GitHubRepo,
17 user::GitHubUser,
18};
19use async_trait::async_trait;
20pub use nipaw_core::{Client, Commit, Error, Issue, Org, Release, Repo, Result, User};
21use reqwest::Proxy;
22use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
23use std::sync::Arc;
24use tokio::sync::RwLock;
25
26#[derive(Debug, Clone)]
27pub(crate) struct GitHubConfig {
28 pub(crate) token: Option<String>,
29 pub(crate) api_url: String,
30 pub(crate) base_url: String,
31}
32
33#[derive(Debug, Clone)]
34pub(crate) struct GitHubClientInner {
35 pub(crate) config: GitHubConfig,
36 pub(crate) client: Arc<RwLock<Arc<ClientWithMiddleware>>>,
37}
38
39impl Default for GitHubConfig {
40 fn default() -> Self {
41 Self {
42 token: None,
43 base_url: "https://github.com".to_string(),
44 api_url: "https://api.github.com".to_string(),
45 }
46 }
47}
48
49impl GitHubConfig {
50 pub fn set_token(&mut self, token: &str) {
52 self.token = Some(token.to_string());
53 }
54 pub fn set_api_url(&mut self, api_url: String) {
56 self.api_url = api_url;
57 }
58
59 pub fn set_base_url(&mut self, base_url: String) {
61 self.base_url = base_url;
62 }
63}
64
65#[derive(Debug, Clone)]
66pub struct GitHubClient {
67 pub(crate) inner: Arc<GitHubClientInner>,
68}
69
70impl Default for GitHubClient {
71 fn default() -> Self {
72 let client = reqwest::Client::new();
73 Self {
74 inner: Arc::new(GitHubClientInner {
75 config: GitHubConfig::default(),
76 client: Arc::new(RwLock::new(Arc::new(
77 ClientBuilder::new(client)
78 .with(HeaderMiddleware)
79 .with(ResponseMiddleware)
80 .build(),
81 ))),
82 }),
83 }
84 }
85}
86impl GitHubClient {
87 pub fn new() -> Self {
88 Self::default()
89 }
90
91 pub fn set_reverse_proxy(&mut self, url: &str) {
93 let clean_url = url.trim_end_matches('/');
94 let inner = Arc::make_mut(&mut self.inner);
95 let api_url = format!("{}/{}", clean_url, inner.config.api_url);
96 let base_url = format!("{}/{}", clean_url, inner.config.base_url);
97 inner.config.set_api_url(api_url);
98 inner.config.set_base_url(base_url);
99 }
100}
101
102#[async_trait]
103impl Client for GitHubClient {
104 fn set_token(&mut self, token: &str) -> Result<()> {
105 if token.is_empty() {
106 return Err(Error::TokenEmpty);
107 }
108 Arc::make_mut(&mut self.inner).config.set_token(token);
109 Ok(())
110 }
111
112 fn set_proxy(&mut self, proxy: &str) -> Result<()> {
113 let client = reqwest::Client::builder().proxy(Proxy::all(proxy)?).build()?;
114 *self.inner.client.try_write().unwrap() = Arc::new(
115 ClientBuilder::new(client).with(HeaderMiddleware).with(ResponseMiddleware).build(),
116 );
117 Ok(())
118 }
119
120 fn user(&self) -> Box<dyn User> {
121 Box::new(GitHubUser(self.inner.clone()))
122 }
123
124 fn org(&self) -> Box<dyn Org> {
125 Box::new(GitHubOrg(self.inner.clone()))
126 }
127
128 fn repo(&self) -> Box<dyn Repo> {
129 Box::new(GitHubRepo(self.inner.clone()))
130 }
131
132 fn commit(&self) -> Box<dyn Commit> {
133 Box::new(GitHubCommit(self.inner.clone()))
134 }
135
136 fn issue(&self) -> Box<dyn Issue> {
137 Box::new(GitHubIssue(self.inner.clone()))
138 }
139
140 fn release(&self) -> Box<dyn Release> {
141 Box::new(GitHubRelease(self.inner.clone()))
142 }
143}