Refactor to use an object-oriented pattern for Sbot #2
|
@ -10,4 +10,5 @@ readme = "README.md"
|
|||
license = "AGPL-3.0-only"
|
||||
|
||||
[dependencies]
|
||||
dirs = "4.0.0"
|
||||
regex = "1.5.4"
|
||||
|
|
15
README.md
15
README.md
|
@ -5,12 +5,21 @@ Rust wrapper around the Go `sbotcli` ScuttleButt tool ([cryptoscope/ssb](https:/
|
|||
## Example
|
||||
|
||||
```rust
|
||||
use peach_sbotcli::{Sbot, SbotCliError};
|
||||
|
||||
fn example() -> Result<(), SbotCliError> {
|
||||
// uses default paths for `sbotcli` and `go-sbot` working directory
|
||||
let sbot = Sbot::init(None, None)?;
|
||||
|
||||
let id = "@p13zSAiOpguI9nsawkGijsnMfWmFd5rlUNpzekEE+vI=.ed25519";
|
||||
|
||||
let follow_ref = peach_sbotcli::follow(id)?;
|
||||
let block_ref = peach_sbotcli::block(id)?;
|
||||
let follow_ref = sbot.follow(id)?;
|
||||
let block_ref = sbot.block(id)?;
|
||||
|
||||
let invite_code = peach_sbotcli::create_invite()?;
|
||||
let invite_code = sbot.create_invite()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//! Custom error implementations.
|
||||
|
||||
use core::str::Utf8Error;
|
||||
use regex::Error as RegexError;
|
||||
use std::{error, fmt, io::Error as IoError, string::FromUtf8Error};
|
||||
|
@ -20,6 +22,7 @@ pub enum SbotCliError {
|
|||
InvalidUtf8(Utf8Error),
|
||||
// external errors
|
||||
InvalidRegex(RegexError),
|
||||
NoHomeDir,
|
||||
}
|
||||
|
||||
impl error::Error for SbotCliError {}
|
||||
|
@ -57,6 +60,12 @@ impl fmt::Display for SbotCliError {
|
|||
SbotCliError::InvalidRegex(ref err) => {
|
||||
write!(f, "{}", err)
|
||||
}
|
||||
SbotCliError::NoHomeDir => {
|
||||
write!(
|
||||
f,
|
||||
"Error initialising sbotcli: no home directory could be determined"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
121
src/lib.rs
121
src/lib.rs
|
@ -5,15 +5,18 @@
|
|||
//! ## Example
|
||||
//!
|
||||
//! ```rust
|
||||
//! use peach_sbotcli::SbotCliError;
|
||||
//! use peach_sbotcli::{Sbot, SbotCliError};
|
||||
//!
|
||||
//! fn example() -> Result<(), SbotCliError> {
|
||||
//! // uses default paths for `sbotcli` and `go-sbot` working directory
|
||||
//! let sbot = Sbot::init(None, None)?;
|
||||
//!
|
||||
//! let id = "@p13zSAiOpguI9nsawkGijsnMfWmFd5rlUNpzekEE+vI=.ed25519";
|
||||
//!
|
||||
//! let follow_ref = peach_sbotcli::follow(id)?;
|
||||
//! let block_ref = peach_sbotcli::block(id)?;
|
||||
//! let follow_ref = sbot.follow(id)?;
|
||||
//! let block_ref = sbot.block(id)?;
|
||||
//!
|
||||
//! let invite_code = peach_sbotcli::create_invite()?;
|
||||
//! let invite_code = sbot.create_invite()?;
|
||||
//!
|
||||
//! Ok(())
|
||||
//! }
|
||||
|
@ -36,9 +39,63 @@
|
|||
pub mod error;
|
||||
mod utils;
|
||||
|
||||
use std::{process::Command, result::Result};
|
||||
|
||||
pub use crate::error::SbotCliError;
|
||||
use std::{ffi::OsString, path::PathBuf, process::Command, result::Result};
|
||||
|
||||
/// An `sbotcli` instance with associated methods for querying a Go sbot server.
|
||||
pub struct Sbot {
|
||||
/// The path to the `sbotcli` binary.
|
||||
pub sbotcli_path: OsString,
|
||||
/// The working directory of the `go-sbot` instance (where the Scuttlebutt database is stored).
|
||||
pub sbot_working_dir: OsString,
|
||||
}
|
||||
|
||||
impl Sbot {
|
||||
/// Initialise an `sbotcli` instance. Sets default path parameters for the `sbotcli` binary and
|
||||
/// `go-sbot` working directory if none are provided. Alternatively, uses the provided
|
||||
/// parameter(s) to define the path(s).
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `sbotcli_path` - an optional string slice representing a file path
|
||||
/// * `sbot_working_dir` - an optional string slice representing a directory path
|
||||
///
|
||||
pub fn init(
|
||||
sbotcli_path: Option<&str>,
|
||||
sbot_working_dir: Option<&str>,
|
||||
) -> Result<Self, SbotCliError> {
|
||||
// set default path for sbotcli
|
||||
let mut path = PathBuf::from(r"/usr/bin/sbotcli");
|
||||
|
||||
// overwrite the default path if one has been provided via the `sbotcli_path` arg
|
||||
if let Some(p) = sbotcli_path {
|
||||
path = PathBuf::from(p);
|
||||
};
|
||||
|
||||
let mut dir = PathBuf::new();
|
||||
if let Some(d) = sbot_working_dir {
|
||||
// define the `sbot_working_dir` using the provided arg
|
||||
dir.push(d)
|
||||
} else {
|
||||
// set default path for go-sbot working directory if no arg is provided
|
||||
// returns `Option<PathBuf>`
|
||||
let home_dir = dirs::home_dir();
|
||||
// it's possible that the home directory cannot be determined, hence the `match`
|
||||
match home_dir {
|
||||
Some(home_dir_path) => {
|
||||
dir.push(home_dir_path);
|
||||
dir.push(".ssb-go");
|
||||
}
|
||||
// return an error if the home directory could not be determined
|
||||
None => return Err(SbotCliError::NoHomeDir),
|
||||
}
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
sbotcli_path: path.into_os_string(),
|
||||
sbot_working_dir: dir.into_os_string(),
|
||||
})
|
||||
}
|
||||
|
||||
/* BLOBS */
|
||||
|
||||
|
@ -55,8 +112,8 @@ pub use crate::error::SbotCliError;
|
|||
///
|
||||
/// * `file_path` - A string slice representing a file path
|
||||
///
|
||||
pub fn add_blob(file_path: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn add_blob(&self, file_path: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("blobs")
|
||||
.arg("add")
|
||||
.arg(file_path)
|
||||
|
@ -83,8 +140,8 @@ pub fn add_blob(file_path: &str) -> Result<String, SbotCliError> {
|
|||
///
|
||||
/// * `id` - A string slice representing an id (profile reference / public key)
|
||||
///
|
||||
pub fn follow(id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn follow(&self, id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("publish")
|
||||
.arg("contact")
|
||||
.arg("--following")
|
||||
|
@ -112,8 +169,8 @@ pub fn follow(id: &str) -> Result<String, SbotCliError> {
|
|||
///
|
||||
/// * `id` - A string slice representing an id (profile reference / public key)
|
||||
///
|
||||
pub fn block(id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn block(&self, id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("publish")
|
||||
.arg("contact")
|
||||
.arg("--blocking")
|
||||
|
@ -141,8 +198,8 @@ pub fn block(id: &str) -> Result<String, SbotCliError> {
|
|||
/// Calls `sbotcli bytype --limit 10 --reverse about`. On success: parses the `stdout` to extract the
|
||||
/// `name` and returns it. On error: returns the `stderr` output with a description.
|
||||
///
|
||||
pub fn get_name() -> Result<Option<String>, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn get_name(&self) -> Result<Option<String>, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("bytype")
|
||||
.arg("--limit")
|
||||
.arg("10")
|
||||
|
@ -174,8 +231,8 @@ pub fn get_name() -> Result<Option<String>, SbotCliError> {
|
|||
///
|
||||
/// * `invite` - A string slice representing an invite code
|
||||
///
|
||||
pub fn accept_invite(invite: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn accept_invite(&self, invite: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("invite")
|
||||
.arg("accept")
|
||||
.arg(invite)
|
||||
|
@ -197,8 +254,8 @@ pub fn accept_invite(invite: &str) -> Result<String, SbotCliError> {
|
|||
///
|
||||
/// Calls `sbotcli invite create`. On success: trims the trailing whitespace from `stdout` and returns the invite code. On error: returns the `stderr` output with a description.
|
||||
///
|
||||
pub fn create_invite() -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn create_invite(&self) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("invite")
|
||||
.arg("create")
|
||||
.output()?;
|
||||
|
@ -227,8 +284,8 @@ pub fn create_invite() -> Result<String, SbotCliError> {
|
|||
/// * `blob_ref` - A string slice representing a blob reference
|
||||
/// * `id` - A string slice representing an id (profile reference / public key)
|
||||
///
|
||||
pub fn publish_image(blob_ref: &str, id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn publish_image(&self, blob_ref: &str, id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("publish")
|
||||
.arg("about")
|
||||
.arg("--image")
|
||||
|
@ -261,8 +318,8 @@ pub fn publish_image(blob_ref: &str, id: &str) -> Result<String, SbotCliError> {
|
|||
/// * `description` - A string slice representing a profile description (bio)
|
||||
/// * `id` - A string slice representing an id (profile reference / public key)
|
||||
///
|
||||
pub fn publish_description(description: &str, id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn publish_description(&self, description: &str, id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("publish")
|
||||
.arg("about")
|
||||
.arg("--description")
|
||||
|
@ -292,8 +349,8 @@ pub fn publish_description(description: &str, id: &str) -> Result<String, SbotCl
|
|||
/// * `name` - A string slice representing a profile name (bio)
|
||||
/// * `id` - A string slice representing an id (profile reference / public key)
|
||||
///
|
||||
pub fn publish_name(id: &str, name: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn publish_name(&self, id: &str, name: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("publish")
|
||||
.arg("about")
|
||||
.arg("--name")
|
||||
|
@ -322,8 +379,8 @@ pub fn publish_name(id: &str, name: &str) -> Result<String, SbotCliError> {
|
|||
///
|
||||
/// * `text` - A string slice representing a post (public message)
|
||||
///
|
||||
pub fn publish_post(text: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn publish_post(&self, text: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("publish")
|
||||
.arg("post")
|
||||
.arg(text)
|
||||
|
@ -353,8 +410,8 @@ pub fn publish_post(text: &str) -> Result<String, SbotCliError> {
|
|||
/// * `id` - A string slice representing an id (profile reference / public key)
|
||||
/// * `msg` - A string slice representing a private message
|
||||
///
|
||||
pub fn publish_private_message(id: &str, msg: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new("sbotcli")
|
||||
pub fn publish_private_message(&self, id: &str, msg: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("publish")
|
||||
.arg("post")
|
||||
.arg("--recps")
|
||||
|
@ -382,8 +439,11 @@ pub fn publish_private_message(id: &str, msg: &str) -> Result<String, SbotCliErr
|
|||
/// Calls `sbotcli call whoami`. On success: parses the `stdout` to extract the ID and returns it.
|
||||
/// On error: returns the `stderr` output with a description.
|
||||
///
|
||||
pub fn whoami() -> Result<Option<String>, SbotCliError> {
|
||||
let output = Command::new("sbotcli").arg("call").arg("whoami").output()?;
|
||||
pub fn whoami(&self) -> Result<Option<String>, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("call")
|
||||
.arg("whoami")
|
||||
.output()?;
|
||||
if output.status.success() {
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
let id = utils::regex_finder(r#""id": "(.*)"\n"#, &stdout)?;
|
||||
|
@ -397,6 +457,7 @@ pub fn whoami() -> Result<Option<String>, SbotCliError> {
|
|||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
|
Loading…
Reference in New Issue