diff --git a/examples/ssb-client.rs b/examples/ssb-client.rs index d7ae0b4..0ab02c0 100644 --- a/examples/ssb-client.rs +++ b/examples/ssb-client.rs @@ -2,12 +2,28 @@ use std::process; use golgi::{messages::SsbMessageContent, GolgiError, Sbot}; +// Golgi is an asynchronous library so we must call it from within an +// async function. The `GolgiError` type encapsulates all possible +// error variants for the library. async fn run() -> Result<(), GolgiError> { + // Attempt to connect to an sbot instance using the default IP address, + // port and network key (aka. capabilities key). let mut sbot_client = Sbot::init(None, None).await?; + // Alternatively, we could specify a non-standard IP and port. + // let ip_port = "127.0.0.1:8021".to_string(); + // let mut sbot_client = Sbot::init(Some(ip_port), None).await?; + + // Call the `whoami` RPC method to retrieve the public key for the sbot + // identity. This is our 'local' public key. let id = sbot_client.whoami().await?; + + // Print the public key (identity) to `stdout`. println!("whoami: {}", id); + // Compose an SSB `about` message type. + // The `SsbMessageContent` type has many variants and allows for a high + // degree of control when creating messages. let name = SsbMessageContent::About { about: id.clone(), name: Some("golgi".to_string()), @@ -19,27 +35,46 @@ async fn run() -> Result<(), GolgiError> { start_datetime: None, }; + // Publish the name message. The `publish` method returns a reference to + // the published message. let name_msg_ref = sbot_client.publish(name).await?; + + // Print the message reference to `stdout`. println!("name_msg_ref: {}", name_msg_ref); + // Compose an SSB `post` message type. let post = SsbMessageContent::Post { text: "golgi go womp womp".to_string(), mentions: None, }; + // Publish the post. let post_msg_ref = sbot_client.publish(post).await?; + + // Print the post reference to `stdout`. println!("post_msg_ref: {}", post_msg_ref); + // Golgi also exposes convenience methods for some of the most common + // message types. Here we see an example of a convenience method for + // posting a description message. The description is for the local + // identity, ie. we are publishing this about "ourself". let post_msg_ref = sbot_client .publish_description("this is a description") .await?; + + // Print the description message reference to `stdout`. println!("description: {}", post_msg_ref); let author: String = id.clone(); println!("author: {:?}", author); + + // Retrieve the description for the given public key (identity). let description = sbot_client.get_description(&author).await?; + + // Print the description to `stdout`. println!("found description: {:?}", description); + // Compose and publish another `post` message type. let post = SsbMessageContent::Post { text: "golgi go womp womp2".to_string(), mentions: None, @@ -51,6 +86,9 @@ async fn run() -> Result<(), GolgiError> { Ok(()) } +// Enable an async main function and execute the `run()` function, +// catching any errors and printing them to `stderr` before exiting the +// process. #[async_std::main] async fn main() { if let Err(e) = run().await { diff --git a/examples/ssb-friends.rs b/examples/ssb-friends.rs index 137d2d2..759d792 100644 --- a/examples/ssb-friends.rs +++ b/examples/ssb-friends.rs @@ -5,76 +5,114 @@ use golgi::{ GolgiError, Sbot, }; +// Golgi is an asynchronous library so we must call it from within an +// async function. The `GolgiError` type encapsulates all possible +// error variants for the library. async fn run() -> Result<(), GolgiError> { + // Attempt to connect to an sbot instance using the default IP address, + // port and network key (aka. capabilities key). let mut sbot_client = Sbot::init(None, None).await?; + // Call the `whoami` RPC method to retrieve the public key for the sbot + // identity. This is our 'local' public key. let id = sbot_client.whoami().await?; + + // Print the public key (identity) to `stdout`. println!("whoami: {}", id); - // test ids to follow and block + // Define IDs (public keys) to follow and block. let to_follow = String::from("@5Pt3dKy2HTJ0mWuS78oIiklIX0gBz6BTfEnXsbvke9c=.ed25519"); let to_block = String::from("@7Y4nwfQmVtAilEzi5knXdS2gilW7cGKSHXdXoT086LM=.ed25519"); - // follow to_follow + // Set the relationship of the local identity to the `to_follow` identity. + // In this case, the `set_relationship` method publishes a `contact` + // message which defines following as `true` and blocking as `false`. + // A message reference is returned for the published `contact` message. let response = sbot_client .set_relationship(&to_follow, true, false) .await?; + + // Print the message reference to `stdout`. println!("follow_response: {:?}", response); - // block to_block + // Set the relationship of the local identity to the `to_block` identity. + // In this case, the `set_relationship` method publishes a `contact` + // message which defines following as `false` and blocking as `true`. + // A message reference is returned for the published `contact` message. let response = sbot_client.set_relationship(&to_block, false, true).await?; + + // Print the message reference to `stdout`. println!("follow_response: {:?}", response); - // print all users you are following + // Golgi also exposes convenience methods for following and blocking. + // Here is an example of a simpler way to follow an identity. + let _follow_response = sbot_client.follow(&to_follow).await?; + + // Blocking can be achieved in a similar fashion. + let _block_response = sbot_client.block(&to_block).await?; + + // Get a list of peers within 1 hop of the local identity. let follows = sbot_client .friends_hops(FriendsHops { max: 1, start: None, - // doesnt seem like reverse does anything, currently + // The `reverse` parameter is not currently implemented in `go-sbot`. reverse: Some(false), }) .await?; + + // Print the list of peers to `stdout`. println!("follows: {:?}", follows); - // print if you are following to_follow (should be true) + // Determine if an identity (`source`) is following a second identity (`dest`). + // This method will return `true` or `false`. let mref = sbot_client .friends_is_following(RelationshipQuery { source: id.clone(), dest: to_follow.clone(), }) .await?; + + // Print the follow status to `stdout`. println!("isfollowingmref: {}", mref); - // print if you are blocking to_block (should be true) + // Determine if an identity (`source`) is blocking a second identity (`dest`). let mref = sbot_client .friends_is_blocking(RelationshipQuery { source: id.clone(), dest: to_block.clone(), }) .await?; + + // Print the block status to `stdout`. println!("isblockingmref: {}", mref); - // print if you are blocking to_follow (should be false) let mref = sbot_client .friends_is_blocking(RelationshipQuery { source: id.clone(), dest: to_follow, }) .await?; + + // Output should be `false`. println!("isblockingmref(should be false): {}", mref); - // print if you are following to_block (should be false) let mref = sbot_client .friends_is_following(RelationshipQuery { source: id, dest: to_block.clone(), }) .await?; + + // Output should be `false`. println!("isfollowingmref(should be false): {}", mref); Ok(()) } +// Enable an async main function and execute the `run()` function, +// catching any errors and printing them to `stderr` before exiting the +// process. #[async_std::main] async fn main() { if let Err(e) = run().await { diff --git a/examples/ssb-invite.rs b/examples/ssb-invite.rs index 5268194..5d5881f 100644 --- a/examples/ssb-invite.rs +++ b/examples/ssb-invite.rs @@ -4,38 +4,69 @@ use kuska_ssb::api::dto::content::PubAddress; use golgi::{messages::SsbMessageContent, GolgiError, Sbot}; +// Golgi is an asynchronous library so we must call it from within an +// async function. The `GolgiError` type encapsulates all possible +// error variants for the library. async fn run() -> Result<(), GolgiError> { + // Attempt to connect to an sbot instance using the default IP address, + // port and network key (aka. capabilities key). let mut sbot_client = Sbot::init(None, None).await?; + // Call the `whoami` RPC method to retrieve the public key for the sbot + // identity. This is our 'local' public key. let id = sbot_client.whoami().await?; + + // Print the public key (identity) to `stdout`. println!("whoami: {}", id); - // publish a pub address message (in order to test accepting invite from other client) + // Compose a `pub` address type message. let pub_address_msg = SsbMessageContent::Pub { address: Some(PubAddress { + // IP address. host: Some("127.0.0.1".to_string()), + // Port. port: 8009, + // Public key. key: id, }), }; + // Publish the `pub` address message. + // This step is required for successful invite code creation. let pub_msg_ref = sbot_client.publish(pub_address_msg).await?; + + // Print the message reference to `stdout`. println!("pub_msg_ref: {}", pub_msg_ref); + // Generate an invite code that can be used 1 time. let invite_code = sbot_client.invite_create(1).await?; + + // Print the invite code to `stdout`. println!("invite (1 use): {:?}", invite_code); + // Generate an invite code that can be used 7 times. let invite_code_2 = sbot_client.invite_create(7).await?; + + // Print the invite code to `stdout`. println!("invite (7 uses): {:?}", invite_code_2); + // Define an invite code. let test_invite = "net:ssbroom2.commoninternet.net:8009~shs:wm8a1zHWjtESv4XSKMWU/rPRhnAoAiSAe4hQSY0UF5A="; + + // Redeem an invite code (initiating a mutual follow between the local + // identity and the identity which generated the code (`wm8a1z...`). let mref = sbot_client.invite_use(test_invite).await?; + + // Print the message reference to `stdout`. println!("mref: {:?}", mref); Ok(()) } +// Enable an async main function and execute the `run()` function, +// catching any errors and printing them to `stderr` before exiting the +// process. #[async_std::main] async fn main() { if let Err(e) = run().await { diff --git a/examples/ssb-stream-example.rs b/examples/ssb-stream-example.rs index f896e4d..8d05342 100644 --- a/examples/ssb-stream-example.rs +++ b/examples/ssb-stream-example.rs @@ -1,56 +1,85 @@ use std::process; use async_std::stream::StreamExt; -use futures::{pin_mut, TryStreamExt}; +use futures::TryStreamExt; use golgi::{ messages::{SsbMessageContentType, SsbMessageValue}, GolgiError, Sbot, }; +// Golgi is an asynchronous library so we must call it from within an +// async function. The `GolgiError` type encapsulates all possible +// error variants for the library. async fn run() -> Result<(), GolgiError> { + // Attempt to connect to an sbot instance using the default IP address, + // port and network key (aka. capabilities key). let mut sbot_client = Sbot::init(None, None).await?; + // Call the `whoami` RPC method to retrieve the public key for the sbot + // identity. This is our 'local' public key. let id = sbot_client.whoami().await?; + + // Print the public key (identity) to `stdout`. println!("whoami: {}", id); let author = id.clone(); - // create a history stream + // Create an ordered stream of all messages authored by the `author` + // identity. let history_stream = sbot_client .create_history_stream(author.to_string()) .await?; - // loop through the results until the end of the stream - pin_mut!(history_stream); // needed for iteration + // Pin the stream to the stack to allow polling of the `future`. + futures::pin_mut!(history_stream); + println!("looping through stream"); + + // Iterate through each element in the stream and match on the `Result`. + // In this case, each element has type `Result`. while let Some(res) = history_stream.next().await { match res { Ok(value) => { + // Print the `SsbMessageValue` of this element to `stdout`. println!("value: {:?}", value); } Err(err) => { - println!("err: {:?}", err); + // Print the `GolgiError` of this element to `stderr`. + eprintln!("err: {:?}", err); } } } + println!("reached end of stream"); - // create a history stream and convert it into a Vec using try_collect - // (if there is any error in the results, it will be raised) + // Create an ordered stream of all messages authored by the `author` + // identity. let history_stream = sbot_client .create_history_stream(author.to_string()) .await?; + + // Collect the stream elements into a `Vec` using + // `try_collect`. A `GolgiError` will be returned from the `run` + // function if any element contains an error. let results: Vec = history_stream.try_collect().await?; + + // Loop through the `SsbMessageValue` elements, printing each one + // to `stdout`. for x in results { println!("x: {:?}", x); } - // example to create a history stream and use a map to convert stream of SsbMessageValue - // into a stream of tuples of (String, SsbMessageContentType) + // Create an ordered stream of all messages authored by the `author` + // identity. let history_stream = sbot_client .create_history_stream(author.to_string()) .await?; + + // Iterate through the elements in the stream and use `map` to convert + // each `SsbMessageValue` element into a tuple of + // `(String, SsbMessageContentType)`. This is an example of stream + // conversion. let type_stream = history_stream.map(|msg| match msg { Ok(val) => { let message_type = val.get_message_type()?; @@ -59,8 +88,15 @@ async fn run() -> Result<(), GolgiError> { } Err(err) => Err(err), }); - pin_mut!(type_stream); // needed for iteration + + // Pin the stream to the stack to allow polling of the `future`. + futures::pin_mut!(type_stream); + println!("looping through type stream"); + + // Iterate through each element in the stream and match on the `Result`. + // In this case, each element has type + // `Result<(String, SsbMessageContentType), GolgiError>`. while let Some(res) = type_stream.next().await { match res { Ok(value) => { @@ -71,12 +107,15 @@ async fn run() -> Result<(), GolgiError> { } } } + println!("reached end of type stream"); - // return Ok Ok(()) } +// Enable an async main function and execute the `run()` function, +// catching any errors and printing them to `stderr` before exiting the +// process. #[async_std::main] async fn main() { if let Err(e) = run().await {