From 0952ad9220810599e520efd1f9769464493cba9c Mon Sep 17 00:00:00 2001 From: notplants Date: Tue, 28 Dec 2021 14:57:30 -0500 Subject: [PATCH] Working with KVT types --- Cargo.lock | 399 ++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 5 +- examples/ssb-client.rs | 57 +----- src/sbot.rs | 25 +-- src/utils.rs | 164 +++++++++++++---- 5 files changed, 544 insertions(+), 106 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 323f046..2ba3a1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aead" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +dependencies = [ + "generic-array", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -202,6 +211,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + [[package]] name = "blocking" version = "1.1.0" @@ -222,6 +240,12 @@ version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "c_linked_list" version = "1.1.1" @@ -252,6 +276,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cipher" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" +dependencies = [ + "generic-array", +] + [[package]] name = "concurrent-queue" version = "1.2.2" @@ -261,6 +294,21 @@ dependencies = [ "cache-padded", ] +[[package]] +name = "cpufeatures" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +dependencies = [ + "libc", +] + +[[package]] +name = "cpuid-bool" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" + [[package]] name = "crossbeam-utils" version = "0.8.5" @@ -271,6 +319,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "crypto-mac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "ctor" version = "0.1.21" @@ -281,6 +339,28 @@ dependencies = [ "syn", ] +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + [[package]] name = "dirs" version = "2.0.2" @@ -302,6 +382,34 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ed25519" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74e1069e39f1454367eb2de793ed062fac4c35c2934b76a81d90dd9abcd28816" +dependencies = [ + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +dependencies = [ + "curve25519-dalek", + "ed25519", + "rand", + "sha2", + "zeroize", +] + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "event-listener" version = "2.5.1" @@ -427,6 +535,16 @@ version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "get_if_addrs" version = "0.5.3" @@ -449,6 +567,17 @@ dependencies = [ "libc", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.3" @@ -457,7 +586,7 @@ checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -486,6 +615,8 @@ dependencies = [ "kuska-ssb", "serde", "serde_json", + "ssb-legacy-msg-data", + "ssb-multiformats", ] [[package]] @@ -509,6 +640,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hmac" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +dependencies = [ + "crypto-mac", + "digest", +] + [[package]] name = "indexmap" version = "1.7.0" @@ -653,6 +794,12 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "parking" version = "2.0.0" @@ -690,6 +837,22 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "poly1305" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7456bc1ad2d4cf82b3a016be4c2ac48daf11bf990c1603ebd447fe6f30fca8" +dependencies = [ + "cpuid-bool", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" + [[package]] name = "proc-macro2" version = "1.0.32" @@ -708,6 +871,46 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + [[package]] name = "redox_syscall" version = "0.2.10" @@ -723,7 +926,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom", + "getrandom 0.2.3", "redox_syscall", ] @@ -750,6 +953,22 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c9613b5a66ab9ba26415184cfc41156594925a9cf3a2057e57f31ff145f6568" +[[package]] +name = "ryu-ecmascript" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79f19ef8ea9a62575f9422da5ca81b1529ccf9be3e2150bf175f36612af0575c" + +[[package]] +name = "salsa20" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "399f290ffc409596022fce5ea5d4138184be4784f2b28c62c59f0d8389059a15" +dependencies = [ + "cipher", + "zeroize", +] + [[package]] name = "same-file" version = "1.0.6" @@ -791,6 +1010,19 @@ dependencies = [ "serde", ] +[[package]] +name = "sha2" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +dependencies = [ + "block-buffer", + "cfg-if 1.0.0", + "cpufeatures", + "digest", + "opaque-debug", +] + [[package]] name = "signal-hook" version = "0.3.10" @@ -810,6 +1042,12 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" + [[package]] name = "slab" version = "0.4.5" @@ -826,6 +1064,63 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "ssb-crypto" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a055e461165ec87134bb33a521e7bb4e49f306ed14db31cab221dc649b2762a2" +dependencies = [ + "base64 0.13.0", + "curve25519-dalek", + "ed25519-dalek", + "hmac", + "rand", + "sha2", + "subtle", + "x25519-dalek", + "xsalsa20poly1305", + "zerocopy", + "zeroize", +] + +[[package]] +name = "ssb-legacy-msg-data" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7984181963c32bfbf791779c8e7a2591d87274a7f40e30da70caf6acf60658d8" +dependencies = [ + "base64 0.13.0", + "encode_unicode", + "indexmap", + "ryu-ecmascript", + "serde", + "serde_derive", + "strtod2", +] + +[[package]] +name = "ssb-multiformats" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f56858fd2b4e75b01522b8e402f4d5d35cf7a4cbcb53b60b72d28782f755cac" +dependencies = [ + "base64 0.13.0", + "serde", + "ssb-crypto", +] + +[[package]] +name = "strtod2" +version = "0.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071feed13cd8d6b39c6fc6f163c6cafd4d9da2f416fe48d5daa3c847d99876dc" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.82" @@ -837,6 +1132,18 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "unicode-xid", +] + [[package]] name = "thiserror" version = "1.0.30" @@ -857,12 +1164,28 @@ dependencies = [ "syn", ] +[[package]] +name = "typenum" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" + [[package]] name = "unicode-xid" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + [[package]] name = "value-bag" version = "1.0.0-alpha.8" @@ -896,6 +1219,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -1023,3 +1352,69 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "x25519-dalek" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2392b6b94a576b4e2bf3c5b2757d63f10ada8020a2e4d08ac849ebcf6ea8e077" +dependencies = [ + "curve25519-dalek", + "rand_core", + "zeroize", +] + +[[package]] +name = "xsalsa20poly1305" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0304c336e98d753428f7b3d8899d60b8a87a961ef50bdfc44af0c1bea2651ce5" +dependencies = [ + "aead", + "poly1305", + "salsa20", + "subtle", + "zeroize", +] + +[[package]] +name = "zerocopy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6580539ad917b7c026220c4b3f2c08d52ce54d6ce0dc491e66002e35388fab46" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d498dbd1fd7beb83c86709ae1c33ca50942889473473d287d56ce4770a18edfb" +dependencies = [ + "proc-macro2", + "syn", + "synstructure", +] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] diff --git a/Cargo.toml b/Cargo.toml index 18620f3..51096c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,7 @@ kuska-handshake = { version = "0.2.0", features = ["async_std"] } kuska-sodiumoxide = "0.2.5-0" # waiting for a pr merge upstream kuska-ssb = { path = "../ssb" } -# try to replace with miniserde -serde = "1" +serde = { version = "1", features = ["derive"] } serde_json = "1" +ssb-legacy-msg-data = "0.1.4" +ssb-multiformats = "0.4.2" \ No newline at end of file diff --git a/examples/ssb-client.rs b/examples/ssb-client.rs index 8c09f4f..37c779c 100644 --- a/examples/ssb-client.rs +++ b/examples/ssb-client.rs @@ -1,6 +1,6 @@ use std::process; -use kuska_ssb::api::dto::content::{SubsetQuery, TypedMessage}; +use kuska_ssb::api::dto::content::{SubsetQuery, TypedMessage, Post}; use golgi::error::GolgiError; use golgi::sbot::Sbot; @@ -11,58 +11,17 @@ async fn run() -> Result<(), GolgiError> { let id = sbot_client.whoami().await?; println!("{}", id); -// /* -// let name = TypedMessage::About { -// about: id, -// name: Some("golgi".to_string()), -// title: None, -// branch: None, -// image: None, -// description: None, -// location: None, -// start_datetime: None, -// }; -// -// let name_msg_ref = sbot_client.publish(name).await?; -// println!("{}", name_msg_ref); - -// let post = TypedMessage::Post { -// text: "golgi go womp womp".to_string(), -// mentions: None, -// }; -// -// let post_msg_ref = sbot_client.publish(post).await?; -// println!("{}", post_msg_ref); - -// -// let post_msg_ref = sbot_client -// .publish_description("this is a description") -// .await?; -// println!("description: {}", post_msg_ref); -// */ - - let author = "@L/z54cbc8V1kL1/MiBhpEKuN3QJkSoZYNaukny3ghIs=.ed25519".to_string(); -// let query = SubsetQuery::Type { -// op: "type".to_string(), -// string: "post".to_string(), -// }; - let query = SubsetQuery::Type { - op: "author".to_string(), - string: author, - }; - let query_response = sbot_client.getsubset(query).await?; - println!("{}", query_response); + println!("Calling create_history"); + let hist_response = sbot_client.create_history_stream(author).await?; + println!("hist: {:?}", hist_response); + let posts: Vec = hist_response.iter().flat_map(|msg| msg.into_post()).collect(); -// println!("Calling log"); -// let log_response = sbot_client.log().await?; -// println!("log: {}", log_response); - -// println!("Calling create_history"); -// let hist_response = sbot_client.create_history_stream(author).await?; -// println!("hist: {:?}", hist_response); + for post in posts { + println!("post: {:?}", post); + } Ok(()) } diff --git a/src/sbot.rs b/src/sbot.rs index 2228193..fc80b1a 100644 --- a/src/sbot.rs +++ b/src/sbot.rs @@ -22,6 +22,7 @@ use serde_json::Value; use crate::error::GolgiError; use crate::utils; +use crate::utils::{SsbMessageValue, KVT}; /// The Scuttlebutt identity, keys and configuration parameters for connecting to a local sbot /// instance, as well as handles for calling RPC methods and receiving responses. @@ -94,11 +95,10 @@ impl Sbot { /// Call the `partialReplication getSubset` RPC method and return a vector /// of messages as KVTs (key, value, timestamp). // TODO: add args for `descending` and `page` (max number of msgs in response) - pub async fn getsubset(&mut self, query: SubsetQuery) -> Result { + pub async fn getsubset(&mut self, query: SubsetQuery) -> Result, GolgiError> { let req_id = self.client.getsubset_req_send(query).await?; - println!("getting subbset!"); - utils::get_async(&mut self.rpc_reader, req_id, utils::getsubset_res_parse).await + utils::get_async_until_eof(&mut self.rpc_reader, req_id, utils::kvt_res_parse).await } /// Call the `whoami` RPC method and return an `id`. @@ -114,7 +114,7 @@ impl Sbot { pub async fn log(&mut self) -> Result { let req_id = self.client.log_req_send().await?; - utils::get_async(&mut self.rpc_reader, req_id, utils::getsubset_res_parse) + utils::get_async(&mut self.rpc_reader, req_id, utils::string_res_parse) .await } @@ -163,20 +163,11 @@ impl Sbot { self.publish(msg).await } - /* - pub async fn publish_post(&mut self, post: Post) -> Result { - let req_id = self.client.publish_req_send(post).await?; - - utils::get_async(&mut self.rpc_reader, req_id, utils::publish_res_parse).await - } - */ - - /// Call the `createHistoryStream` RPC method and print the output. - pub async fn create_history_stream(&mut self, id: String) -> Result, GolgiError> { + /// Call the `createHistoryStream` RPC method and return a vector + /// of SsbMessageValue. + pub async fn create_history_stream(&mut self, id: String) -> Result, GolgiError> { let args = CreateHistoryStreamIn::new(id); let req_id = self.client.create_history_stream_req_send(&args).await?; - // TODO: message_res_parse is currently throwing "Failed to serializ JSON slice" -// utils::get_async_until_eof(&mut self.rpc_reader, req_id, utils::message_res_parse).await - utils::get_async_until_eof(&mut self.rpc_reader, req_id, utils::json_res_parse).await + utils::get_async_until_eof(&mut self.rpc_reader, req_id, utils::ssb_message_res_parse).await } } diff --git a/src/utils.rs b/src/utils.rs index 4dd5b7d..f8a025a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,51 +1,139 @@ -/* - -use kuska_handshake::async_std::BoxStream; -use kuska_sodiumoxide::crypto::sign::ed25519; -use kuska_ssb::discovery; -use kuska_ssb::keystore; -use kuska_ssb::keystore::OwnedIdentity; -*/ use std::fmt::Debug; - use async_std::io::Read; -use kuska_ssb::api::dto::WhoAmIOut; use serde_json::Value; +use serde::{Serialize, Deserialize}; +use kuska_ssb::api::dto::WhoAmIOut; use kuska_ssb::feed::{Feed, Message}; use kuska_ssb::rpc::{RecvMsg, RequestNo, RpcReader}; +use kuska_ssb::api::dto::content::{Post, Vote}; +use kuska_ssb::api::dto::content::TypedMessage; + +use ssb_legacy_msg_data::LegacyF64; +use ssb_multiformats::multihash::Multihash; use crate::error::GolgiError; -pub fn getsubset_res_parse(body: &[u8]) -> Result { - // TODO: cleanup with proper error handling etc. - Ok(std::str::from_utf8(body).unwrap().to_string()) + +/// 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, + pub author: String, + pub sequence: u64, + pub timestamp: LegacyF64, + pub hash: String, + pub content: Value, + pub signature: String, } -// parses a kvt +impl SsbMessageValue { + pub fn get_message_type(&self) -> String { + let msg_type: String = self.content.get("type").map(|msg_type| msg_type.to_string()).unwrap_or_else(|| "none".to_string()); + msg_type + } + + pub fn into_post(self) -> Result { + let p: Post = serde_json::from_value(self.content)?; + Ok(p) + } + + pub fn into_vote(self) -> Result { + let p: Vote = serde_json::from_value(self.content)?; + Ok(p) + } + + // NOTE: this doesnt work, because the arms return two different types + // but maybe there is a way to do type inheritance? + // this SO post says you dont deserialize directly into enum variants + // https://stackoverflow.com/questions/59460464/how-do-i-use-serde-to-deserialize-into-a-specific-enum-variant +// pub fn into_typed_message(self) -> Result { +// let msg_type = self.get_message_type(); +// let msg = match msg_type { +// "post" => { +// let p: Post = serde_json::from_value(self.content)?; +// p +// }, +// "vote" => { +// let p: Vote = serde_json::from_value(self.content)?; +// p +// }, +// _ => { +// Err(GolgiError::Sbot("No type included in message content".to_string())) +// } +// }; +// Ok(msg) +// } +} + +/// 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 KVT { + pub key: String, + pub value: SsbMessageValue, + pub timestamp: f64, + pub rts: Option, +} + +/// Function to parse an array of bytes (returned by an rpc call) into a KVT. +/// +/// # Arguments +/// +/// * `body` - An array of u8 to be parsed. +pub fn kvt_res_parse(body: &[u8]) -> Result { + let value: Value = serde_json::from_slice(&body)?; + let kvt: KVT = serde_json::from_value(value)?; + Ok(kvt) +} + +/// Function to parse an array of bytes (returned by an rpc call) into a kuska_ssb::feed::Feed. +/// This data type is a KVT (TODO: link to explain this) +/// +/// # Arguments +/// +/// * `body` - An array of u8 to be parsed. pub fn feed_res_parse(body: &[u8]) -> Result { - Ok(Feed::from_slice(body)?) -} - -pub fn message_res_parse(body: &[u8]) -> Result { - let content = std::str::from_utf8(&body).unwrap().to_string(); - println!("content: {:?}", content); - let message: Message = serde_json::from_slice(body)?; - Ok(message) + let value: Value = serde_json::from_slice(&body)?; + let feed: Feed = serde_json::from_value(value)?; + Ok(feed) } +/// Function to parse an array of bytes (returned by an rpc call) into a String. +/// +/// # Arguments +/// +/// * `body` - An array of u8 to be parsed. pub fn string_res_parse(body: &[u8]) -> Result { // TODO: cleanup with proper error handling etc. Ok(std::str::from_utf8(body).unwrap().to_string()) } +/// Function to parse an array of bytes (returned by an rpc call) into a serde_json::Value. +/// +/// # Arguments +/// +/// * `body` - An array of u8 to be parsed. pub fn json_res_parse(body: &[u8]) -> Result { - let content = std::str::from_utf8(&body).unwrap().to_string(); - println!("content: {:?}", content); let message: Value = serde_json::from_slice(body)?; Ok(message) } +/// Function to parse an array of bytes (returned by an rpc call) into an SsbMessageValue +/// +/// # Arguments +/// +/// * `body` - An array of u8 to be parsed. +pub fn ssb_message_res_parse(body: &[u8]) -> Result { + let message: SsbMessageValue = serde_json::from_slice(body)?; + Ok(message) +} + //pub fn publish_res_parse(body: &[u8]) -> Result { pub fn publish_res_parse(body: &[u8]) -> Result { @@ -80,27 +168,20 @@ where F: Fn(&[u8]) -> Result, T: Debug, { - println!("req_no: {:?}", req_no); loop { let (id, msg) = rpc_reader.recv().await?; - println!("id: {:?}", id); - println!("msg: {:?}", msg); if id == req_no { match msg { RecvMsg::RpcResponse(_type, body) => { - let m = std::str::from_utf8(&body).unwrap().to_string(); - println!("msg: {:?}", m); return f(&body).map_err(|err| err); }, RecvMsg::ErrorResponse(message) => { return Err(GolgiError::Sbot(message)); }, RecvMsg::CancelStreamRespose() => { - return Err(GolgiError::Sbot("No RPC response from sbot for request".to_string())); + return Err(GolgiError::Sbot("sbot returned CancelStreamResponse before any content".to_string())); }, - _ => { - println!("empty"); - } + _ => {} } } } @@ -138,15 +219,12 @@ where let parsed_response: Result = f(&body); match parsed_response { Ok(parsed_message) => { - println!("parsed {:?}", parsed_message); messages.push(parsed_message); }, Err(err) => { return Err(err); } } - let display = f(&body)?; - println!("{:?}", display); } RecvMsg::ErrorResponse(message) => { return Err(GolgiError::Sbot(message)); @@ -159,6 +237,19 @@ where Ok(messages) } +/// Takes in an rpc request number, and a handling function, +/// and calls the handling function on all responses which match the request number, +/// and prints out the result of the handling function. +/// +/// This is a function useful for debugging, and only prints the output. +/// +/// # Arguments +/// +/// * `rpc_reader` - A `RpcReader` which can return Messages in a loop +/// * `req_no` - A `RequestNo` of the response to listen for +/// * `f` - A function which takes in an array of u8 and returns a Result. +/// This is a function which parses the response from the RpcReader. T is a generic type, +/// so this parse function can return multiple possible types (String, json, custom struct etc.) pub async fn print_source_until_eof<'a, R, T, F>( rpc_reader: &mut RpcReader, req_no: RequestNo, @@ -175,6 +266,7 @@ where match msg { RecvMsg::RpcResponse(_type, body) => { let display = f(&body)?; + println!("{:?}", display); } RecvMsg::ErrorResponse(message) => { return Err(GolgiError::Sbot(message));