diff options
Diffstat (limited to 'src/micropub.rs')
-rw-r--r-- | src/micropub.rs | 81 |
1 files changed, 81 insertions, 0 deletions
diff --git a/src/micropub.rs b/src/micropub.rs new file mode 100644 index 0000000..e855459 --- /dev/null +++ b/src/micropub.rs @@ -0,0 +1,81 @@ +use soup::prelude::*; +pub use kittybox_util::micropub::{Error as MicropubError, Config, QueryType}; + +#[derive(Debug)] +pub struct Client { + micropub: String, + access_token: String, + + //http: soup::Session, +} + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error("glib error: {0}")] + Glib(#[from] glib::Error), + #[error("json serialization error: {0}")] + Json(#[from] serde_json::Error), + #[error("micropub error: {0}")] + Micropub(#[from] MicropubError), + #[error("micropub server did not return a location: header")] + NoLocationHeader +} + +impl Client { + pub fn new(uri: glib::Uri, token: String) -> Self { + Self { + micropub: uri.to_string(), + access_token: token, + + //http: soup::Session::new() + } + } + + pub async fn config(&self) -> Result<Config, Error> { + let uri = glib::Uri::parse(&self.micropub, glib::UriFlags::NONE).unwrap(); + let uri = super::util::append_query( + &uri, [("q".to_string(), "config".to_string())] + ); + + let exch = soup::Message::from_uri("GET", &uri); + let headers = exch.request_headers().expect("SoupMessage with no headers"); + // TODO: create a SoupAuth subclass that allows pasting in a token + headers.append("Authorization", &format!("Bearer {}", self.access_token)); + + let http = soup::Session::new(); + let body = http.send_and_read_future(&exch, glib::Priority::DEFAULT).await?; + + Ok(serde_json::from_slice(&body)?) + } + + pub async fn send_post(&self, post: microformats::types::Item) -> Result<glib::Uri, Error> { + let uri = glib::Uri::parse(&self.micropub, glib::UriFlags::NONE).unwrap(); + let exch = soup::Message::from_uri("POST", &uri); + let headers = exch.request_headers().expect("SoupMessage with no headers"); + headers.append("Authorization", &format!("Bearer {}", self.access_token)); + + exch.set_request_body_from_bytes(Some("application/json"), + Some(&glib::Bytes::from_owned(serde_json::to_vec(&post).unwrap())) + ); + + let http = soup::Session::new(); + let body = http.send_and_read_future(&exch, glib::Priority::DEFAULT).await?; + + match exch.status() { + soup::Status::Created | soup::Status::Accepted => { + let response_headers = exch.response_headers().expect("Successful SoupMessage with no response headers"); + let location = response_headers.one("Location").ok_or(Error::NoLocationHeader)?; + + Ok(glib::Uri::parse(&location, glib::UriFlags::NONE)?) + }, + soup::Status::InternalServerError | soup::Status::BadGateway | soup::Status::ServiceUnavailable => { + todo!("micropub server is down") + }, + _ => { + let error = serde_json::from_slice::<MicropubError>(&body)?; + + Err(error.into()) + } + } + } +} |