From d08138ea633da76d9ca390e4f9e3c5489aee23d1 Mon Sep 17 00:00:00 2001 From: Harald Eilertsen Date: Mon, 5 Jul 2021 22:03:47 +0200 Subject: Update reqwest and make async. This means adding the full tokio as a dependency. While there isn't much gain to going async in the current cli demo app, a full fledged app may have more to gain by it. First foray into async rust, so I might not do it right... --- src/abconfig.rs | 4 ++-- src/abook.rs | 4 ++-- src/bin/zot/main.rs | 19 +++++++++++-------- src/bin/zot/zot/abconfig.rs | 4 ++-- src/bin/zot/zot/abook.rs | 4 ++-- src/bin/zot/zot/channel_stream.rs | 4 ++-- src/bin/zot/zot/item.rs | 4 ++-- src/bin/zot/zot/network_stream.rs | 4 ++-- src/bin/zot/zot/xchan.rs | 8 ++++---- src/channel_stream.rs | 4 ++-- src/client.rs | 40 ++++++++++++++++++++------------------- src/group.rs | 8 ++++---- src/item.rs | 21 ++++++++++++++++---- src/network_stream.rs | 4 ++-- src/xchan.rs | 4 ++-- 15 files changed, 77 insertions(+), 59 deletions(-) (limited to 'src') diff --git a/src/abconfig.rs b/src/abconfig.rs index 6348030..ebb7e2b 100644 --- a/src/abconfig.rs +++ b/src/abconfig.rs @@ -61,14 +61,14 @@ impl ABConfigRequest { self } - pub fn fetch(&self, client: &Client) -> Result, Error> { + pub async fn fetch(&self, client: &Client) -> Result, Error> { let mut req = client.get("abconfig"); if let Some(id) = self.abook_id { req = req.query(&[("abook_id", id.to_string())]); } - Ok(serde_json::from_str(&req.send()?.text()?)?) + Ok(serde_json::from_str(&req.send().await?.text().await?)?) } } diff --git a/src/abook.rs b/src/abook.rs index 59981ba..938a48f 100644 --- a/src/abook.rs +++ b/src/abook.rs @@ -114,13 +114,13 @@ impl AbookRequest { self } - pub fn fetch(&self, client: &Client) -> Result, Error> { + pub async fn fetch(&self, client: &Client) -> Result, Error> { let mut req = client.get("abook"); if let Some(id) = self.abook_id { req = req.query(&[("abook_id", id.to_string())]); } - Ok(serde_json::from_str(&req.send()?.text()?)?) + Ok(serde_json::from_str(&req.send().await?.text().await?)?) } } diff --git a/src/bin/zot/main.rs b/src/bin/zot/main.rs index 5828f44..09fdd61 100644 --- a/src/bin/zot/main.rs +++ b/src/bin/zot/main.rs @@ -22,7 +22,8 @@ use std::str::FromStr; mod zot; -fn main() { +#[tokio::main] +async fn main() { dotenv().ok(); let site = env::var("HZ_SITE").expect("SITE variable expected"); let user = env::var("HZ_USER").expect("USER variable expected"); @@ -79,24 +80,25 @@ fn main() { match matches.subcommand() { ("channel", Some(m)) => { let raw = m.is_present("raw"); - zot::channel_stream::fetch(&client, raw); + zot::channel_stream::fetch(&client, raw).await; } ("network", Some(m)) => { let raw = m.is_present("raw"); - zot::network_stream::fetch(&client, raw); + zot::network_stream::fetch(&client, raw).await; } ("abconfig", _) => { - zot::abconfig::fetch(&client); + zot::abconfig::fetch(&client).await; } ("abook", Some(m)) => { let raw = m.is_present("raw"); - zot::abook::fetch(&client, raw); + zot::abook::fetch(&client, raw).await; } ("group", Some(m)) => { if let Some(id) = m.value_of("ID") { let res = zotapi::group_members() .by_group_id(u64::from_str(id).unwrap()) .fetch(&client) + .await .unwrap(); if m.is_present("raw") { @@ -108,6 +110,7 @@ fn main() { let res = zotapi::group_members() .by_group_name(gname) .fetch(&client) + .await .unwrap(); if m.is_present("raw") { @@ -116,7 +119,7 @@ fn main() { zot::group::list_members(&res); } } else { - let res = zotapi::group().fetch(&client).unwrap(); + let res = zotapi::group().fetch(&client).await.unwrap(); if m.is_present("raw") { println!("{}", res); @@ -135,10 +138,10 @@ fn main() { zot::xchan::Type::Addr }; - zot::xchan::fetch(&client, raw, t, m.value_of("ID").unwrap()); + zot::xchan::fetch(&client, raw, t, m.value_of("ID").unwrap()).await; } ("post", Some(m)) => { - zot::item::post(&client, m); + zot::item::post(&client, m).await; } _ => { println!("{}", matches.usage()); diff --git a/src/bin/zot/zot/abconfig.rs b/src/bin/zot/zot/abconfig.rs index 2e357e4..14875c8 100644 --- a/src/bin/zot/zot/abconfig.rs +++ b/src/bin/zot/zot/abconfig.rs @@ -17,8 +17,8 @@ use zotapi; -pub fn fetch(client: &zotapi::Client) { - match zotapi::ABConfig::z().fetch(&client) { +pub async fn fetch(client: &zotapi::Client) { + match zotapi::ABConfig::z().fetch(&client).await { Ok(v) => { println!("Id: Chan: Cat: Key: Val: xchan:"); for entry in v { diff --git a/src/bin/zot/zot/abook.rs b/src/bin/zot/zot/abook.rs index 97025c3..6c33757 100644 --- a/src/bin/zot/zot/abook.rs +++ b/src/bin/zot/zot/abook.rs @@ -15,8 +15,8 @@ * along with this program. If not, see . */ -pub fn fetch(client: &zotapi::Client, _raw: bool) { - match zotapi::Abook::z().fetch(&client) { +pub async fn fetch(client: &zotapi::Client, _raw: bool) { + match zotapi::Abook::z().fetch(&client).await { Ok(abooks) => { for b in abooks { println!("{:?}", b); diff --git a/src/bin/zot/zot/channel_stream.rs b/src/bin/zot/zot/channel_stream.rs index 33ad7cf..68a5402 100644 --- a/src/bin/zot/zot/channel_stream.rs +++ b/src/bin/zot/zot/channel_stream.rs @@ -20,8 +20,8 @@ use zotapi; use serde_json; use std::iter::Iterator; -pub fn fetch(client: &zotapi::Client, raw: bool) { - match zotapi::channel_stream().fetch(&client) { +pub async fn fetch(client: &zotapi::Client, raw: bool) { + match zotapi::channel_stream().fetch(&client).await { Ok(payload) => { if raw { println!("{}", payload); diff --git a/src/bin/zot/zot/item.rs b/src/bin/zot/zot/item.rs index 648a9f0..dbb39ba 100644 --- a/src/bin/zot/zot/item.rs +++ b/src/bin/zot/zot/item.rs @@ -18,7 +18,7 @@ use clap::ArgMatches; use zotapi; -pub fn post(client: &zotapi::Client, args: &ArgMatches) { +pub async fn post(client: &zotapi::Client, args: &ArgMatches<'_>) { let mut msg = zotapi::item(); let body: String; @@ -42,7 +42,7 @@ pub fn post(client: &zotapi::Client, args: &ArgMatches) { } } - match msg.create(&client) { + match msg.create(&client).await { Ok(res) => { if res.success { println!("New item with id {} posted successfully!", res.item_id); diff --git a/src/bin/zot/zot/network_stream.rs b/src/bin/zot/zot/network_stream.rs index 0e6edb4..a5a7142 100644 --- a/src/bin/zot/zot/network_stream.rs +++ b/src/bin/zot/zot/network_stream.rs @@ -20,8 +20,8 @@ use zotapi; use serde_json; use std::iter::Iterator; -pub fn fetch(client: &zotapi::Client, raw: bool) { - match zotapi::network_stream().fetch(&client) { +pub async fn fetch(client: &zotapi::Client, raw: bool) { + match zotapi::network_stream().fetch(&client).await { Ok(payload) => { if raw { println!("{}", payload); diff --git a/src/bin/zot/zot/xchan.rs b/src/bin/zot/zot/xchan.rs index 088d49c..146b2ab 100644 --- a/src/bin/zot/zot/xchan.rs +++ b/src/bin/zot/zot/xchan.rs @@ -23,11 +23,11 @@ pub enum Type { GUID, } -pub fn fetch(client: &zotapi::Client, _raw: bool, t: Type, id: &str) { +pub async fn fetch(client: &zotapi::Client, _raw: bool, t: Type, id: &str) { let res = match t { - Type::Addr => zotapi::XChan::z().by_address(&id).fetch(&client), - Type::Hash => zotapi::XChan::z().by_hash(&id).fetch(&client), - Type::GUID => zotapi::XChan::z().by_guid(&id).fetch(&client), + Type::Addr => zotapi::XChan::z().by_address(&id).fetch(&client).await, + Type::Hash => zotapi::XChan::z().by_hash(&id).fetch(&client).await, + Type::GUID => zotapi::XChan::z().by_guid(&id).fetch(&client).await, }; match res { diff --git a/src/channel_stream.rs b/src/channel_stream.rs index 49f51e7..ed63f11 100644 --- a/src/channel_stream.rs +++ b/src/channel_stream.rs @@ -24,7 +24,7 @@ pub fn channel_stream() -> ChannelStream { } impl ChannelStream { - pub fn fetch(&self, client: &Client) -> Result { - client.fetch_stream("channel/stream", &()) + pub async fn fetch(&self, client: &Client) -> Result { + client.fetch_stream("channel/stream", &()).await } } diff --git a/src/client.rs b/src/client.rs index c681b27..3f43479 100644 --- a/src/client.rs +++ b/src/client.rs @@ -22,6 +22,7 @@ use reqwest::{ }; use serde::Serialize; use std::collections::BTreeMap; +use std::fs::File; use std::io::Read; use url::Url; @@ -56,22 +57,17 @@ impl Client { r.to_string() } - pub fn fetch_stream(&self, path: &str, args: &T) -> Result + pub async fn fetch_stream(&self, path: &str, args: &T) -> Result where T: Serialize + std::fmt::Debug, { let url = dbg!(self.url(path, args)); - let res = self - .inner - .get(&url) - .header(ACCEPT, "application/json") - .basic_auth(self.user.clone(), Some(self.pw.clone())) - .send()?; + let res = self.get(&url).send().await?; - handle_result(res) + handle_result(res).await } - pub fn post_data(&self, path: &str, data: &T) -> Result + pub async fn post_data(&self, path: &str, data: &T) -> Result where T: Serialize + std::fmt::Debug, { @@ -84,12 +80,12 @@ impl Client { .basic_auth(self.user.clone(), Some(self.pw.clone())) .body(serde_qs::to_string(&data)?)) //.form(&data)) - .send()?; + .send().await?; - handle_result(res) + handle_result(res).await } - pub fn post_multipart( + pub async fn post_multipart( &self, path: &str, data: &BTreeMap<&str, T>, @@ -106,7 +102,14 @@ impl Client { } for f in files.iter() { - form = form.file("media", f).unwrap(); + let mut pdata = vec![]; + let path = std::path::Path::new(f); + File::open(path)?.read_to_end(&mut pdata)?; + + let filename = String::from(path.file_name().unwrap().to_str().unwrap()); + let p = reqwest::multipart::Part::bytes(pdata) + .file_name(filename); + form = form.part("media", p); } let res = self @@ -114,9 +117,10 @@ impl Client { .post(&url) .basic_auth(self.user.clone(), Some(self.pw.clone())) .multipart(form) - .send()?; + .send() + .await?; - handle_result(res) + handle_result(res).await } /// Return a RequestBuilder object that's set up with the correct @@ -139,13 +143,11 @@ impl Client { // A common function for handling the response after a request. // // Consumes the response, and return it as a string or an error. -fn handle_result(mut res: reqwest::Response) -> Result { +async fn handle_result(res: reqwest::Response) -> Result { match res.status() { StatusCode::UNAUTHORIZED => Err(Error::Unauthorized), StatusCode::OK => { - let mut body = String::new(); - res.read_to_string(&mut body)?; - Ok(body) + Ok(res.text().await?) } _ => { eprintln!("Received unknown status: {:?}", res.status()); diff --git a/src/group.rs b/src/group.rs index 2ed8e92..cf3a057 100644 --- a/src/group.rs +++ b/src/group.rs @@ -24,8 +24,8 @@ pub fn group() -> Group { } impl Group { - pub fn fetch(&self, client: &Client) -> Result { - client.fetch_stream("group", &()) + pub async fn fetch(&self, client: &Client) -> Result { + client.fetch_stream("group", &()).await } } @@ -57,7 +57,7 @@ impl<'a> GroupMembers<'a> { self } - pub fn fetch(&self, client: &Client) -> Result { - client.fetch_stream("group_members", &self.id.as_ref().unwrap()) + pub async fn fetch(&self, client: &Client) -> Result { + client.fetch_stream("group_members", &self.id.as_ref().unwrap()).await } } diff --git a/src/item.rs b/src/item.rs index 7c5935d..d61401b 100644 --- a/src/item.rs +++ b/src/item.rs @@ -21,6 +21,8 @@ use reqwest::{ }; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; +use std::fs::File; +use std::io::Read; /// Data type for values that an Item can hold. #[derive(Debug, Serialize)] @@ -81,13 +83,17 @@ pub struct ItemCreatedResponse { /// Typical usage: /// /// ```no_run +/// # async { /// let client = zotapi::client("https://myhub.com", "mychannel", "mypw"); /// let new_post = zotapi::item() /// .title("A title") /// .body("The body of the post") /// .file("/my/photo.jpg") -/// .create(&client)?; +/// .create(&client) +/// .await?; /// # Ok::<(), zotapi::Error>(()) +/// # }; +/// ``` /// ``` #[derive(Debug)] pub struct ItemBuilder<'a> { @@ -133,7 +139,7 @@ impl<'a> ItemBuilder<'a> { } /// Create the item by poting it to the server - pub fn create(&self, client: &Client) -> Result { + pub async fn create(&self, client: &Client) -> Result { dbg!(self); let mut req = client.post("item/update"); @@ -149,13 +155,20 @@ impl<'a> ItemBuilder<'a> { } for f in self.files.iter() { - form = form.file("media", f)?; + let mut pdata = vec![]; + let path = std::path::Path::new(f); + File::open(path)?.read_to_end(&mut pdata)?; + + let filename = String::from(path.file_name().unwrap().to_str().unwrap()); + let p = reqwest::multipart::Part::bytes(pdata) + .file_name(filename); + form = form.part("media", p); } req = req.multipart(form) } - Ok(serde_json::from_str(&req.send()?.text()?)?) + Ok(serde_json::from_str(&req.send().await?.text().await?)?) } } diff --git a/src/network_stream.rs b/src/network_stream.rs index 8204458..80e7c11 100644 --- a/src/network_stream.rs +++ b/src/network_stream.rs @@ -24,7 +24,7 @@ pub fn network_stream() -> NetworkStream { } impl NetworkStream { - pub fn fetch(&self, client: &Client) -> Result { - client.fetch_stream("network/stream", &()) + pub async fn fetch(&self, client: &Client) -> Result { + client.fetch_stream("network/stream", &()).await } } diff --git a/src/xchan.rs b/src/xchan.rs index 994f4b0..6fbe7a2 100644 --- a/src/xchan.rs +++ b/src/xchan.rs @@ -80,7 +80,7 @@ impl<'a> XChanRequest<'a> { self } - pub fn fetch(&self, client: &Client) -> Result { + pub async fn fetch(&self, client: &Client) -> Result { let mut req = client.get("xchan"); if let Some(sel) = &self.data { @@ -91,6 +91,6 @@ impl<'a> XChanRequest<'a> { }; } - Ok(serde_json::from_str(&dbg!(req.send()?.text()?))?) + Ok(serde_json::from_str(&dbg!(req.send().await?.text().await?))?) } } -- cgit v1.2.3