1pub mod model;
2pub mod prelude;
3
4
5#[cfg(feature = "default")]
6use async_trait::async_trait;
7#[cfg(feature = "default")]
8use reqwest::{Client as HttpClient, RequestBuilder};
9#[cfg(feature = "default")]
10use std::sync::Arc;
11#[cfg(feature = "default")]
12use reqwest::header::HeaderMap;
13#[cfg(feature = "default")]
14use serde::de::DeserializeOwned;
15
16#[cfg(feature = "blocking")]
17pub mod blocking;
18#[cfg(feature = "default")]
19pub mod images;
20#[cfg(feature = "default")]
21pub mod bans;
22#[cfg(feature = "default")]
23pub mod kumo;
24#[cfg(feature = "default")]
25pub mod music;
26#[cfg(feature = "default")]
27use crate::{
28 images::Images,
29 bans::Bans,
30 kumo::Kumo,
31 music::Music,
32 model::bans::BanUpdate
33};
34#[cfg(feature = "serenity")]
35use typemap_rev::TypeMapKey;
36
37use std::{
38 error::Error,
39 fmt::{
40 Display, Formatter, Result as FmtResult
41 }
42};
43
44#[cfg(feature = "default")]
46pub struct Client {
47 pub token: String,
48 pub images: Images,
49 pub bans: Bans,
50 pub kumo: Kumo,
51 pub music: Music,
52 pub http: Arc<HttpClient>
53}
54
55#[cfg(feature = "default")]
56impl Client {
57 pub fn new(token: impl ToString) -> Self {
58 let mut default_auth_header = HeaderMap::new();
59 default_auth_header.insert("Authorization", format!("Bearer {}", token.to_string()).parse().expect("Cannot parse default headers"));
60 let http_client = Arc::new(HttpClient::builder()
61 .default_headers(default_auth_header)
62 .user_agent("KSoft.rs")
63 .build()
64 .expect("Something went wrong when creating http client"));
65
66 Self {
67 token: token.to_string(),
68 images: Images::new(Arc::clone(&http_client)),
69 bans: Bans::new(Arc::clone(&http_client)),
70 kumo: Kumo::new(Arc::clone(&http_client)),
71 music: Music::new(Arc::clone(&http_client)),
72 http: http_client
73 }
74 }
75
76 pub fn event_handler(&self, handler: impl EventHandler + Send + Sync + 'static ) {
100 self.bans.event_handler(handler);
101 }
102}
103
104#[cfg(feature = "serenity")]
105impl TypeMapKey for Client {
106 type Value = Arc<Self>;
107}
108
109#[cfg(feature = "default")]
110pub(crate) async fn make_request<S: DeserializeOwned, E: DeserializeOwned>(c: RequestBuilder) -> HttpResult<S, E> {
111 let response = c.send().await?;
112
113 return match response.status().as_u16() {
114 c if c == 429u16 => Err(HttpError::RateLimited),
115 c if c >= 500u16 => Err(HttpError::InternalServerError(response.text().await?)),
116 200u16 => {
117 let data = response.json::<S>().await?;
118 Ok(Ok(data))
119 },
120 _ => {
121 let err = response.json::<E>().await?;
122 Ok(Err(err))
123 }
124 }
125}
126
127const BASE_ENDPOINT: &str = "https://api.ksoft.si";
128
129pub(crate) fn endpoint(to: impl AsRef<str>) -> String {
130 format!("{}{}", BASE_ENDPOINT, to.as_ref())
131}
132
133pub type HttpResult<S, E> = Result<ApiResponse<S, E>, HttpError>;
135
136pub type ApiResponse<S, E> = Result<S, E>;
138
139#[derive(Debug)]
140pub enum HttpError {
141 RequestFailed(reqwest::Error),
142 InternalServerError(String),
143 RateLimited
144}
145
146impl From<reqwest::Error> for HttpError {
147 fn from(e: reqwest::Error) -> Self {
148 HttpError::RequestFailed(e)
149 }
150}
151
152impl Error for HttpError {}
153
154impl Display for HttpError {
155 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
156 match self {
157 Self::RequestFailed(why) => write!(f, "Request failed: {}", why.to_string()),
158 Self::InternalServerError(why) => write!(f, "Internal server error: {}", why),
159 Self::RateLimited => write!(f, "KSoft server responded with code 429 (Ratelimited)")
160 }
161 }
162}
163
164#[cfg(feature = "default")]
165#[async_trait]
166pub trait EventHandler: Send + Sync + 'static {
167 async fn ban_updated(&self, _data: Vec<BanUpdate>) {}
169}