mirror of https://gitlab.com/famedly/conduit.git
26 changed files with 697 additions and 585 deletions
@ -0,0 +1,104 @@
|
||||
use crate::{utils, Error, Result}; |
||||
use http::header::{HeaderValue, CONTENT_TYPE}; |
||||
use log::warn; |
||||
use ruma::api::OutgoingRequest; |
||||
use std::{ |
||||
convert::{TryFrom, TryInto}, |
||||
fmt::Debug, |
||||
time::Duration, |
||||
}; |
||||
|
||||
pub async fn send_request<T: OutgoingRequest>( |
||||
globals: &crate::database::globals::Globals, |
||||
registration: serde_yaml::Value, |
||||
request: T, |
||||
) -> Result<T::IncomingResponse> |
||||
where |
||||
T: Debug, |
||||
{ |
||||
let destination = registration.get("url").unwrap().as_str().unwrap(); |
||||
let hs_token = registration.get("hs_token").unwrap().as_str().unwrap(); |
||||
|
||||
let mut http_request = request |
||||
.try_into_http_request(&destination, Some("")) |
||||
.unwrap(); |
||||
|
||||
let mut parts = http_request.uri().clone().into_parts(); |
||||
let old_path_and_query = parts.path_and_query.unwrap().as_str().to_owned(); |
||||
let symbol = if old_path_and_query.contains("?") { |
||||
"&" |
||||
} else { |
||||
"?" |
||||
}; |
||||
|
||||
parts.path_and_query = Some( |
||||
(old_path_and_query + symbol + "access_token=" + hs_token) |
||||
.parse() |
||||
.unwrap(), |
||||
); |
||||
*http_request.uri_mut() = parts.try_into().expect("our manipulation is always valid"); |
||||
|
||||
http_request.headers_mut().insert( |
||||
CONTENT_TYPE, |
||||
HeaderValue::from_str("application/json").unwrap(), |
||||
); |
||||
|
||||
let mut reqwest_request = reqwest::Request::try_from(http_request) |
||||
.expect("all http requests are valid reqwest requests"); |
||||
|
||||
*reqwest_request.timeout_mut() = Some(Duration::from_secs(30)); |
||||
|
||||
let url = reqwest_request.url().clone(); |
||||
let reqwest_response = globals.reqwest_client().execute(reqwest_request).await; |
||||
|
||||
// Because reqwest::Response -> http::Response is complicated:
|
||||
match reqwest_response { |
||||
Ok(mut reqwest_response) => { |
||||
let status = reqwest_response.status(); |
||||
let mut http_response = http::Response::builder().status(status); |
||||
let headers = http_response.headers_mut().unwrap(); |
||||
|
||||
for (k, v) in reqwest_response.headers_mut().drain() { |
||||
if let Some(key) = k { |
||||
headers.insert(key, v); |
||||
} |
||||
} |
||||
|
||||
let status = reqwest_response.status(); |
||||
|
||||
let body = reqwest_response |
||||
.bytes() |
||||
.await |
||||
.unwrap_or_else(|e| { |
||||
warn!("server error: {}", e); |
||||
Vec::new().into() |
||||
}) // TODO: handle timeout
|
||||
.into_iter() |
||||
.collect::<Vec<_>>(); |
||||
|
||||
if status != 200 { |
||||
warn!( |
||||
"Server returned bad response {} ({}): {} {:?}", |
||||
destination, |
||||
url, |
||||
status, |
||||
utils::string_from_bytes(&body) |
||||
); |
||||
} |
||||
|
||||
let response = T::IncomingResponse::try_from( |
||||
http_response |
||||
.body(body) |
||||
.expect("reqwest body is valid http body"), |
||||
); |
||||
response.map_err(|_| { |
||||
warn!( |
||||
"Server returned invalid response bytes {} ({})", |
||||
destination, url |
||||
); |
||||
Error::BadServerResponse("Server returned bad response.") |
||||
}) |
||||
} |
||||
Err(e) => Err(e.into()), |
||||
} |
||||
} |
||||
@ -0,0 +1,67 @@
|
||||
use crate::{utils, Error, Result}; |
||||
use std::collections::HashMap; |
||||
use std::sync::{Arc, RwLock}; |
||||
|
||||
#[derive(Clone)] |
||||
pub struct Appservice { |
||||
pub(super) cached_registrations: Arc<RwLock<HashMap<String, serde_yaml::Value>>>, |
||||
pub(super) id_appserviceregistrations: sled::Tree, |
||||
} |
||||
|
||||
impl Appservice { |
||||
pub fn register_appservice(&self, yaml: serde_yaml::Value) -> Result<()> { |
||||
// TODO: Rumaify
|
||||
let id = yaml.get("id").unwrap().as_str().unwrap(); |
||||
self.id_appserviceregistrations |
||||
.insert(id, serde_yaml::to_string(&yaml).unwrap().as_bytes())?; |
||||
self.cached_registrations |
||||
.write() |
||||
.unwrap() |
||||
.insert(id.to_owned(), yaml); |
||||
|
||||
Ok(()) |
||||
} |
||||
|
||||
pub fn get_registration(&self, id: &str) -> Result<Option<serde_yaml::Value>> { |
||||
self.cached_registrations |
||||
.read() |
||||
.unwrap() |
||||
.get(id) |
||||
.map_or_else( |
||||
|| { |
||||
Ok(self |
||||
.id_appserviceregistrations |
||||
.get(id)? |
||||
.map(|bytes| { |
||||
Ok::<_, Error>(serde_yaml::from_slice(&bytes).map_err(|_| { |
||||
Error::bad_database( |
||||
"Invalid registration bytes in id_appserviceregistrations.", |
||||
) |
||||
})?) |
||||
}) |
||||
.transpose()?) |
||||
}, |
||||
|r| Ok(Some(r.clone())), |
||||
) |
||||
} |
||||
|
||||
pub fn iter_ids(&self) -> impl Iterator<Item = Result<String>> { |
||||
self.id_appserviceregistrations.iter().keys().map(|id| { |
||||
Ok(utils::string_from_bytes(&id?).map_err(|_| { |
||||
Error::bad_database("Invalid id bytes in id_appserviceregistrations.") |
||||
})?) |
||||
}) |
||||
} |
||||
|
||||
pub fn iter_all<'a>( |
||||
&'a self, |
||||
) -> impl Iterator<Item = Result<(String, serde_yaml::Value)>> + 'a { |
||||
self.iter_ids().filter_map(|id| id.ok()).map(move |id| { |
||||
Ok(( |
||||
id.clone(), |
||||
self.get_registration(&id)? |
||||
.expect("iter_ids only returns appservices that exist"), |
||||
)) |
||||
}) |
||||
} |
||||
} |
||||
Loading…
Reference in new issue