Parse json into SsbMessageValue
This commit is contained in:
parent
bbb3a41662
commit
c3d00837cb
@ -11,3 +11,7 @@ license = "LGPL-3.0-only"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
regex = "1.5.4"
|
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),
|
Blob(String),
|
||||||
Contact(String),
|
Contact(String),
|
||||||
GetAboutMsgs(String),
|
GetAboutMsgs(String),
|
||||||
|
GetRelationship(String),
|
||||||
Invite(String),
|
Invite(String),
|
||||||
Publish(String),
|
Publish(String),
|
||||||
WhoAmI(String),
|
WhoAmI(String),
|
||||||
@ -22,6 +23,7 @@ pub enum SbotCliError {
|
|||||||
InvalidUtf8(Utf8Error),
|
InvalidUtf8(Utf8Error),
|
||||||
// external errors
|
// external errors
|
||||||
InvalidRegex(RegexError),
|
InvalidRegex(RegexError),
|
||||||
|
ParseJson(serde_json::Error),
|
||||||
NoHomeDir,
|
NoHomeDir,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,6 +40,9 @@ impl fmt::Display for SbotCliError {
|
|||||||
}
|
}
|
||||||
SbotCliError::GetAboutMsgs(ref err) => {
|
SbotCliError::GetAboutMsgs(ref err) => {
|
||||||
write!(f, "{}", err)
|
write!(f, "{}", err)
|
||||||
|
},
|
||||||
|
SbotCliError::GetRelationship(ref err) => {
|
||||||
|
write!(f, "{}", err)
|
||||||
}
|
}
|
||||||
SbotCliError::Invite(ref err) => {
|
SbotCliError::Invite(ref err) => {
|
||||||
write!(f, "{}", err)
|
write!(f, "{}", err)
|
||||||
@ -60,6 +65,9 @@ impl fmt::Display for SbotCliError {
|
|||||||
SbotCliError::InvalidRegex(ref err) => {
|
SbotCliError::InvalidRegex(ref err) => {
|
||||||
write!(f, "{}", err)
|
write!(f, "{}", err)
|
||||||
}
|
}
|
||||||
|
SbotCliError::ParseJson(ref err) => {
|
||||||
|
write!(f, "{}", err)
|
||||||
|
}
|
||||||
SbotCliError::NoHomeDir => {
|
SbotCliError::NoHomeDir => {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
@ -93,3 +101,6 @@ impl From<RegexError> for SbotCliError {
|
|||||||
SbotCliError::InvalidRegex(err)
|
SbotCliError::InvalidRegex(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
212
src/lib.rs
212
src/lib.rs
@ -35,6 +35,10 @@
|
|||||||
//! ## License
|
//! ## License
|
||||||
//!
|
//!
|
||||||
//! LGPL-3.0.
|
//! 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;
|
pub mod error;
|
||||||
mod utils;
|
mod utils;
|
||||||
@ -42,6 +46,43 @@ mod utils;
|
|||||||
pub use crate::error::SbotCliError;
|
pub use crate::error::SbotCliError;
|
||||||
use std::{ffi::OsString, path::PathBuf, process::Command, result::Result};
|
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.
|
/// An `sbotcli` instance with associated methods for querying a Go sbot server.
|
||||||
pub struct Sbot {
|
pub struct Sbot {
|
||||||
/// The path to the `sbotcli` binary.
|
/// The path to the `sbotcli` binary.
|
||||||
@ -57,8 +98,8 @@ impl Sbot {
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `sbotcli_path` - an optional string slice representing a file 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
|
/// * `sbot_working_dir` - an optional string slice representing a directory path where sbotcli stores its data
|
||||||
///
|
///
|
||||||
pub fn init(
|
pub fn init(
|
||||||
sbotcli_path: Option<&str>,
|
sbotcli_path: Option<&str>,
|
||||||
@ -110,7 +151,7 @@ impl Sbot {
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # 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> {
|
pub fn add_blob(&self, file_path: &str) -> Result<String, SbotCliError> {
|
||||||
let output = Command::new(&self.sbotcli_path)
|
let output = Command::new(&self.sbotcli_path)
|
||||||
@ -131,65 +172,154 @@ impl Sbot {
|
|||||||
|
|
||||||
/* CONTACTS */
|
/* 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.
|
/// and returns the message reference. On error: returns the `stderr` output with a description.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # 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> {
|
pub fn set_relationship(&self, id: &str, following: bool, blocking: bool) -> Result<String, SbotCliError> {
|
||||||
let output = Command::new(&self.sbotcli_path)
|
let mut command = Command::new(&self.sbotcli_path);
|
||||||
|
command
|
||||||
.arg("publish")
|
.arg("publish")
|
||||||
.arg("contact")
|
.arg("contact");
|
||||||
.arg("--following")
|
if following {
|
||||||
|
command.arg("--following");
|
||||||
|
}
|
||||||
|
if blocking {
|
||||||
|
command.arg("--blocking");
|
||||||
|
}
|
||||||
|
let output = command
|
||||||
.arg(id)
|
.arg(id)
|
||||||
.output()?;
|
.output()?;
|
||||||
if output.status.success() {
|
if output.status.success() {
|
||||||
let stdout = String::from_utf8(output.stdout)?;
|
let stdout = String::from_utf8(output.stdout)?;
|
||||||
let msg_ref = stdout.trim_end().to_string();
|
let msg_ref = stdout.trim_end().to_string();
|
||||||
|
|
||||||
Ok(msg_ref)
|
Ok(msg_ref)
|
||||||
} else {
|
} else {
|
||||||
let stderr = std::str::from_utf8(&output.stderr)?;
|
let stderr = std::str::from_utf8(&output.stderr)?;
|
||||||
Err(SbotCliError::Contact(format!(
|
Err(SbotCliError::Contact(format!(
|
||||||
"Error following peer: {}",
|
"Error setting relationship with peer: {}",
|
||||||
stderr
|
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.
|
/// 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
|
/// # 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> {
|
pub fn block(&self, id: &str) -> Result<String, SbotCliError> {
|
||||||
let output = Command::new(&self.sbotcli_path)
|
let current_relationship = self.get_relationship(id)?;
|
||||||
.arg("publish")
|
self.set_relationship(id, current_relationship.following, true)
|
||||||
.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
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 */
|
/* GET ABOUT MESSAGES */
|
||||||
|
|
||||||
@ -551,22 +681,4 @@ mod tests {
|
|||||||
let result = 2 + 2;
|
let result = 2 + 2;
|
||||||
assert_eq!(result, 4);
|
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…
x
Reference in New Issue
Block a user