Compare commits

...

50 Commits

Author SHA1 Message Date
glyph 15c5e77da6 Merge pull request 'Add TanglesThread struct import for args' (#61) from tangle_docs_fix into main
Reviewed-on: #61
2022-11-22 13:09:02 +00:00
glyph a42478c169 add TanglesThread struct import for args 2022-11-22 15:07:12 +02:00
glyph 0c083b5ce4 Merge pull request 'Add tangles.thread RPC method and example' (#60) from add_tangles_thread into main
Reviewed-on: #60
2022-11-22 07:56:28 +00:00
glyph ea7fc86ee1 Merge branch 'main' into add_tangles_thread 2022-11-22 07:55:43 +00:00
glyph f6b561ebde clarify tangles.thread doc comment 2022-11-22 09:49:49 +02:00
glyph 8dac8b1a62 remove unneeded imports 2022-11-22 09:44:55 +02:00
glyph 87f75fae94 remove debugging println 2022-11-22 09:44:36 +02:00
glyph a08f3adbef add an example of calling the tangles.thread rpc method 2022-11-18 15:10:56 +02:00
glyph 5c4b92a8bf add tangles.thread rpc method 2022-11-18 15:10:37 +02:00
glyph 195eeb523c make timestamp field an option for SsbMessageKVT and derive eq where partialeq is already derived 2022-11-18 15:04:50 +02:00
glyph 2b37f19a27 Merge pull request 'fix: use new urls' (#58) from decentral1se/golgi:fix-urls into main
Reviewed-on: #58
2022-11-18 07:14:48 +00:00
decentral1se 7024797e0f
fix: use new urls 2022-11-17 19:07:20 +01:00
glyph 9981b64bb2 Merge pull request 'Pass complete args struct to create_history_stream' (#56) from create_history_stream_opts into main
Reviewed-on: #56
2022-08-09 10:15:41 +00:00
glyph ad3a5ed932 Merge branch 'main' into create_history_stream_opts 2022-08-09 10:14:38 +00:00
glyph 457dda6d2d Merge pull request 'Introduce `names` RPC methods' (#53) from names_rpc into main
Reviewed-on: #53
2022-08-09 10:14:02 +00:00
glyph ec5666fe02 Merge branch 'main' into names_rpc 2022-08-09 10:07:23 +00:00
glyph 1335aeb544 bump version 2022-08-09 08:26:39 +01:00
glyph c556373a96 update create_history_stream example 2022-08-09 08:24:53 +01:00
glyph 80e99deb6f pass CreateHistoryStream as arg 2022-08-09 08:24:39 +01:00
glyph e16f567c19 revert friends example code 2022-08-08 08:25:31 +01:00
glyph 821198a400 fix kuska dependency and bump version 2022-08-08 08:13:55 +01:00
glyph 05e2540403 add get_signifier method and call it from get_name 2022-08-08 08:10:13 +01:00
glyph 3fe1a4bbea remove unnecessary imports 2022-08-07 13:17:23 +01:00
notplants 3c37297018 Merge pull request 'Change sbot::init to not panic and instead return an error' (#51) from no-panic into main
Reviewed-on: #51
2022-07-16 05:57:36 +00:00
notplants b24f2e4a06 Combine Sbot and SbotInit errors 2022-07-15 11:16:46 +02:00
glyph 31b432165e introduce names_get_signifier and names_get_image 2022-07-13 09:04:29 +01:00
notplants 48beb4a2e5 Merge branch 'main' of https://git.coopcloud.tech/glyph/golgi into new-rexport 2022-07-12 13:13:31 +02:00
notplants e9667a57be Change sbot::init to not panic and instead return an error 2022-07-12 13:13:22 +02:00
glyph ab86d4fe0b merge main 2022-07-11 08:51:07 +01:00
glyph 22d12f31ac Merge pull request 'Replace SsbMessageValue with SsbMessageKVT in stream examples' (#49) from fix_broken_stream_examples into main
Reviewed-on: #49
2022-07-07 08:16:32 +00:00
notplants fbe7072995 Merge pull request 'Re-export kuska_ssb' (#50) from kuska_ssb into main
Reviewed-on: #50
2022-07-07 07:58:58 +00:00
notplants f41f8b55d2 Reexport kuska_ssb 2022-07-06 12:45:53 +02:00
glyph 15acebbbfa replace SsbMessageValue with SsbMessageKVT in stream examples 2022-07-01 08:58:33 +01:00
glyph 1c44f0e56a Merge pull request 'Remove lockfile from repo' (#48) from remove_lockfile into main
Reviewed-on: #48
2022-07-01 07:41:28 +00:00
glyph 89a98dd6ab add lockfile to git ignore list 2022-06-29 16:01:42 +01:00
glyph e03729907f bump patch version 2022-06-29 16:00:56 +01:00
glyph 175add2c72 remove lockfile 2022-06-29 15:58:39 +01:00
glyph bf7d574064 Merge pull request 'Return KVT from create_history_stream()' (#47) from return_kvt_from_history_stream into main
Reviewed-on: #47
2022-06-29 13:38:55 +00:00
glyph 914ffb70cc fix formatting 2022-06-29 13:56:43 +01:00
glyph 2abe4b5e10 bump version to reflect api change 2022-06-29 13:49:38 +01:00
glyph bb07839691 return kvt instead of value 2022-06-29 13:49:00 +01:00
notplants ca4c1114dd Merge pull request 'Add support for custom keyfile paths' (#41) from keypaths into main
Reviewed-on: #41
2022-06-15 10:27:28 +00:00
notplants 1651b73426 Fix clippy warnings 2022-06-15 12:27:04 +02:00
notplants 1fc56ac8f1 Update kuska-ssb dependency 2022-06-15 12:12:18 +02:00
glyph 2e1e9a79f1 basic names rpc support 2022-06-09 09:15:50 +01:00
notplants 51dc82280a Remove debug statements 2022-05-26 23:11:18 +02:00
notplants 6daddeab9e Debug address 2022-05-26 23:03:43 +02:00
notplants fb115b280f Prefix 127.0.0.1 to address if starts with : 2022-05-26 22:54:19 +02:00
notplants b4987d514a Cargo.toml 2022-05-25 14:01:48 +02:00
notplants 3f3c18b8b7 Add support for custom keyfile paths 2022-05-25 13:49:27 +02:00
15 changed files with 333 additions and 1171 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/target
Cargo.lock

1113
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package]
name = "golgi"
version = "0.1.1"
version = "0.2.4"
edition = "2021"
authors = ["Max Fowler <max@mfowler.info>", "Andrew Reid <glyph@mycelial.technology>"]
readme = "README.md"
@ -16,6 +16,7 @@ async-std = "1.10.0"
async-stream = "0.3.2"
base64 = "0.13.0"
futures = "0.3.21"
log = "0.4"
hex = "0.4.3"
kuska-handshake = { version = "0.2.0", features = ["async_std"] }
kuska-sodiumoxide = "0.2.5-0"

View File

@ -4,8 +4,11 @@ use async_std::stream::StreamExt;
use futures::TryStreamExt;
use golgi::{
api::get_subset::{SubsetQuery, SubsetQueryOptions},
messages::{SsbMessageContentType, SsbMessageValue},
api::{
get_subset::{SubsetQuery, SubsetQueryOptions},
history_stream::CreateHistoryStream,
},
messages::{SsbMessageContentType, SsbMessageKVT},
sbot::Keystore,
GolgiError, Sbot,
};
@ -30,10 +33,11 @@ async fn run() -> Result<(), GolgiError> {
/* HISTORY STREAM EXAMPLE */
let history_stream_args = CreateHistoryStream::new(author.to_string());
// Create an ordered stream of all messages authored by the `author`
// identity.
// identity. Messages are returned as KVTs (Key Value Timestamp).
let history_stream = sbot_client
.create_history_stream(author.to_string())
.create_history_stream(history_stream_args)
.await?;
// Pin the stream to the stack to allow polling of the `future`.
@ -42,12 +46,12 @@ async fn run() -> Result<(), GolgiError> {
println!("looping through stream");
// Iterate through each element in the stream and match on the `Result`.
// In this case, each element has type `Result<SsbMessageValue, GolgiError>`.
// In this case, each element has type `Result<SsbMessageKVT, GolgiError>`.
while let Some(res) = history_stream.next().await {
match res {
Ok(value) => {
// Print the `SsbMessageValue` of this element to `stdout`.
println!("value: {:?}", value);
Ok(kvt) => {
// Print the `SsbMessageKVT` of this element to `stdout`.
println!("kvt: {:?}", kvt);
}
Err(err) => {
// Print the `GolgiError` of this element to `stderr`.
@ -61,15 +65,15 @@ async fn run() -> Result<(), GolgiError> {
// Create an ordered stream of all messages authored by the `author`
// identity.
let history_stream = sbot_client
.create_history_stream(author.to_string())
.create_history_stream(CreateHistoryStream::new(author.to_string()))
.await?;
// Collect the stream elements into a `Vec<SsbMessageValue>` using
// Collect the stream elements into a `Vec<SsbMessageKVT>` using
// `try_collect`. A `GolgiError` will be returned from the `run`
// function if any element contains an error.
let results: Vec<SsbMessageValue> = history_stream.try_collect().await?;
let results: Vec<SsbMessageKVT> = history_stream.try_collect().await?;
// Loop through the `SsbMessageValue` elements, printing each one
// Loop through the `SsbMessageKVT` elements, printing each one
// to `stdout`.
for x in results {
println!("x: {:?}", x);
@ -78,17 +82,18 @@ async fn run() -> Result<(), GolgiError> {
// Create an ordered stream of all messages authored by the `author`
// identity.
let history_stream = sbot_client
.create_history_stream(author.to_string())
.create_history_stream(CreateHistoryStream::new(author.to_string()))
.await?;
// Iterate through the elements in the stream and use `map` to convert
// each `SsbMessageValue` element into a tuple of
// each `SsbMessageKVT` 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()?;
let tuple: (String, SsbMessageContentType) = (val.signature, message_type);
Ok(kvt) => {
let message_type = kvt.value.get_message_type()?;
// Return the message key and type.
let tuple: (String, SsbMessageContentType) = (kvt.key, message_type);
Ok(tuple)
}
Err(err) => Err(err),

84
examples/tangles.rs Normal file
View File

@ -0,0 +1,84 @@
use std::process;
use async_std::stream::StreamExt;
use golgi::{api::tangles::TanglesThread, sbot::Keystore, 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 initialise a connection to an sbot instance using the
// secret file at the Patchwork path and the default IP address, port
// and network key (aka. capabilities key).
//let mut sbot_client = Sbot::init(Keystore::Patchwork, None, None).await?;
let mut sbot_client =
Sbot::init(Keystore::GoSbot, Some("127.0.0.1:8021".to_string()), 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);
/* TANGLES THREAD EXAMPLE */
// Define the message key that will be used to generate the tangle stream.
// This must be the key of the root message in the thread (ie. the first
// message of the thread).
let msg_key = "%vY53ethgEG1tNsKqmLm6isNSbsu+jwMf/UNGMfUiLm0=.sha256".to_string();
// Instantiate the arguments for the `tangles.thread` RPC by instantiating
// a new instant of the `TanglesThread` struct.
let args = TanglesThread::new(msg_key).keys_values(true, true);
// It's also possible to define the maximum number of messages
// returned from the stream by setting the `limit` value:
// Note: a limit of 3 will return a maximum of 4 messages! The root
// message + 3 other messages in the thread.
// let args = TanglesThread::new(msg_key).keys_values(true, true).limit(3);
// Create an ordered stream of all messages comprising the thread
// in which the given message resides. Messages are returned as KVTs
// (Key Value Timestamp).
let thread_stream = sbot_client.tangles_thread(args).await?;
// Pin the stream to the stack to allow polling of the `future`.
futures::pin_mut!(thread_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<SsbMessageKVT, GolgiError>`.
while let Some(res) = thread_stream.next().await {
match res {
Ok(kvt) => {
// Print the `SsbMessageKVT` of this element to `stdout`.
println!("kvt: {:?}", kvt);
}
Err(err) => {
// Print the `GolgiError` of this element to `stderr`.
eprintln!("err: {:?}", err);
}
}
}
println!("reached end of stream");
// Take a look at the `examples/streams.rs` file in this repo for more
// ways of handling streams.
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 {
eprintln!("Application error: {}", e);
process::exit(1);
}
}

View File

@ -5,10 +5,12 @@
//! - [`Sbot::get_about_info`]
//! - [`Sbot::get_about_message_stream`]
//! - [`Sbot::get_description`]
//! - [`Sbot::get_image`]
//! - [`Sbot::get_latest_about_message`]
//! - [`Sbot::get_name`]
//! - [`Sbot::get_name_and_image`]
//! - [`Sbot::get_profile_info`]
//! - [`Sbot::get_signifier`]
use std::collections::HashMap;
@ -19,6 +21,7 @@ use crate::{
error::GolgiError,
messages::{SsbMessageContentType, SsbMessageValue},
sbot::Sbot,
utils,
};
impl Sbot {
@ -82,6 +85,40 @@ impl Sbot {
Ok(about_message_stream)
}
/// Get the latest `image` value for a peer. The value is a blob reference.
///
/// # Example
///
/// ```rust
/// use golgi::{Sbot, GolgiError, sbot::Keystore};
///
/// async fn image_info() -> Result<(), GolgiError> {
/// let mut sbot_client = Sbot::init(Keystore::Patchwork, None, None).await?;
///
/// let ssb_id = "@zqshk7o2Rpd/OaZ/MxH6xXONgonP1jH+edK9+GZb/NY=.ed25519";
///
/// let image = sbot_client.get_image(ssb_id).await?;
///
/// println!("peer {} is identified by {}", ssb_id, image);
///
/// Ok(())
/// }
/// ```
pub async fn get_image(&mut self, ssb_id: &str) -> Result<String, GolgiError> {
let mut sbot_connection = self.get_sbot_connection().await?;
let req_id = sbot_connection
.client
.names_get_image_for_req_send(ssb_id)
.await?;
utils::get_async(
&mut sbot_connection.rpc_reader,
req_id,
utils::string_res_parse,
)
.await
}
/// Get the value of the latest `about` type message, containing the given
/// `key`, for a peer.
///
@ -186,8 +223,16 @@ impl Sbot {
&mut self,
ssb_id: &str,
) -> Result<HashMap<String, String>, GolgiError> {
let keys_to_search_for = vec!["name", "description", "image"];
self.get_about_info(ssb_id, keys_to_search_for).await
let key_to_search_for = vec!["description"];
let description = self.get_about_info(ssb_id, key_to_search_for).await?;
let mut profile_info = self.get_name_and_image(ssb_id).await?;
// extend the `profile_info` HashMap by adding the key-value from the
// `description` HashMap; `profile_info` now contains all three
// key-value pairs
profile_info.extend(description.into_iter());
Ok(profile_info)
}
/// Get the latest `name` and `image` values for a peer. This method can
@ -232,8 +277,15 @@ impl Sbot {
&mut self,
ssb_id: &str,
) -> Result<HashMap<String, String>, GolgiError> {
let keys_to_search_for = vec!["name", "image"];
self.get_about_info(ssb_id, keys_to_search_for).await
let mut name_and_image: HashMap<String, String> = HashMap::new();
let name = self.get_name(ssb_id).await?;
let image = self.get_image(ssb_id).await?;
name_and_image.insert("name".to_string(), name);
name_and_image.insert("image".to_string(), image);
Ok(name_and_image)
}
/// Get the latest values for the provided keys from the `about` type
@ -335,7 +387,8 @@ impl Sbot {
Ok(profile_info)
}
/// Get the latest `name` value for a peer.
/// Get the latest `name` value for a peer. The public key of the peer
/// will be returned if no `name` value is found.
///
/// # Example
///
@ -347,17 +400,15 @@ impl Sbot {
///
/// let ssb_id = "@zqshk7o2Rpd/OaZ/MxH6xXONgonP1jH+edK9+GZb/NY=.ed25519";
///
/// if let Some(name) = sbot_client.get_name(ssb_id).await? {
/// println!("peer {} is named {}", ssb_id, name)
/// } else {
/// eprintln!("no name found for peer {}", ssb_id)
/// }
/// let name = sbot_client.get_name(ssb_id).await?;
///
/// println!("peer {} is named {}", ssb_id, name);
///
/// Ok(())
/// }
/// ```
pub async fn get_name(&mut self, ssb_id: &str) -> Result<Option<String>, GolgiError> {
self.get_latest_about_message(ssb_id, "name").await
pub async fn get_name(&mut self, ssb_id: &str) -> Result<String, GolgiError> {
self.get_signifier(ssb_id).await
}
/// Get the latest `description` value for a peer.
@ -384,4 +435,39 @@ impl Sbot {
pub async fn get_description(&mut self, ssb_id: &str) -> Result<Option<String>, GolgiError> {
self.get_latest_about_message(ssb_id, "description").await
}
/// Get the latest `name` value (signifier) for a peer. The public key of
/// the peer will be returned if no `name` value is found.
///
/// # Example
///
/// ```rust
/// use golgi::{Sbot, GolgiError, sbot::Keystore};
///
/// async fn name_info() -> Result<(), GolgiError> {
/// let mut sbot_client = Sbot::init(Keystore::Patchwork, None, None).await?;
///
/// let ssb_id = "@zqshk7o2Rpd/OaZ/MxH6xXONgonP1jH+edK9+GZb/NY=.ed25519";
///
/// let name = sbot_client.get_signifier(ssb_id).await?;
///
/// println!("peer {} is named {}", ssb_id, name);
///
/// Ok(())
/// }
/// ```
pub async fn get_signifier(&mut self, ssb_id: &str) -> Result<String, GolgiError> {
let mut sbot_connection = self.get_sbot_connection().await?;
let req_id = sbot_connection
.client
.names_get_signifier_req_send(ssb_id)
.await?;
utils::get_async(
&mut sbot_connection.rpc_reader,
req_id,
utils::string_res_parse,
)
.await
}
}

View File

@ -12,7 +12,7 @@ use crate::{error::GolgiError, messages::SsbMessageValue, sbot::Sbot, utils};
pub use kuska_ssb::api::dto::content::{SubsetQuery, SubsetQueryOptions};
impl Sbot {
/// Make a subset query, as defined by the [Subset replication for SSB specification](https://github.com/ssb-ngi-pointer/ssb-subset-replication-spec).
/// Make a subset query, as defined by the [Subset replication for SSB specification](https://github.com/ssbc/ssb-subset-replication-spec).
///
/// Calls the `partialReplication. getSubset` RPC method.
///

View File

@ -5,25 +5,32 @@
//! - [`Sbot::create_history_stream`]
use async_std::stream::Stream;
use kuska_ssb::api::dto::CreateHistoryStreamIn;
pub use kuska_ssb::api::dto::CreateHistoryStreamIn as CreateHistoryStream;
use crate::{error::GolgiError, messages::SsbMessageValue, sbot::Sbot, utils};
use crate::{error::GolgiError, messages::SsbMessageKVT, sbot::Sbot, utils};
impl Sbot {
/// Call the `createHistoryStream` RPC method.
/// Call the `createHistoryStream` RPC method. Returns messages in the form
/// of KVTs (Key Value Timestamp).
///
/// # Example
///
/// ```rust
/// use async_std::stream::StreamExt;
/// use golgi::{Sbot, GolgiError, sbot::Keystore};
/// use golgi::{
/// Sbot,
/// GolgiError,
/// sbot::Keystore,
/// api::history_stream::CreateHistoryStream
/// };
///
/// async fn history() -> Result<(), GolgiError> {
/// let mut sbot_client = Sbot::init(Keystore::Patchwork, None, None).await?;
///
/// let ssb_id = "@zqshk7o2Rpd/OaZ/MxH6xXONgonP1jH+edK9+GZb/NY=.ed25519".to_string();
///
/// let history_stream = sbot_client.create_history_stream(ssb_id).await?;
/// let args = CreateHistoryStream::new(ssb_id);
/// let history_stream = sbot_client.create_history_stream(args).await?;
///
/// history_stream.for_each(|msg| {
/// match msg {
@ -37,20 +44,16 @@ impl Sbot {
/// ```
pub async fn create_history_stream(
&mut self,
id: String,
) -> Result<impl Stream<Item = Result<SsbMessageValue, GolgiError>>, GolgiError> {
args: CreateHistoryStream,
) -> Result<impl Stream<Item = Result<SsbMessageKVT, GolgiError>>, GolgiError> {
let mut sbot_connection = self.get_sbot_connection().await?;
let args = CreateHistoryStreamIn::new(id);
let req_id = sbot_connection
.client
.create_history_stream_req_send(&args)
.await?;
let history_stream = utils::get_source_stream(
sbot_connection.rpc_reader,
req_id,
utils::ssb_message_res_parse,
)
.await;
let history_stream =
utils::get_source_stream(sbot_connection.rpc_reader, req_id, utils::kvt_res_parse)
.await;
Ok(history_stream)
}
}

View File

@ -6,6 +6,7 @@ pub mod history_stream;
pub mod invite;
pub mod private;
pub mod publish;
pub mod tangles;
pub mod whoami;
pub use crate::sbot::*;

61
src/api/tangles.rs Normal file
View File

@ -0,0 +1,61 @@
//! Take a reference to the root message of a thread and return a stream of all
//! messages in the thread. This includes the root message and all replies.
//!
//! Implements the following methods:
//!
//! - [`Sbot::tangles_thread`]
use async_std::stream::Stream;
pub use kuska_ssb::api::dto::TanglesThread;
use crate::{error::GolgiError, messages::SsbMessageKVT, sbot::Sbot, utils};
impl Sbot {
/// Call the `tanglesThread` RPC method. Returns messages in the form
/// of KVTs (Key Value Timestamp).
///
/// # Example
///
/// ```rust
/// use async_std::stream::StreamExt;
/// use golgi::{
/// Sbot,
/// GolgiError,
/// api::tangles::TanglesThread,
/// sbot::Keystore
/// };
///
/// async fn tangle() -> Result<(), GolgiError> {
/// let mut sbot_client = Sbot::init(Keystore::Patchwork, None, None).await?;
///
/// let msg_key = "%kmXb3MXtBJaNugcEL/Q7G40DgcAkMNTj3yhmxKHjfCM=.sha256";
///
/// let args = TanglesThread::new(msg_key).keys_values(true, true);
/// let tangles_thread = sbot_client.tangles_thread(msg_id).await?;
///
/// tangles_thread.for_each(|msg| {
/// match msg {
/// Ok(kvt) => println!("msg kvt: {:?}", kvt),
/// Err(e) => eprintln!("error: {}", e),
/// }
/// }).await;
///
/// Ok(())
/// }
/// ```
pub async fn tangles_thread(
&mut self,
args: TanglesThread,
) -> Result<impl Stream<Item = Result<SsbMessageKVT, GolgiError>>, GolgiError> {
let mut sbot_connection = self.get_sbot_connection().await?;
let req_id = sbot_connection
.client
.tangles_thread_req_send(&args)
.await?;
let thread_stream =
utils::get_source_stream(sbot_connection.rpc_reader, req_id, utils::kvt_res_parse)
.await;
Ok(thread_stream)
}
}

View File

@ -77,7 +77,7 @@ impl std::fmt::Display for GolgiError {
// TODO: improve this variant with a context message
// then have the core display msg be: "SSB RPC error: {}", context
GolgiError::Rpc(ref err) => write!(f, "SSB RPC failure: {}", err),
GolgiError::Sbot(ref err) => write!(f, "Sbot returned an error response: {}", err),
GolgiError::Sbot(ref err) => write!(f, "Sbot encountered an error: {}", err),
GolgiError::SigilLink(ref context) => write!(f, "SSB blob ID error: {}", context),
GolgiError::SerdeJson(_) => write!(f, "Failed to serialize JSON slice"),
//GolgiError::WhoAmI(ref err) => write!(f, "{}", err),

View File

@ -15,7 +15,7 @@
//! API for interacting with an sbot instance and uses the
//! [kuska-ssb](https://github.com/Kuska-ssb) libraries to make RPC calls.
//! Development efforts are currently oriented towards
//! [go-sbot](https://github.com/cryptoscope/ssb) interoperability.
//! [go-sbot](https://github.com/ssbc/go-ssb) interoperability.
//!
//! ## Features
//!
@ -48,7 +48,7 @@
//! // Call the `whoami` RPC method to retrieve the public key for the sbot
//! // identity.
//! let id = sbot_client.whoami().await?;
//!
//!
//! // Print the public key (identity) to `stdout`.
//! println!("{}", id);
//!
@ -76,3 +76,4 @@ pub mod sbot;
pub mod utils;
pub use crate::{error::GolgiError, sbot::Sbot};
pub use kuska_ssb;

View File

@ -32,7 +32,7 @@ pub struct SsbMessageValue {
}
/// Message content types.
#[derive(Debug, PartialEq)]
#[derive(Debug, Eq, PartialEq)]
#[allow(missing_docs)]
pub enum SsbMessageContentType {
About,
@ -99,6 +99,6 @@ impl SsbMessageValue {
pub struct SsbMessageKVT {
pub key: String,
pub value: SsbMessageValue,
pub timestamp: f64,
pub timestamp: Option<f64>,
pub rts: Option<f64>,
}

View File

@ -20,6 +20,10 @@ pub enum Keystore {
Patchwork,
/// GoSbot default keystore path: `.ssb-go/secret` in the user's home directory.
GoSbot,
/// GoSbot keystore in a custom location
CustomGoSbot(String),
/// Patchwork keystore in a custom location
CustomPatchwork(String),
}
/// A struct representing a connection with a running sbot.
@ -54,12 +58,16 @@ impl Sbot {
ip_port: Option<String>,
net_id: Option<String>,
) -> Result<Sbot, GolgiError> {
let address = if ip_port.is_none() {
let mut address = if ip_port.is_none() {
"127.0.0.1:8008".to_string()
} else {
ip_port.unwrap()
};
if address.starts_with(':') {
address = format!("127.0.0.1{}", address);
}
let network_id = if net_id.is_none() {
discovery::ssb_net_id()
} else {
@ -67,12 +75,36 @@ impl Sbot {
};
let OwnedIdentity { pk, sk, id } = match keystore {
Keystore::Patchwork => keystore::from_patchwork_local()
.await
.expect("couldn't read local secret"),
Keystore::GoSbot => keystore::from_gosbot_local()
.await
.expect("couldn't read local secret"),
Keystore::Patchwork => keystore::from_patchwork_local().await.map_err(|_err| {
GolgiError::Sbot(
"sbot initialization error: couldn't read local patchwork secret from default location".to_string(),
)
})?,
Keystore::GoSbot => keystore::from_gosbot_local().await.map_err(|_err| {
GolgiError::Sbot(
"sbot initialization error: couldn't read local go-sbot secret from default location".to_string(),
)
})?,
Keystore::CustomGoSbot(key_path) => {
keystore::from_custom_gosbot_keypath(key_path.to_string())
.await
.map_err(|_err| {
GolgiError::Sbot(format!(
"sbot initialization error: couldn't read local go-sbot secret from: {}",
key_path
))
})?
}
Keystore::CustomPatchwork(key_path) => {
keystore::from_custom_patchwork_keypath(key_path.to_string())
.await
.map_err(|_err| {
GolgiError::Sbot(format!(
"sbot initialization error: couldn't read local patchwork secret from: {}",
key_path
))
})?
}
};
Ok(Self {

View File

@ -76,7 +76,7 @@ where
if id == req_no {
match msg {
RecvMsg::RpcResponse(_type, body) => {
return f(&body).map_err(|err| err);
return f(&body);
}
RecvMsg::ErrorResponse(message) => {
return Err(GolgiError::Sbot(message));