Parse json into SsbMessageValue
This commit is contained in:
parent
bbb3a41662
commit
c3d00837cb
|
@ -11,3 +11,7 @@ license = "LGPL-3.0-only"
|
|||
[dependencies]
|
||||
dirs = "4.0.0"
|
||||
regex = "1.5.4"
|
||||
serde_json = "1.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
ssb-legacy-msg-data = "0.1.4"
|
||||
ssb-multiformats = "0.4.2"
|
||||
|
|
11
src/error.rs
11
src/error.rs
|
@ -13,6 +13,7 @@ pub enum SbotCliError {
|
|||
Blob(String),
|
||||
Contact(String),
|
||||
GetAboutMsgs(String),
|
||||
GetRelationship(String),
|
||||
Invite(String),
|
||||
Publish(String),
|
||||
WhoAmI(String),
|
||||
|
@ -22,6 +23,7 @@ pub enum SbotCliError {
|
|||
InvalidUtf8(Utf8Error),
|
||||
// external errors
|
||||
InvalidRegex(RegexError),
|
||||
ParseJson(serde_json::Error),
|
||||
NoHomeDir,
|
||||
}
|
||||
|
||||
|
@ -38,6 +40,9 @@ impl fmt::Display for SbotCliError {
|
|||
}
|
||||
SbotCliError::GetAboutMsgs(ref err) => {
|
||||
write!(f, "{}", err)
|
||||
},
|
||||
SbotCliError::GetRelationship(ref err) => {
|
||||
write!(f, "{}", err)
|
||||
}
|
||||
SbotCliError::Invite(ref err) => {
|
||||
write!(f, "{}", err)
|
||||
|
@ -60,6 +65,9 @@ impl fmt::Display for SbotCliError {
|
|||
SbotCliError::InvalidRegex(ref err) => {
|
||||
write!(f, "{}", err)
|
||||
}
|
||||
SbotCliError::ParseJson(ref err) => {
|
||||
write!(f, "{}", err)
|
||||
}
|
||||
SbotCliError::NoHomeDir => {
|
||||
write!(
|
||||
f,
|
||||
|
@ -93,3 +101,6 @@ impl From<RegexError> for SbotCliError {
|
|||
SbotCliError::InvalidRegex(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
212
src/lib.rs
212
src/lib.rs
|
@ -35,6 +35,10 @@
|
|||
//! ## License
|
||||
//!
|
||||
//! LGPL-3.0.
|
||||
use serde_json::Value;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use ssb_multiformats::multihash::Multihash;
|
||||
use ssb_legacy_msg_data::LegacyF64;
|
||||
|
||||
pub mod error;
|
||||
mod utils;
|
||||
|
@ -42,6 +46,43 @@ mod utils;
|
|||
pub use crate::error::SbotCliError;
|
||||
use std::{ffi::OsString, path::PathBuf, process::Command, result::Result};
|
||||
|
||||
|
||||
/// HELPER STRUCTS FOR GETTING AND SETTING VALUES FROM SBOT
|
||||
|
||||
/// A struct which represents any ssb message in the log.
|
||||
///
|
||||
/// Modified from https://github.com/sunrise-choir/ssb-validate.
|
||||
///
|
||||
/// Every ssb message in the log has a content field, as a first-level key.
|
||||
/// This content field is further parsed based on the specific type of message.
|
||||
///
|
||||
/// Data type representing the `value` of a message object (`KVT`). More information concerning the
|
||||
/// data model can be found
|
||||
/// in the [`Metadata` documentation](https://spec.scuttlebutt.nz/feed/messages.html#metadata).
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct SsbMessageValue {
|
||||
pub previous: Option<Multihash>,
|
||||
pub author: String,
|
||||
pub sequence: u64,
|
||||
pub timestamp: LegacyF64,
|
||||
pub hash: String,
|
||||
pub content: Value,
|
||||
pub signature: String,
|
||||
}
|
||||
|
||||
/// A struct which represents a relationship with another user (peer).
|
||||
/// Any combination of following and blocking is possible except
|
||||
/// for following=true AND blocking=true.
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct PeerRelationship {
|
||||
following: bool,
|
||||
blocking: bool
|
||||
}
|
||||
|
||||
|
||||
/// SBOT METHODS
|
||||
|
||||
/// An `sbotcli` instance with associated methods for querying a Go sbot server.
|
||||
pub struct Sbot {
|
||||
/// The path to the `sbotcli` binary.
|
||||
|
@ -57,8 +98,8 @@ impl Sbot {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `sbotcli_path` - an optional string slice representing a file path
|
||||
/// * `sbot_working_dir` - an optional string slice representing a directory path
|
||||
/// * `sbotcli_path` - an optional string slice representing the file path to the sbotcli binary
|
||||
/// * `sbot_working_dir` - an optional string slice representing a directory path where sbotcli stores its data
|
||||
///
|
||||
pub fn init(
|
||||
sbotcli_path: Option<&str>,
|
||||
|
@ -110,7 +151,7 @@ impl Sbot {
|
|||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `file_path` - A string slice representing a file path
|
||||
/// * `file_path` - A string slice representing a file path to the blob to be added
|
||||
///
|
||||
pub fn add_blob(&self, file_path: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
|
@ -131,65 +172,154 @@ impl Sbot {
|
|||
|
||||
/* CONTACTS */
|
||||
|
||||
/// Follow a peer.
|
||||
/// Set relationship with a peer.
|
||||
///
|
||||
/// Calls `sbotcli publish contact --following [id]`. On success: trims the trailing whitespace from `stdout`
|
||||
/// A relationship has two properties:
|
||||
/// - following (either true or false)
|
||||
/// - blocking (either true or false)
|
||||
///
|
||||
/// This is an idempotent function which sets the relationship with a peer for following and blocking,
|
||||
/// based on the arguments that are passed in.
|
||||
///
|
||||
/// It uses `sbotcli publish contact [id]`. Passing the --following and/or --blocking flags,
|
||||
/// if following or blocking is set to true, respectively.
|
||||
///
|
||||
/// On success: trims the trailing whitespace from `stdout`
|
||||
/// and returns the message reference. On error: returns the `stderr` output with a description.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id` - A string slice representing an id (profile reference / public key)
|
||||
/// * `id` - A string slice representing an id (profile reference / public key) of the account to follow
|
||||
/// * `following` - a boolean representing whether to follow this account or not
|
||||
/// * `blocking` - a boolean representing whether to block this account or not
|
||||
///
|
||||
pub fn follow(&self, id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
pub fn set_relationship(&self, id: &str, following: bool, blocking: bool) -> Result<String, SbotCliError> {
|
||||
let mut command = Command::new(&self.sbotcli_path);
|
||||
command
|
||||
.arg("publish")
|
||||
.arg("contact")
|
||||
.arg("--following")
|
||||
.arg("contact");
|
||||
if following {
|
||||
command.arg("--following");
|
||||
}
|
||||
if blocking {
|
||||
command.arg("--blocking");
|
||||
}
|
||||
let output = command
|
||||
.arg(id)
|
||||
.output()?;
|
||||
if output.status.success() {
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
let msg_ref = stdout.trim_end().to_string();
|
||||
|
||||
Ok(msg_ref)
|
||||
} else {
|
||||
let stderr = std::str::from_utf8(&output.stderr)?;
|
||||
Err(SbotCliError::Contact(format!(
|
||||
"Error following peer: {}",
|
||||
"Error setting relationship with peer: {}",
|
||||
stderr
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Block a peer.
|
||||
/// Get the latest value of a current relationship with a peer.
|
||||
///
|
||||
/// We determine the value of the relationship by looking up the most recent contact
|
||||
/// message made about that peer.
|
||||
///
|
||||
/// If no contact message is found, then a relationship of following=false blocking=false
|
||||
/// is returned.
|
||||
///
|
||||
/// Calls `sbotcli bytype --limit 1 --reverse contact`.
|
||||
///
|
||||
/// On success: parses a PeerRelationship from the ssb_message or returns one with default values.
|
||||
/// On error: returns the `stderr` output with a description.
|
||||
///
|
||||
/// # arguments
|
||||
///
|
||||
/// * `id` - a string slice representing the id (profile reference / public key)
|
||||
/// of the peer to look up the relationship with.
|
||||
///
|
||||
pub fn get_relationship(&self, _id: &str) -> Result<PeerRelationship, SbotCliError> {
|
||||
// TODO: need to filter this query down to the actual user it should be for
|
||||
// right now this is not a real query
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("bytype")
|
||||
.arg("--limit")
|
||||
.arg("1")
|
||||
.arg("--reverse")
|
||||
.arg("contact")
|
||||
.output()?;
|
||||
if output.status.success() {
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
println!("stdout: {:?}", stdout);
|
||||
let ssb_message : SsbMessageValue = serde_json::from_str(&stdout).map_err(|err| {
|
||||
SbotCliError::GetRelationship(format!("error deserializing ssb message while getting relationship to peer: {}", err))
|
||||
})?;
|
||||
let relationship : PeerRelationship = serde_json::from_value(ssb_message.content).map_err(|err| {
|
||||
SbotCliError::GetRelationship(format!("error deserializing ssb message content while getting relationship to peer: {}", err))
|
||||
})?;
|
||||
Ok(relationship)
|
||||
} else {
|
||||
let stderr = std::str::from_utf8(&output.stderr)?;
|
||||
Err(SbotCliError::GetRelationship(format!(
|
||||
"error getting relationship to peer: {}",
|
||||
stderr
|
||||
)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Follow a peer. Does not change whatever blocking relationship user already has with this peer.
|
||||
///
|
||||
/// On success: trims the trailing whitespace from `stdout`
|
||||
/// and returns the message reference. On error: returns the `stderr` output with a description.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id` - A string slice representing an id (profile reference / public key) of the account to follow
|
||||
///
|
||||
pub fn follow(&self, id: &str) -> Result<String, SbotCliError> {
|
||||
let current_relationship = self.get_relationship(id)?;
|
||||
self.set_relationship(id, true, current_relationship.blocking)
|
||||
}
|
||||
|
||||
/// Block a peer. Does not change whatever following relationship user already has with this peer.
|
||||
///
|
||||
/// Calls `sbotcli publish contact --blocking [id]`. On success: trims the trailing whitespace from `stdout` and returns the message reference. On error: returns the `stderr` output with a description.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id` - A string slice representing an id (profile reference / public key)
|
||||
/// * `id` - A string slice representing an id (profile reference / public key) of the account to block
|
||||
///
|
||||
pub fn block(&self, id: &str) -> Result<String, SbotCliError> {
|
||||
let output = Command::new(&self.sbotcli_path)
|
||||
.arg("publish")
|
||||
.arg("contact")
|
||||
.arg("--blocking")
|
||||
.arg(id)
|
||||
.output()?;
|
||||
if output.status.success() {
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
let msg_ref = stdout.trim_end().to_string();
|
||||
|
||||
Ok(msg_ref)
|
||||
} else {
|
||||
let stderr = std::str::from_utf8(&output.stderr)?;
|
||||
Err(SbotCliError::Contact(format!(
|
||||
"Error blocking peer: {}",
|
||||
stderr
|
||||
)))
|
||||
}
|
||||
let current_relationship = self.get_relationship(id)?;
|
||||
self.set_relationship(id, current_relationship.following, true)
|
||||
}
|
||||
|
||||
/// Unfollow a peer. Does not change whatever blocking relationship user already has with this peer.
|
||||
///
|
||||
/// On success: trims the trailing whitespace from `stdout`
|
||||
/// and returns the message reference. On error: returns the `stderr` output with a description.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id` - A string slice representing an id (profile reference / public key) of the account to follow
|
||||
///
|
||||
pub fn unfollow(&self, id: &str) -> Result<String, SbotCliError> {
|
||||
let current_relationship = self.get_relationship(id)?;
|
||||
self.set_relationship(id, false, current_relationship.blocking)
|
||||
}
|
||||
|
||||
/// Unblock a peer. Does not change whatever following relationship user already has with this peer.
|
||||
///
|
||||
/// Calls `sbotcli publish contact --blocking [id]`. On success: trims the trailing whitespace from `stdout` and returns the message reference. On error: returns the `stderr` output with a description.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `id` - A string slice representing an id (profile reference / public key) of the account to block
|
||||
///
|
||||
pub fn unblock(&self, id: &str) -> Result<String, SbotCliError> {
|
||||
let current_relationship = self.get_relationship(id)?;
|
||||
self.set_relationship(id, current_relationship.following, false)
|
||||
}
|
||||
|
||||
/* GET ABOUT MESSAGES */
|
||||
|
||||
|
@ -551,22 +681,4 @@ mod tests {
|
|||
let result = 2 + 2;
|
||||
assert_eq!(result, 4);
|
||||
}
|
||||
|
||||
use crate::Sbot;
|
||||
|
||||
#[test]
|
||||
fn new_test() {
|
||||
let sbot = Sbot::init(Some("/Users/notplants/go/bin/sbotcli"), None).unwrap();
|
||||
let self_id = sbot.whoami().unwrap();
|
||||
let profile_image = "/Users/notplants/computer/docs/avi/plants.png";
|
||||
let result = sbot.add_blob(profile_image);
|
||||
// sbot.publish_image(profile_image);
|
||||
// let result = sbot.get_about_message("image", &self_id);
|
||||
// println!("get_profile_image");
|
||||
match result {
|
||||
Ok(res) => println!("success: {:?}", res),
|
||||
Err(err) => println!("error: {:?}", err)
|
||||
}
|
||||
assert_eq!(2, 2);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue