From c406bb48709846cad7da85295d1efe28d510b9cd Mon Sep 17 00:00:00 2001 From: notplants Date: Sat, 15 Jan 2022 10:36:52 -0500 Subject: [PATCH] Working friends methods --- examples/ssb-friends.rs | 62 ++++++++++++++++++++++++++++ src/sbot.rs | 89 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 examples/ssb-friends.rs diff --git a/examples/ssb-friends.rs b/examples/ssb-friends.rs new file mode 100644 index 0000000..0b65a78 --- /dev/null +++ b/examples/ssb-friends.rs @@ -0,0 +1,62 @@ +use async_std::stream::StreamExt; +use futures::pin_mut; +use std::process; + +use golgi::sbot::{SubsetQuery, SubsetQueryOptions, FriendsHopsOpts}; +use golgi::error::GolgiError; +use golgi::messages::SsbMessageContent; +use golgi::sbot::Sbot; + +async fn run() -> Result<(), GolgiError> { + let mut sbot_client = Sbot::init(None, None).await?; + + let id = sbot_client.whoami().await?; + println!("whoami: {}", id); + + // test ids to follow and block + let to_follow = "@5Pt3dKy2HTJ0mWuS78oIiklIX0gBz6BTfEnXsbvke9c=.ed25519"; + let to_block = "@7Y4nwfQmVtAilEzi5knXdS2gilW7cGKSHXdXoT086LM=.ed25519"; + + // follow to_follow + let response = sbot_client.set_relationship(to_follow, true, false).await?; + println!("follow_response: {:?}", response); + + // block to_block + let response = sbot_client.set_relationship(to_block, false, true).await?; + println!("follow_response: {:?}", response); + + // print all users you are following + let follows = sbot_client.friends_hops(FriendsHopsOpts { + max: 1, + start: None, + // doesnt seem like reverse does anything, currently + reverse: Some(false), + }).await?; + println!("follows: {:?}", follows); + + // print if you are following to_follow (should be true) + let mref = sbot_client.friends_is_following(&id, to_follow).await?; + println!("isfollowingmref: {}", mref); + + // print if you are blocking to_block (should be true) + let mref = sbot_client.friends_is_blocking(&id, to_block).await?; + println!("isblockingmref: {}", mref); + + // print if you are blocking to_follow (should be false) + let mref = sbot_client.friends_is_blocking(&id, to_follow).await?; + println!("isblockingmref(should be false): {}", mref); + + // print if you are following to_block (should be false) + let mref = sbot_client.friends_is_following(&id, to_block).await?; + println!("isfollowingmref(should be false): {}", mref); + + Ok(()) +} + +#[async_std::main] +async fn main() { + if let Err(e) = run().await { + eprintln!("Application error: {}", e); + process::exit(1); + } +} diff --git a/src/sbot.rs b/src/sbot.rs index f1fcfca..e4cd61f 100644 --- a/src/sbot.rs +++ b/src/sbot.rs @@ -21,7 +21,7 @@ use crate::utils; use crate::utils::get_source_stream; // re-export types from kuska -pub use kuska_ssb::api::dto::content::{SubsetQuery, SubsetQueryOptions}; +pub use kuska_ssb::api::dto::content::{SubsetQuery, SubsetQueryOptions, FriendsHopsOpts}; /// A struct representing a connection with a running sbot. /// A client and an rpc_reader can together be used to make requests to the sbot @@ -184,9 +184,32 @@ impl Sbot { .await } + // Convenience method to set a relationship with following: true, blocking: false + pub async fn follow(&mut self, contact: &str) -> Result { + self.set_relationship(contact, true, false).await + } + + // Convenience method to set a relationship with following: false, blocking: true + pub async fn block(&mut self, contact: &str) -> Result { + self.set_relationship(contact, false, true).await + } + + /// Publishes a contact relationship to the given user (with ssb_id) with the given state. + pub async fn set_relationship(&mut self, contact: &str, following: bool, blocking: bool) -> Result { + let msg = SsbMessageContent::Contact { + contact: Some(contact.to_string()), + following: Some(following), + blocking: Some(blocking), + autofollow: None + }; + self.publish(msg).await + } + /// Call the `friends follow` RPC method and return a message reference. /// if state is true, then sets the following status to true /// if state is false, then sets the following status to false (unfollow) + /// TODO: currently this method is not working (seems to be missing from go-sbot) + /// as a workaround, we can use set_relationship instead just fine pub async fn friends_follow( &mut self, ssb_id: &str, @@ -226,6 +249,70 @@ impl Sbot { .await } + /// Call the `friends isblocking` RPC method and return a message reference. + /// returns true if src_id is blocking dest_id and false otherwise + pub async fn friends_is_blocking( + &mut self, + src_id: &str, + dest_id: &str, + ) -> Result { + let mut sbot_connection = self.get_sbot_connection().await?; + let req_id = sbot_connection + .client + .friends_isblocking_req_send(src_id, dest_id) + .await?; + + utils::get_async( + &mut sbot_connection.rpc_reader, + req_id, + utils::string_res_parse, + ) + .await + } + + // Gets a Vec where each element is a peer you are following + pub async fn get_follows(&mut self) -> Result, GolgiError> { + self.friends_hops(FriendsHopsOpts { + max: 1, + start: None, + reverse: Some(false), + }).await + } + + // Gets a Vec where each element is a peer who follows you + /// TODO: currently this method is not working + /// go-sbot does not seem to listen to the reverse=True parameter + /// and just returns follows + pub async fn get_followers(&mut self) -> Result, GolgiError> { + self.friends_hops(FriendsHopsOpts { + max: 1, + start: None, + reverse: Some(true), + }).await + } + + /// Call the `friends hops` RPC method and return a Vector + /// where each element of the vector is the ssb_id of a peer. + /// + /// When opts.reverse = True, it should return peers who are following you + /// (but this is currently not working) + pub async fn friends_hops( + &mut self, + opts: FriendsHopsOpts, + ) -> Result, GolgiError> { + let mut sbot_connection = self.get_sbot_connection().await?; + let req_id = sbot_connection + .client + .friends_hops_req_send(opts) + .await?; + utils::get_source_until_eof( + &mut sbot_connection.rpc_reader, + req_id, + utils::string_res_parse, + ) + .await + } + /// Wrapper for publish which constructs and publishes a post message appropriately from a string. /// /// # Arguments