From cc7a1dd97ff5e1d71b5ca11bc10e519bb7597a04 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 26 Oct 2022 12:56:08 -0500 Subject: [PATCH 01/63] Moving stuff from other branch I am creating this new branch and moving my changes over, so I don't have to deal commit merging issues --- Cargo.lock | 2 + Cargo.toml | 4 +- src/ipfs.rs | 40 +++++++++++++++++++ src/ipfs/daemon.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++++ src/ipfs/error.rs | 4 ++ src/ipfs/result.rs | 22 +++++++++++ src/lib.rs | 1 + 7 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/ipfs.rs create mode 100644 src/ipfs/daemon.rs create mode 100644 src/ipfs/error.rs create mode 100644 src/ipfs/result.rs diff --git a/Cargo.lock b/Cargo.lock index 02c27b8..54ad9f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -450,6 +450,8 @@ dependencies = [ "clap", "colored", "did-key", + "serde", + "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b1e2e4c..6a22902 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,4 +11,6 @@ bs58 = "0.4.0" base64 = "0.13.0" clap = { version = "3.2.12", features = ["derive"] } did-key = "0.1.1" -colored = "2.0.0" \ No newline at end of file +colored = "2.0.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.87" \ No newline at end of file diff --git a/src/ipfs.rs b/src/ipfs.rs new file mode 100644 index 0000000..b8fc085 --- /dev/null +++ b/src/ipfs.rs @@ -0,0 +1,40 @@ +use std::collections::HashMap; + +use serde_json::Value; + +use self::{error::IpfsError, result::*}; + +pub mod daemon; +pub mod error; +pub mod result; + +pub trait Ipfs { + fn add(name:&str, path:&str, is_directory:bool) -> Result; + fn bitswap_ledger(peer_id:&str) -> Result; + fn bitswap_reprovide() -> Result; + //Note bitswap_stat is left out because it for diagonostic purposes + fn bitswap_wantlist(peer: &str) -> Result, IpfsError>; + fn get_block(block_cid: &str) -> Result; + //TODO: multihash_alg should be enum + fn put_block(data: &str, multihash_alg: &str, multihash_length: &str, is_pin:bool, allow_big_block:bool, cid_codec:Option) + -> Result; + fn remove_block(block_cid:&str, force:bool) -> Result; + fn block_stats(block_cid:&str) -> Result; + fn get_bootstrap_peers() -> Result, IpfsError>; + fn add_bootstrap_peer(peer:&str) -> Result, IpfsError>; + fn add_bootstrap_defaults() -> Result, IpfsError>; + fn remove_bootstrap_peer(peer:&str) -> Result, IpfsError>; + fn remove_all_bootstrap_peer(peer:&str) -> Result, IpfsError>; + fn get_object_data(path:&str, start:Option, length:Option) + -> Result; + fn cid_to_base32(cid: &str) -> Result; + //format, bases, hashes, commands, and codes endpoints were not included as I think they are mainly for debug + fn edit_config(key:&str, value:Option<&str>, is_bool:bool, is_object:bool) -> Result; + fn apply_profile_config(profile:&str) -> Result; + fn replace_config(path:&str) -> Result; + fn get_config() -> Result; + fn export_dag(cid: &str) -> Result; + //TODO: format should be enum + fn get_dag(cid: &str, codec: &str) -> Result; + fn import_dag(path:&str, pin_roots:bool, allow_big_block:bool) -> Result<(), IpfsError>; +} \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs new file mode 100644 index 0000000..6ebaee4 --- /dev/null +++ b/src/ipfs/daemon.rs @@ -0,0 +1,97 @@ +use crate::ipfs::Ipfs; +use super::{error::IpfsError, result::*}; +use std::collections::HashMap; +pub struct IpfsViaDaemon { + +} +impl Ipfs for IpfsViaDaemon { + fn add(name:&str, path:&str, is_directory:bool) -> Result { + todo!() + } + + fn bitswap_ledger(peer_id:&str) -> Result { + todo!() + } + + fn bitswap_reprovide() -> Result { + todo!() + } + + fn bitswap_wantlist(peer: &str) -> Result, IpfsError> { + todo!() + } + + fn get_block(block_cid: &str) -> Result { + todo!() + } + + fn put_block(data: &str, multihash_alg: &str, multihash_length: &str, is_pin:bool, allow_big_block:bool, cid_codec:Option) + -> Result { + todo!() + } + + fn remove_block(block_cid:&str, force:bool) -> Result { + todo!() + } + + fn block_stats(block_cid:&str) -> Result { + todo!() + } + + fn get_bootstrap_peers() -> Result, IpfsError> { + todo!() + } + + fn add_bootstrap_peer(peer:&str) -> Result, IpfsError> { + todo!() + } + + fn add_bootstrap_defaults() -> Result, IpfsError> { + todo!() + } + + fn remove_bootstrap_peer(peer:&str) -> Result, IpfsError> { + todo!() + } + + fn remove_all_bootstrap_peer(peer:&str) -> Result, IpfsError> { + todo!() + } + + fn get_object_data(path:&str, start:Option, length:Option) + -> Result { + todo!() + } + + fn cid_to_base32(cid: &str) -> Result { + todo!() + } + + fn edit_config(key:&str, value:Option<&str>, is_bool:bool, is_object:bool) -> Result { + todo!() + } + + fn apply_profile_config(profile:&str) -> Result { + todo!() + } + + fn replace_config(path:&str) -> Result { + todo!() + } + + fn get_config() -> Result { + todo!() + } + + fn export_dag(cid: &str) -> Result { + todo!() + } + + fn get_dag(cid: &str, codec: &str) -> Result { + todo!() + } + + fn import_dag(path:&str, pin_roots:bool, allow_big_block:bool) -> Result<(), IpfsError> { + todo!() + } +} \ No newline at end of file diff --git a/src/ipfs/error.rs b/src/ipfs/error.rs new file mode 100644 index 0000000..1954ea9 --- /dev/null +++ b/src/ipfs/error.rs @@ -0,0 +1,4 @@ + +pub struct IpfsError{ + +} \ No newline at end of file diff --git a/src/ipfs/result.rs b/src/ipfs/result.rs new file mode 100644 index 0000000..2102c67 --- /dev/null +++ b/src/ipfs/result.rs @@ -0,0 +1,22 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AddedData{ + bytes:i64, + hash:String, + name:String, + size:String +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Ledger{ + exchanged: i64, + peer: String, + recv: i64, + sent: i64, + value: i64 +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct IpfsBlock{ + key: String, + size: i32 +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 52958ec..97e4791 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1 +1,2 @@ pub mod cmd; +pub mod ipfs; From 3e5e7704baaa38cafab2f2c023bd9588be364600 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Fri, 28 Oct 2022 18:52:06 -0500 Subject: [PATCH 02/63] IPFS Trait Complete --- Cargo.lock | 7 ++++ Cargo.toml | 1 + src/ipfs.rs | 51 ++++++++++------------------ src/ipfs/daemon.rs | 84 +++++++--------------------------------------- src/ipfs/error.rs | 4 --- src/ipfs/result.rs | 22 ------------ 6 files changed, 38 insertions(+), 131 deletions(-) delete mode 100644 src/ipfs/error.rs delete mode 100644 src/ipfs/result.rs diff --git a/Cargo.lock b/Cargo.lock index 54ad9f6..73625c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + [[package]] name = "arrayref" version = "0.3.6" @@ -445,6 +451,7 @@ dependencies = [ name = "fission" version = "0.1.0" dependencies = [ + "anyhow", "base64 0.13.0", "bs58", "clap", diff --git a/Cargo.toml b/Cargo.toml index 6a22902..e72a364 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +anyhow = "1.0.66" bs58 = "0.4.0" base64 = "0.13.0" clap = { version = "3.2.12", features = ["derive"] } diff --git a/src/ipfs.rs b/src/ipfs.rs index b8fc085..bf8702f 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -1,40 +1,25 @@ -use std::collections::HashMap; +//use std::collections::{HashMap, btree_map::OccupiedError}; -use serde_json::Value; +use std::collections::HashMap; -use self::{error::IpfsError, result::*}; +use anyhow::Result; +use serde::{Deserialize, Serialize}; pub mod daemon; -pub mod error; -pub mod result; pub trait Ipfs { - fn add(name:&str, path:&str, is_directory:bool) -> Result; - fn bitswap_ledger(peer_id:&str) -> Result; - fn bitswap_reprovide() -> Result; - //Note bitswap_stat is left out because it for diagonostic purposes - fn bitswap_wantlist(peer: &str) -> Result, IpfsError>; - fn get_block(block_cid: &str) -> Result; - //TODO: multihash_alg should be enum - fn put_block(data: &str, multihash_alg: &str, multihash_length: &str, is_pin:bool, allow_big_block:bool, cid_codec:Option) - -> Result; - fn remove_block(block_cid:&str, force:bool) -> Result; - fn block_stats(block_cid:&str) -> Result; - fn get_bootstrap_peers() -> Result, IpfsError>; - fn add_bootstrap_peer(peer:&str) -> Result, IpfsError>; - fn add_bootstrap_defaults() -> Result, IpfsError>; - fn remove_bootstrap_peer(peer:&str) -> Result, IpfsError>; - fn remove_all_bootstrap_peer(peer:&str) -> Result, IpfsError>; - fn get_object_data(path:&str, start:Option, length:Option) - -> Result; - fn cid_to_base32(cid: &str) -> Result; - //format, bases, hashes, commands, and codes endpoints were not included as I think they are mainly for debug - fn edit_config(key:&str, value:Option<&str>, is_bool:bool, is_object:bool) -> Result; - fn apply_profile_config(profile:&str) -> Result; - fn replace_config(path:&str) -> Result; - fn get_config() -> Result; - fn export_dag(cid: &str) -> Result; - //TODO: format should be enum - fn get_dag(cid: &str, codec: &str) -> Result; - fn import_dag(path:&str, pin_roots:bool, allow_big_block:bool) -> Result<(), IpfsError>; + fn add_file(path:&str) -> Result; + fn add_directory(path:&str) -> Result; + fn add_bootstrap(peer_id:&str) -> Result>; + fn connect_to(peer_id:&str) -> Result>; + fn disconect_from(peer_id:&str)-> Result>; + fn config(options:HashMap) -> Result>; +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CidData{ + bytes:i64, + hash:String, + name:String, + size:String } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 6ebaee4..168a5b6 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,97 +1,37 @@ use crate::ipfs::Ipfs; -use super::{error::IpfsError, result::*}; +use super::CidData; +use anyhow::Result; use std::collections::HashMap; pub struct IpfsViaDaemon { } -impl Ipfs for IpfsViaDaemon { - fn add(name:&str, path:&str, is_directory:bool) -> Result { - todo!() - } - - fn bitswap_ledger(peer_id:&str) -> Result { - todo!() - } - - fn bitswap_reprovide() -> Result { - todo!() - } - - fn bitswap_wantlist(peer: &str) -> Result, IpfsError> { - todo!() - } - - fn get_block(block_cid: &str) -> Result { - todo!() - } - - fn put_block(data: &str, multihash_alg: &str, multihash_length: &str, is_pin:bool, allow_big_block:bool, cid_codec:Option) - -> Result { - todo!() - } - - fn remove_block(block_cid:&str, force:bool) -> Result { - todo!() - } - - fn block_stats(block_cid:&str) -> Result { - todo!() - } - - fn get_bootstrap_peers() -> Result, IpfsError> { +impl IpfsViaDaemon { + pub fn new() -> Result { todo!() } - - fn add_bootstrap_peer(peer:&str) -> Result, IpfsError> { - todo!() - } - - fn add_bootstrap_defaults() -> Result, IpfsError> { - todo!() - } - - fn remove_bootstrap_peer(peer:&str) -> Result, IpfsError> { - todo!() - } - - fn remove_all_bootstrap_peer(peer:&str) -> Result, IpfsError> { - todo!() - } - - fn get_object_data(path:&str, start:Option, length:Option) - -> Result { - todo!() - } - - fn cid_to_base32(cid: &str) -> Result { - todo!() - } - - fn edit_config(key:&str, value:Option<&str>, is_bool:bool, is_object:bool) -> Result { - todo!() - } - - fn apply_profile_config(profile:&str) -> Result { +} +impl Ipfs for IpfsViaDaemon { + fn add_file(path:&str) -> Result { todo!() } - fn replace_config(path:&str) -> Result { + fn add_directory(path:&str) -> Result { todo!() } - fn get_config() -> Result { + fn add_bootstrap(peer_id:&str) -> Result> { todo!() } - fn export_dag(cid: &str) -> Result { + fn connect_to(peer_id:&str) -> Result> { todo!() } - fn get_dag(cid: &str, codec: &str) -> Result { + fn disconect_from(peer_id:&str)-> Result> { todo!() } - fn import_dag(path:&str, pin_roots:bool, allow_big_block:bool) -> Result<(), IpfsError> { + fn config(options:HashMap) -> Result> { todo!() } } \ No newline at end of file diff --git a/src/ipfs/error.rs b/src/ipfs/error.rs deleted file mode 100644 index 1954ea9..0000000 --- a/src/ipfs/error.rs +++ /dev/null @@ -1,4 +0,0 @@ - -pub struct IpfsError{ - -} \ No newline at end of file diff --git a/src/ipfs/result.rs b/src/ipfs/result.rs deleted file mode 100644 index 2102c67..0000000 --- a/src/ipfs/result.rs +++ /dev/null @@ -1,22 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AddedData{ - bytes:i64, - hash:String, - name:String, - size:String -} -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Ledger{ - exchanged: i64, - peer: String, - recv: i64, - sent: i64, - value: i64 -} -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct IpfsBlock{ - key: String, - size: i32 -} \ No newline at end of file From 9bf1c5ee6f48cd1bbb01c9ae2f11d1ece399fc28 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 8 Nov 2022 13:42:48 -0700 Subject: [PATCH 03/63] adding what I got so I can review brian's pr --- Cargo.lock | 313 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 +- src/ipfs.rs | 25 ++-- src/ipfs/daemon.rs | 149 +++++++++++++++++++-- src/ipfs/http.rs | 44 +++++++ src/ipfs/options.rs | 34 +++++ 6 files changed, 541 insertions(+), 28 deletions(-) create mode 100644 src/ipfs/http.rs create mode 100644 src/ipfs/options.rs diff --git a/Cargo.lock b/Cargo.lock index 73625c1..0b27680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,17 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +[[package]] +name = "async-trait" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "atomic-polyfill" version = "0.1.10" @@ -167,6 +178,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + [[package]] name = "cfg-if" version = "1.0.0" @@ -452,15 +469,23 @@ name = "fission" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "base64 0.13.0", "bs58", "clap", "colored", "did-key", + "hyper", "serde", "serde_json", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -476,6 +501,45 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + [[package]] name = "generic-array" version = "0.14.6" @@ -534,6 +598,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hash32" version = "0.2.1" @@ -618,6 +701,64 @@ dependencies = [ "hmac 0.8.1", ] +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "indexmap" version = "1.9.1" @@ -728,6 +869,18 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + [[package]] name = "nb" version = "0.1.3" @@ -796,6 +949,18 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkcs8" version = "0.7.6" @@ -1091,6 +1256,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "spin" version = "0.9.4" @@ -1171,6 +1355,68 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +[[package]] +name = "tokio" +version = "1.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "pin-project-lite", + "socket2", + "winapi", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + [[package]] name = "typenum" version = "1.15.0" @@ -1232,6 +1478,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -1329,6 +1585,63 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "wyz" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index e72a364..adb4a4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,6 @@ clap = { version = "3.2.12", features = ["derive"] } did-key = "0.1.1" colored = "2.0.0" serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0.87" \ No newline at end of file +serde_json = "1.0.87" +hyper = {version = "0.14", features = ["client", "http2", "tcp"]} +async-trait = "0.1.58" \ No newline at end of file diff --git a/src/ipfs.rs b/src/ipfs.rs index bf8702f..c1b30e9 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -1,25 +1,20 @@ //use std::collections::{HashMap, btree_map::OccupiedError}; +use async_trait::async_trait; use std::collections::HashMap; use anyhow::Result; -use serde::{Deserialize, Serialize}; pub mod daemon; +pub mod http; +pub mod options; +#[async_trait] pub trait Ipfs { - fn add_file(path:&str) -> Result; - fn add_directory(path:&str) -> Result; - fn add_bootstrap(peer_id:&str) -> Result>; - fn connect_to(peer_id:&str) -> Result>; - fn disconect_from(peer_id:&str)-> Result>; - fn config(options:HashMap) -> Result>; -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CidData{ - bytes:i64, - hash:String, - name:String, - size:String + async fn add_file(&mut self, name:&str, file_name:&str, path:&str, contents:Vec) -> Result; + async fn add_directory(&mut self, path:&str) -> Result; + async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; + async fn connect_to(&mut self, peer_id:&str) -> Result>; + async fn disconect_from(&mut self, peer_id:&str)-> Result>; + async fn config(&mut self, options:HashMap) -> Result>; } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 168a5b6..41433b2 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,37 +1,162 @@ use crate::ipfs::Ipfs; -use super::CidData; -use anyhow::Result; +use anyhow::{Result, bail}; +use super::options::*; +use serde_json::Value; +use std::io::Read; use std::collections::HashMap; +use async_trait::async_trait; +use std::process::{Command, Child}; +use colored::Colorize; +use crate::ipfs::http::HttpHandler; +use std::time::{Duration, SystemTime}; +use std::thread::sleep; + pub struct IpfsViaDaemon { - + http:HttpHandler, + ipfs_process:Child, + is_ipfs_ready:bool, + last_ipfs_output:Vec } impl IpfsViaDaemon { pub fn new() -> Result { - todo!() + IpfsViaDaemon::configure()?; + let proccess = Command::new(IPFS_EXE) + .arg("daemon") + .spawn()?; + println!("{}", ("⚠️ Warning: Ipfs Proccess Started. Please do NOT force close this app⚠️".yellow())); + anyhow::Ok(IpfsViaDaemon{ + ipfs_process: proccess, + http: HttpHandler::new(), + is_ipfs_ready: false, + last_ipfs_output: vec![] + }) + } + fn configure() -> Result<()>{ + //This sets the API's address + let address = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_PORT); + let is_addr_set = Command::new(IPFS_EXE) + .arg("config") + .arg("Addresses.API") + .arg(address) + .spawn()? + .wait()? + .success(); + if !is_addr_set { + bail!("Attempted to set the api address, but failed!"); + } + anyhow::Ok(()) + } + async fn send_request(&mut self, options:&CmdOptions) -> Result>{ + self.await_ready()?; + let response = self.http.send_request(options); + anyhow::Ok(response.await?) + } + fn await_ready(&mut self) -> Result<()>{ + if self.is_ipfs_ready == true { return anyhow::Ok(());} + let start_time = SystemTime::now(); + loop { + match &mut self.ipfs_process.stdout { + Some(out) => { + let mut buffer:Vec = vec![]; + out.read_to_end(&mut buffer)?; + self.last_ipfs_output.append(&mut buffer); + drop(buffer); + + let text_so_far = match std::str::from_utf8(self.last_ipfs_output.as_slice()){ + Ok(text) => text, + Err(_) => "" + }; + if text_so_far.contains(READY_TEXT){ + self.is_ipfs_ready = true; + break; + }else if text_so_far.contains("\n") { + self.last_ipfs_output.clear(); + } + }, + None => () + } + + sleep(Duration::new(SLEEP_LENGTH as u64, 0)); + + let now = SystemTime::now(); + if now.duration_since(start_time)? > Duration::new(BOOT_TIME_OUT as u64, 0) { + bail!("{}","Failed to start ipfs because the timeout reached!!".red()) + } + } + anyhow::Ok(()) } } +#[async_trait] impl Ipfs for IpfsViaDaemon { - fn add_file(path:&str) -> Result { - todo!() + async fn add_file(&mut self, name:&str, file_name:&str, path:&str, contents:Vec) -> Result { + let cmd = "add"; + let args = HashMap::from([ + ("quieter", "true"), + ("cid-version", "1") + ]); + let disposition = format!("form-data; name=\"{}\"; filename=\"{}\"", name, file_name); + let headers = HashMap::from([ + ("Abspath", path), + ("Content-Disposition", &disposition), + ("Content-Type", "application/octet-stream") + ]); + let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); + let result_data = self.send_request(&cmd_options).await?; + return anyhow::Ok(std::str::from_utf8(result_data.as_slice())?.to_string()); } - fn add_directory(path:&str) -> Result { + async fn add_directory(&mut self, path:&str) -> Result { todo!() } - fn add_bootstrap(peer_id:&str) -> Result> { - todo!() + async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { + let cmd = "bootstrap/add"; + let args = HashMap::from([ + ("arg", peer_id) + ]); + let cmd_options = CmdOptions::new(cmd, &args); + let result_data = self.send_request(&cmd_options).await?; + let result_json:Value = serde_json::from_str(std::str::from_utf8(result_data.as_slice())?)?; + let peer_list:Vec = value_to_vec(&result_json, "peer")?; + return anyhow::Ok(peer_list); } - fn connect_to(peer_id:&str) -> Result> { + async fn connect_to(&mut self, peer_id:&str) -> Result> { todo!() } - fn disconect_from(peer_id:&str)-> Result> { + async fn disconect_from(&mut self, peer_id:&str)-> Result> { todo!() } - fn config(options:HashMap) -> Result> { + async fn config(&mut self, options:HashMap) -> Result> { todo!() } +} +impl Drop for IpfsViaDaemon { + fn drop(&mut self) { + self.ipfs_process.kill().unwrap(); + println!("{}", ("Ipfs proccess closed. Feel free to close app whenever. ✅".bright_green())) + } +} +//TODO: This needs to be move to utils +fn value_to_vec(json:&Value, index:&str) -> Result> + where A:Clone + for<'de> serde::Deserialize<'de>{ + anyhow::Ok( match json.get(index) { + Some(list_json) => { + match list_json.as_array() { + Some(list) => { + list.iter().map(|item_json| { + let item:A = match serde_json::from_value(item_json.clone()){ + Ok(x) => x, + Err(_) => panic!("Improperly formatted Json: cannot format type") + }; + item + }).collect() + }, + None => panic!("Improperly formatted Json: Not an Array") + } + }, + None => bail!("Improperly formatted Json: Cant locate index {}", index) + }) } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs new file mode 100644 index 0000000..6ed6b4a --- /dev/null +++ b/src/ipfs/http.rs @@ -0,0 +1,44 @@ +use hyper::body::{HttpBody, Bytes}; +use hyper::{Uri, Client, Request, Method, Body}; +use hyper::client::connect::HttpConnector; +use anyhow::{Result}; +use super::options::{CmdOptions, IPFS_PORT, IPFS_ADDR}; + +pub struct HttpHandler{ + http_client:Client, +} +impl HttpHandler { + pub fn new() -> HttpHandler{ + let client = Client::new(); + return HttpHandler{ + http_client:client + }; + } + pub async fn send_request(&self, options:&CmdOptions) -> Result>{ + let mut arg_str:String = options.args.iter() + .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) + .collect(); + arg_str.pop(); + let request_url = format!("{}:{}/api/v0/{}?{}", IPFS_ADDR, IPFS_PORT, options.cmd, arg_str); + drop(arg_str); + + let mut response = match &options.post_options { + Some(post_options) => { + let mut request = Request::builder() + .method(Method::POST) + .uri(request_url); + for (key, value) in &post_options.headers { + request = request.header(key, value); + } + self.http_client.request(request.body(Body::from((&post_options.body).clone()))?).await? + }, + None => { + let request:Uri = request_url.parse()?; + self.http_client.get(request).await? + } + }; + let response_body = response.body_mut(); + let response_bytes = response_body.data().await.unwrap_or( Ok(Bytes::new()))?.to_vec(); + anyhow::Ok(response_bytes) + } +} \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs new file mode 100644 index 0000000..26a75bc --- /dev/null +++ b/src/ipfs/options.rs @@ -0,0 +1,34 @@ +use std::collections::HashMap; + +pub const IPFS_PORT:u16 = 4867; +pub const IPFS_ADDR:&str = "127.0.0.1"; +pub const IPFS_EXE:&str = "ipfs"; +pub const BOOT_TIME_OUT:u16 = 120;//In seconds +pub const SLEEP_LENGTH:u8 = 1;//In seconds +pub const READY_TEXT:&str = "Daemon is ready"; + +pub struct PostOptions { + pub headers:HashMap, + pub body: Vec +} +pub struct CmdOptions { + pub cmd: String, + pub args: HashMap, + pub post_options: Option +} +impl CmdOptions { + pub fn new(cmd: &str, args: &HashMap<&str, &str>) -> Self{ + let owned_args:HashMap = args.iter() + .map(|(key, val)| (key.to_string(), val.to_string())) + .collect(); + Self { cmd:cmd.to_string(), args:owned_args, post_options: None } + } + pub fn to_post(mut self, headers: &HashMap<&str, &str>, body: &[u8]) -> Self{ + let owned_body = body.to_vec(); + let owned_headers:HashMap = headers.iter() + .map(|(key, val)| (key.to_string(), val.to_string())) + .collect(); + self.post_options = Some(PostOptions { headers: owned_headers, body: owned_body }); + return self; + } +} \ No newline at end of file From af8d47016d92ff8b41da8ff51d05c7a15a1bbcc9 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 9 Nov 2022 11:08:12 -0700 Subject: [PATCH 04/63] ready for testing for a lot of it --- Cargo.lock | 51 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 ++- src/ipfs.rs | 2 +- src/ipfs/daemon.rs | 52 ++++++++++++++++++++++++++++++++++------------ 4 files changed, 93 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b27680..f8885a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -475,6 +475,7 @@ dependencies = [ "clap", "colored", "did-key", + "futures", "hyper", "serde", "serde_json", @@ -501,6 +502,21 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.25" @@ -508,6 +524,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -516,6 +533,34 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.25" @@ -534,10 +579,16 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index adb4a4a..28614d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,4 +16,5 @@ colored = "2.0.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.87" hyper = {version = "0.14", features = ["client", "http2", "tcp"]} -async-trait = "0.1.58" \ No newline at end of file +async-trait = "0.1.58" +futures = "0.3.25" \ No newline at end of file diff --git a/src/ipfs.rs b/src/ipfs.rs index c1b30e9..109e67b 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -16,5 +16,5 @@ pub trait Ipfs { async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; async fn connect_to(&mut self, peer_id:&str) -> Result>; async fn disconect_from(&mut self, peer_id:&str)-> Result>; - async fn config(&mut self, options:HashMap) -> Result>; + async fn config(&mut self, options:HashMap) -> Result<()>; } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 41433b2..5a3240d 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -2,6 +2,7 @@ use crate::ipfs::Ipfs; use anyhow::{Result, bail}; use super::options::*; use serde_json::Value; +use futures::{join, Future}; use std::io::Read; use std::collections::HashMap; use async_trait::async_trait; @@ -85,6 +86,16 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } + async fn swarm_or_bootstrap_cmd(&mut self, cmd:&str, peer_id:&str) -> Result>{ + let args = HashMap::from([ + ("arg", peer_id) + ]); + let cmd_options = CmdOptions::new(cmd, &args); + let result_data = self.send_request(&cmd_options).await?; + let result_json:Value = serde_json::from_str(std::str::from_utf8(result_data.as_slice())?)?; + let peer_list:Vec = value_to_vec(&result_json, "peer")?; + return anyhow::Ok(peer_list); + } } #[async_trait] impl Ipfs for IpfsViaDaemon { @@ -110,27 +121,42 @@ impl Ipfs for IpfsViaDaemon { } async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { - let cmd = "bootstrap/add"; - let args = HashMap::from([ - ("arg", peer_id) - ]); - let cmd_options = CmdOptions::new(cmd, &args); - let result_data = self.send_request(&cmd_options).await?; - let result_json:Value = serde_json::from_str(std::str::from_utf8(result_data.as_slice())?)?; - let peer_list:Vec = value_to_vec(&result_json, "peer")?; - return anyhow::Ok(peer_list); + self.swarm_or_bootstrap_cmd("bootstrap/add", peer_id).await } async fn connect_to(&mut self, peer_id:&str) -> Result> { - todo!() + self.swarm_or_bootstrap_cmd("swarm/connect", peer_id).await } async fn disconect_from(&mut self, peer_id:&str)-> Result> { - todo!() + self.swarm_or_bootstrap_cmd("swarm/disconnect", peer_id).await } - async fn config(&mut self, options:HashMap) -> Result> { - todo!() + async fn config(&mut self, options:HashMap) -> Result<()> { + for (setting, value) in options { + let cleaned_value = value.to_lowercase(); + let is_bool = match cleaned_value.trim() == "true" || cleaned_value.trim() == "false" { + true => "true", + false => "false" + }; + let is_json = match serde_json::from_str::(&value).is_ok() { + true => "true", + false => "false" + }; + let args = HashMap::from([ + ("arg".to_string(), setting.to_string()), + ("arg".to_string(), value.to_string()), + ("bool".to_string(), is_bool.to_string()), + ("json".to_string(), is_json.to_string()) + ]); + let cmd_options = CmdOptions{ + cmd:"config".to_string(), + post_options:None, + args + }; + self.send_request(&cmd_options).await?; + } + anyhow::Ok(()) } } impl Drop for IpfsViaDaemon { From 9dc983177d8ff6186be126e6cb1f6e2e555f9a85 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 15 Nov 2022 13:19:53 -0700 Subject: [PATCH 05/63] first test done We can connect! YAY --- Cargo.lock | 492 +++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 4 +- src/ipfs/daemon.rs | 121 +++++++---- src/ipfs/http.rs | 93 ++++++--- src/ipfs/options.rs | 16 +- src/main.rs | 1 + 6 files changed, 645 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8885a0..59e32b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,6 +184,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +[[package]] +name = "cc" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -246,6 +252,22 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "cortex-m" version = "0.7.6" @@ -442,6 +464,24 @@ dependencies = [ "void", ] +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + [[package]] name = "ff" version = "0.10.1" @@ -472,13 +512,15 @@ dependencies = [ "async-trait", "base64 0.13.0", "bs58", + "bytes", "clap", "colored", "did-key", "futures", - "hyper", + "reqwest", "serde", "serde_json", + "tokio", ] [[package]] @@ -487,6 +529,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -810,6 +867,29 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "1.9.1" @@ -820,6 +900,21 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" + [[package]] name = "itoa" version = "1.0.4" @@ -920,6 +1015,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + [[package]] name = "mio" version = "0.8.5" @@ -929,7 +1030,25 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.42.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] @@ -947,6 +1066,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "once_cell" version = "1.13.0" @@ -959,6 +1088,51 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openssl" +version = "0.10.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_str_bytes" version = "6.1.0" @@ -994,6 +1168,29 @@ dependencies = [ "group 0.11.0", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.42.0", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -1022,6 +1219,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + [[package]] name = "ppv-lite86" version = "0.2.16" @@ -1136,6 +1339,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.6.0" @@ -1153,6 +1365,52 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" +dependencies = [ + "base64 0.13.0", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "riscv" version = "0.7.0" @@ -1198,12 +1456,45 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys 0.36.1", +] + [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "security-framework" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -1265,6 +1556,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.9.9" @@ -1278,6 +1581,15 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "1.3.2" @@ -1316,6 +1628,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "socket2" version = "0.4.7" @@ -1391,6 +1709,20 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -1406,6 +1738,21 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "tokio" version = "1.21.2" @@ -1417,11 +1764,36 @@ dependencies = [ "libc", "memchr", "mio", + "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", + "tokio-macros", "winapi", ] +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.4" @@ -1474,24 +1846,56 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + [[package]] name = "unicode-ident" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "vcell" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -1576,6 +1980,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.83" @@ -1605,6 +2021,16 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1636,6 +2062,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + [[package]] name = "windows-sys" version = "0.42.0" @@ -1643,12 +2082,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_x86_64_msvc 0.42.0", ] [[package]] @@ -1657,24 +2096,48 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + [[package]] name = "windows_aarch64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + [[package]] name = "windows_i686_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + [[package]] name = "windows_i686_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + [[package]] name = "windows_x86_64_gnu" version = "0.42.0" @@ -1687,12 +2150,27 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "windows_x86_64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + [[package]] name = "wyz" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 28614d2..4397dc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,8 @@ did-key = "0.1.1" colored = "2.0.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.87" -hyper = {version = "0.14", features = ["client", "http2", "tcp"]} +reqwest = "0.11.12" +bytes = "1.2.1" +tokio = { version = "1", features = ["full"] } async-trait = "0.1.58" futures = "0.3.25" \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 5a3240d..0d9ed0e 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -2,8 +2,6 @@ use crate::ipfs::Ipfs; use anyhow::{Result, bail}; use super::options::*; use serde_json::Value; -use futures::{join, Future}; -use std::io::Read; use std::collections::HashMap; use async_trait::async_trait; use std::process::{Command, Child}; @@ -15,12 +13,13 @@ use std::thread::sleep; pub struct IpfsViaDaemon { http:HttpHandler, ipfs_process:Child, - is_ipfs_ready:bool, - last_ipfs_output:Vec + is_ipfs_ready:bool } impl IpfsViaDaemon { pub fn new() -> Result { + println!("{}", "Configuring ipfs...".green()); IpfsViaDaemon::configure()?; + println!("{}", "Starting ipfs...".green()); let proccess = Command::new(IPFS_EXE) .arg("daemon") .spawn()?; @@ -28,17 +27,26 @@ impl IpfsViaDaemon { anyhow::Ok(IpfsViaDaemon{ ipfs_process: proccess, http: HttpHandler::new(), - is_ipfs_ready: false, - last_ipfs_output: vec![] + is_ipfs_ready: false }) } fn configure() -> Result<()>{ //This sets the API's address - let address = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_PORT); + //let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); + let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); + let http_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_HTTP_PORT); + //let http_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_HTTP_PORT); + IpfsViaDaemon::config_option("Addresses.API", &api_addr)?; + IpfsViaDaemon::config_option("Addresses.Gateway", &http_addr)?; + anyhow::Ok(()) + } + fn config_option(option:&str, value:&str)-> Result<()>{ + let cmd_str = format!("ipfs {} Addresses.API {}", option, value); + println!("running cmd \"{}\"", cmd_str.blue()); let is_addr_set = Command::new(IPFS_EXE) .arg("config") - .arg("Addresses.API") - .arg(address) + .arg(option) + .arg(value) .spawn()? .wait()? .success(); @@ -47,34 +55,22 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } - async fn send_request(&mut self, options:&CmdOptions) -> Result>{ - self.await_ready()?; - let response = self.http.send_request(options); + async fn send_request(&mut self, options:&CmdOptions, response_handler:F) -> Result + where F: Fn(Vec) -> Result{ + self.await_ready().await?; + let response = self.http.try_send_request(options, response_handler); anyhow::Ok(response.await?) } - fn await_ready(&mut self) -> Result<()>{ + async fn await_ready(&mut self) -> Result<()>{ if self.is_ipfs_ready == true { return anyhow::Ok(());} let start_time = SystemTime::now(); loop { - match &mut self.ipfs_process.stdout { - Some(out) => { - let mut buffer:Vec = vec![]; - out.read_to_end(&mut buffer)?; - self.last_ipfs_output.append(&mut buffer); - drop(buffer); - - let text_so_far = match std::str::from_utf8(self.last_ipfs_output.as_slice()){ - Ok(text) => text, - Err(_) => "" - }; - if text_so_far.contains(READY_TEXT){ - self.is_ipfs_ready = true; - break; - }else if text_so_far.contains("\n") { - self.last_ipfs_output.clear(); - } - }, - None => () + println!("{}", "checking if ipfs is ready...".green()); + + if self.poll_ipfs_ready().await { + println!("{}", "IPFS is ready!!".green()); + self.is_ipfs_ready = true; + break; } sleep(Duration::new(SLEEP_LENGTH as u64, 0)); @@ -86,14 +82,43 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } + async fn poll_ipfs_ready(&mut self) -> bool{ + let args = HashMap::new(); + let cmd = CmdOptions::new("config/show", &args); + let response = self.http.send_request(&cmd).await; + return match response { + Ok(_) => true, + Err(e) => { + eprint!("{}", e); + false + } + }; + } async fn swarm_or_bootstrap_cmd(&mut self, cmd:&str, peer_id:&str) -> Result>{ let args = HashMap::from([ ("arg", peer_id) ]); let cmd_options = CmdOptions::new(cmd, &args); - let result_data = self.send_request(&cmd_options).await?; - let result_json:Value = serde_json::from_str(std::str::from_utf8(result_data.as_slice())?)?; - let peer_list:Vec = value_to_vec(&result_json, "peer")?; + let peer_list = self.send_request(&cmd_options, |result_data| { + let result_str =std::str::from_utf8(result_data.as_slice())?; + let result_json:Value = match serde_json::from_str(result_str){ + Ok(x) => x, + Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) + }; + let peer_list = match value_to_vec::(&result_json, "Strings"){ + Ok(peers) => { + for peer in peers.iter() { + if !peer.contains("success"){ + bail!("The following peer did not successfully connect: {}", peer) + } + } + anyhow::Ok(peers) + }, + Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) + }; + anyhow::Ok(peer_list?) + }).await?; + return anyhow::Ok(peer_list); } } @@ -112,8 +137,10 @@ impl Ipfs for IpfsViaDaemon { ("Content-Type", "application/octet-stream") ]); let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); - let result_data = self.send_request(&cmd_options).await?; - return anyhow::Ok(std::str::from_utf8(result_data.as_slice())?.to_string()); + let result = self.send_request(&cmd_options, |result_data| { + anyhow::Ok(std::str::from_utf8(result_data.as_slice())?.to_string()) + }).await?; + return anyhow::Ok(result); } async fn add_directory(&mut self, path:&str) -> Result { @@ -154,7 +181,7 @@ impl Ipfs for IpfsViaDaemon { post_options:None, args }; - self.send_request(&cmd_options).await?; + self.send_request(&cmd_options, |_| anyhow::Ok(())).await?; } anyhow::Ok(()) } @@ -162,7 +189,7 @@ impl Ipfs for IpfsViaDaemon { impl Drop for IpfsViaDaemon { fn drop(&mut self) { self.ipfs_process.kill().unwrap(); - println!("{}", ("Ipfs proccess closed. Feel free to close app whenever. ✅".bright_green())) + println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } } //TODO: This needs to be move to utils @@ -185,4 +212,20 @@ fn value_to_vec(json:&Value, index:&str) -> Result> }, None => bail!("Improperly formatted Json: Cant locate index {}", index) }) +} + +#[cfg(test)] +mod tests { + use futures::executor::block_on; + + use super::*; + + #[test] + fn can_connect(){ + println!("starting test"); + let peer_id = "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ"; + let mut ipfs = IpfsViaDaemon::new().unwrap(); + block_on(ipfs.connect_to(peer_id)).unwrap(); + assert!(true); + } } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index 6ed6b4a..efefa57 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -1,44 +1,71 @@ -use hyper::body::{HttpBody, Bytes}; -use hyper::{Uri, Client, Request, Method, Body}; -use hyper::client::connect::HttpConnector; -use anyhow::{Result}; -use super::options::{CmdOptions, IPFS_PORT, IPFS_ADDR}; +use bytes::Bytes; + +use colored::Colorize; +use anyhow::Result; +use tokio::runtime::Runtime; +use reqwest::{Client, Response}; +use super::options::{CmdOptions, IPFS_RETRY_ATTEMPTS}; pub struct HttpHandler{ - http_client:Client, + http_client:Client, + tokio:Runtime } impl HttpHandler { pub fn new() -> HttpHandler{ let client = Client::new(); + let runtime = tokio::runtime::Runtime::new().unwrap(); return HttpHandler{ - http_client:client + http_client:client, + tokio:runtime }; } - pub async fn send_request(&self, options:&CmdOptions) -> Result>{ - let mut arg_str:String = options.args.iter() - .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) - .collect(); - arg_str.pop(); - let request_url = format!("{}:{}/api/v0/{}?{}", IPFS_ADDR, IPFS_PORT, options.cmd, arg_str); - drop(arg_str); - - let mut response = match &options.post_options { - Some(post_options) => { - let mut request = Request::builder() - .method(Method::POST) - .uri(request_url); - for (key, value) in &post_options.headers { - request = request.header(key, value); - } - self.http_client.request(request.body(Body::from((&post_options.body).clone()))?).await? - }, - None => { - let request:Uri = request_url.parse()?; - self.http_client.get(request).await? - } + + pub async fn send_request(&mut self, options:&CmdOptions) -> Result>{ + let request_url = options.get_url(); + let body = match &options.post_options { + Some(post_options) => Bytes::copy_from_slice(post_options.body.as_slice()), + None => Bytes::new() }; - let response_body = response.body_mut(); - let response_bytes = response_body.data().await.unwrap_or( Ok(Bytes::new()))?.to_vec(); - anyhow::Ok(response_bytes) + println!("{}", (format!("sending get or post request to \"{}\"", request_url).green())); + let response = self.tokio.block_on(async { + self.http_client + .post(request_url) + .body(body) + .send().await + })?; + let response_bytes = response.bytes().await?; + println!("response recieved"); + anyhow::Ok(response_bytes.into()) } -} \ No newline at end of file + pub async fn try_send_request(&mut self, options:&CmdOptions, response_handler:F) -> Result + where F: Fn(Vec) -> Result{ + let mut attempt:u8 = 1; + 'attempt_loop: loop { + println!("attempting to send post request: attempt {} of {}", attempt, IPFS_RETRY_ATTEMPTS); + let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS; + let response_result = self.send_request(options).await; + let response = match is_final_attempt { + true => response_result?, + false => { match response_result { + Ok(x) => x, + Err(_) => { + attempt += 1; + continue 'attempt_loop + } + }} + }; + let handled_result = match is_final_attempt { + true => response_handler(response), + false => { match response_handler(response) { + Ok(x) => Ok(x), + Err(_) => { + attempt += 1; + continue 'attempt_loop + } + }} + }; + return Ok(handled_result?); + } + } + +} diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index 26a75bc..56df4b7 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -1,11 +1,12 @@ use std::collections::HashMap; -pub const IPFS_PORT:u16 = 4867; +pub const IPFS_API_PORT:u16 = 4867; +pub const IPFS_HTTP_PORT:u16 = 5742; +pub const IPFS_RETRY_ATTEMPTS:u8 = 3; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const BOOT_TIME_OUT:u16 = 120;//In seconds pub const SLEEP_LENGTH:u8 = 1;//In seconds -pub const READY_TEXT:&str = "Daemon is ready"; pub struct PostOptions { pub headers:HashMap, @@ -31,4 +32,15 @@ impl CmdOptions { self.post_options = Some(PostOptions { headers: owned_headers, body: owned_body }); return self; } + pub fn get_url(&self) -> String { + let mut arg_str:String = self.args.iter() + .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) + .collect(); + arg_str.pop(); + let url = format!("http://{}:{}/api/v0/{}", IPFS_ADDR, IPFS_API_PORT, self.cmd); + return match arg_str.len() == 0{ + true => url, + false => format!("{}?{}", url, arg_str) + } + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index a56fa27..ea9c7c6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,6 +27,7 @@ enum Commands { #[clap(about = "User application management")] User(User), } + fn main() { let cli = Cli::parse(); From caaa8690384be9abbdf8b42005c70f9c672ff752 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Fri, 18 Nov 2022 14:32:00 -0700 Subject: [PATCH 06/63] fibonacci http retry wait --- Cargo.lock | 136 +++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 6 +- src/ipfs/daemon.rs | 111 +++++++++++++++++++++++++----------- src/ipfs/http.rs | 31 +++++----- src/ipfs/options.rs | 2 +- 5 files changed, 233 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59e32b3..cb44aeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,6 +60,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + [[package]] name = "bare-metal" version = "0.2.5" @@ -87,6 +93,21 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bit_field" version = "0.10.1" @@ -172,6 +193,12 @@ version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +[[package]] +name = "bytemuck" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" + [[package]] name = "byteorder" version = "1.4.3" @@ -432,7 +459,7 @@ checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek", "ed25519", - "rand", + "rand 0.7.3", "serde", "sha2", "zeroize", @@ -516,13 +543,27 @@ dependencies = [ "clap", "colored", "did-key", + "fixed", "futures", + "proptest", "reqwest", "serde", "serde_json", "tokio", ] +[[package]] +name = "fixed" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418922d2c280b8c68f82699494cc8c48f392233233a9a8b9a48a57a36c0ad0ef" +dependencies = [ + "az", + "bytemuck", + "half", + "typenum", +] + [[package]] name = "fnv" version = "1.0.7" @@ -725,6 +766,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554" +dependencies = [ + "crunchy", +] + [[package]] name = "hash32" version = "0.2.1" @@ -955,7 +1005,7 @@ dependencies = [ "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", - "rand", + "rand 0.7.3", "serde", "sha2", "typenum", @@ -1066,6 +1116,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.14.0" @@ -1264,6 +1323,38 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" +dependencies = [ + "bit-set", + "bitflags", + "byteorder", + "lazy_static", + "num-traits", + "quick-error 2.0.1", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" version = "1.0.20" @@ -1292,6 +1383,17 @@ dependencies = [ "rand_hc", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -1339,6 +1441,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1450,6 +1561,18 @@ dependencies = [ "semver 1.0.14", ] +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.11" @@ -1933,6 +2056,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 4397dc0..440b905 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,4 +19,8 @@ reqwest = "0.11.12" bytes = "1.2.1" tokio = { version = "1", features = ["full"] } async-trait = "0.1.58" -futures = "0.3.25" \ No newline at end of file +futures = "0.3.25" +fixed = "1.20.0" + +[dev-dependencies] +proptest = "1.0.0" \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 0d9ed0e..3aa7428 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,5 +1,6 @@ use crate::ipfs::Ipfs; use anyhow::{Result, bail}; +use futures::executor::block_on; use super::options::*; use serde_json::Value; use std::collections::HashMap; @@ -13,7 +14,8 @@ use std::thread::sleep; pub struct IpfsViaDaemon { http:HttpHandler, ipfs_process:Child, - is_ipfs_ready:bool + is_ipfs_ready:bool, + connected_peers:Vec } impl IpfsViaDaemon { pub fn new() -> Result { @@ -27,7 +29,8 @@ impl IpfsViaDaemon { anyhow::Ok(IpfsViaDaemon{ ipfs_process: proccess, http: HttpHandler::new(), - is_ipfs_ready: false + is_ipfs_ready: false, + connected_peers: vec![] }) } fn configure() -> Result<()>{ @@ -55,10 +58,9 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } - async fn send_request(&mut self, options:&CmdOptions, response_handler:F) -> Result - where F: Fn(Vec) -> Result{ + async fn send_request(&mut self, options:&CmdOptions) -> Result>{ self.await_ready().await?; - let response = self.http.try_send_request(options, response_handler); + let response = self.http.try_send_request(options); anyhow::Ok(response.await?) } async fn await_ready(&mut self) -> Result<()>{ @@ -99,25 +101,23 @@ impl IpfsViaDaemon { ("arg", peer_id) ]); let cmd_options = CmdOptions::new(cmd, &args); - let peer_list = self.send_request(&cmd_options, |result_data| { - let result_str =std::str::from_utf8(result_data.as_slice())?; - let result_json:Value = match serde_json::from_str(result_str){ - Ok(x) => x, - Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) - }; - let peer_list = match value_to_vec::(&result_json, "Strings"){ - Ok(peers) => { - for peer in peers.iter() { - if !peer.contains("success"){ - bail!("The following peer did not successfully connect: {}", peer) - } + let result_data = self.send_request(&cmd_options).await?; + let result_str =std::str::from_utf8(result_data.as_slice())?; + let result_json:Value = match serde_json::from_str(result_str){ + Ok(x) => x, + Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) + }; + let peer_list = match value_to_vec::(&result_json, "Strings"){ + Ok(peers) => { + for peer in peers.iter() { + if !peer.contains("success"){ + bail!("The following peer did not successfully connect: {}", peer) } - anyhow::Ok(peers) - }, - Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) - }; - anyhow::Ok(peer_list?) - }).await?; + } + peers + }, + Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) + }; return anyhow::Ok(peer_list); } @@ -137,9 +137,8 @@ impl Ipfs for IpfsViaDaemon { ("Content-Type", "application/octet-stream") ]); let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); - let result = self.send_request(&cmd_options, |result_data| { - anyhow::Ok(std::str::from_utf8(result_data.as_slice())?.to_string()) - }).await?; + let result_data = self.send_request(&cmd_options).await?; + let result = std::str::from_utf8(result_data.as_slice())?.to_string(); return anyhow::Ok(result); } @@ -152,11 +151,20 @@ impl Ipfs for IpfsViaDaemon { } async fn connect_to(&mut self, peer_id:&str) -> Result> { - self.swarm_or_bootstrap_cmd("swarm/connect", peer_id).await + let response = self.swarm_or_bootstrap_cmd("swarm/connect", peer_id).await?; + self.connected_peers.push(peer_id.to_string()); + print!("Connected Peers: "); + self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); + anyhow::Ok(response) } async fn disconect_from(&mut self, peer_id:&str)-> Result> { - self.swarm_or_bootstrap_cmd("swarm/disconnect", peer_id).await + let response = self.swarm_or_bootstrap_cmd("swarm/disconnect", peer_id).await?; + self.connected_peers.iter_mut() + .filter(|peer_id_to_check| (peer_id_to_check.to_string() != peer_id.to_string())); + print!("Connected Peers: "); + self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); + anyhow::Ok(response) } async fn config(&mut self, options:HashMap) -> Result<()> { @@ -181,13 +189,16 @@ impl Ipfs for IpfsViaDaemon { post_options:None, args }; - self.send_request(&cmd_options, |_| anyhow::Ok(())).await?; + self.send_request(&cmd_options).await?; } anyhow::Ok(()) } } impl Drop for IpfsViaDaemon { fn drop(&mut self) { + for peer in self.connected_peers.clone(){ + block_on(self.disconect_from(&peer)); + } self.ipfs_process.kill().unwrap(); println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } @@ -217,15 +228,47 @@ fn value_to_vec(json:&Value, index:&str) -> Result> #[cfg(test)] mod tests { use futures::executor::block_on; - + use anyhow::Result; + use proptest::prelude::*; use super::*; + const PEER_ADDRS:&'static [&'static str] = &[ + "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", + "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", + "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4001/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", + "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/ip4/54.235.17.70/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/ip4/54.235.17.70/udp/4001/quic/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4001/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", + "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4001/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", + "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4001/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", + "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", + "/ip4/54.235.17.70/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", + ]; + + fn connect_to_peers() -> IpfsViaDaemon{ + let mut ipfs = IpfsViaDaemon::new().unwrap(); + for peer in PEER_ADDRS { + block_on(ipfs.connect_to(peer)).unwrap(); + } + ipfs + + } + #[test] fn can_connect(){ - println!("starting test"); - let peer_id = "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ"; - let mut ipfs = IpfsViaDaemon::new().unwrap(); - block_on(ipfs.connect_to(peer_id)).unwrap(); + connect_to_peers(); assert!(true); } + // proptest! { + // #[test] + // #[serial] + // fn can_add_file(s: &str){ + // let mut ipfs = connect_to_peers(); + // ipf.add_file() + // assert!(true); + // } + // } } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index efefa57..4b1c38d 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -1,9 +1,11 @@ +use std::time::Duration; + use bytes::Bytes; use colored::Colorize; use anyhow::Result; use tokio::runtime::Runtime; -use reqwest::{Client, Response}; +use reqwest::Client; use super::options::{CmdOptions, IPFS_RETRY_ATTEMPTS}; pub struct HttpHandler{ @@ -37,10 +39,12 @@ impl HttpHandler { println!("response recieved"); anyhow::Ok(response_bytes.into()) } - pub async fn try_send_request(&mut self, options:&CmdOptions, response_handler:F) -> Result - where F: Fn(Vec) -> Result{ - let mut attempt:u8 = 1; + pub async fn try_send_request(&mut self, options:&CmdOptions) -> Result>{ + let mut attempt:u16 = 1; 'attempt_loop: loop { + if attempt != 1 { + std::thread::sleep(Duration::new(get_fibinaci(attempt), 0)) + } println!("attempting to send post request: attempt {} of {}", attempt, IPFS_RETRY_ATTEMPTS); let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS; let response_result = self.send_request(options).await; @@ -54,18 +58,15 @@ impl HttpHandler { } }} }; - let handled_result = match is_final_attempt { - true => response_handler(response), - false => { match response_handler(response) { - Ok(x) => Ok(x), - Err(_) => { - attempt += 1; - continue 'attempt_loop - } - }} - }; - return Ok(handled_result?); + return anyhow::Ok(response); } } } + +fn get_fibinaci(n:u16) -> u64{ + let phi:f64 = fixed::consts::PHI.to_num(); + let numerator:f64 = phi.powi(n as i32)-((-phi).powi(n as i32)); + let denominator:f64 = f64::sqrt(5 as f64); + return (numerator/denominator).round() as u64; +} \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index 56df4b7..c70d208 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; pub const IPFS_API_PORT:u16 = 4867; pub const IPFS_HTTP_PORT:u16 = 5742; -pub const IPFS_RETRY_ATTEMPTS:u8 = 3; +pub const IPFS_RETRY_ATTEMPTS:u16 = 10; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const BOOT_TIME_OUT:u16 = 120;//In seconds From 32431163e43dc8e926c882f991deb910df9866a4 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Fri, 25 Nov 2022 10:40:44 -0600 Subject: [PATCH 07/63] try fail http fixed --- Cargo.lock | 21 ++++++++++ Cargo.toml | 1 + src/ipfs/daemon.rs | 28 +++++++++++--- src/ipfs/http.rs | 21 +++++++--- src/ipfs/options.rs | 2 +- test-dir/more/also-test.txt | 76 +++++++++++++++++++++++++++++++++++++ test-dir/text.txt | 1 + 7 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 test-dir/more/also-test.txt create mode 100644 test-dir/text.txt diff --git a/Cargo.lock b/Cargo.lock index cb44aeb..4bad6f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -550,6 +550,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "walkdir", ] [[package]] @@ -1579,6 +1580,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.20" @@ -2065,6 +2075,17 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 440b905..895e6a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ tokio = { version = "1", features = ["full"] } async-trait = "0.1.58" futures = "0.3.25" fixed = "1.20.0" +walkdir = "2.3.2" [dev-dependencies] proptest = "1.0.0" \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 3aa7428..1fb8ee8 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,6 +1,7 @@ use crate::ipfs::Ipfs; use anyhow::{Result, bail}; use futures::executor::block_on; +use reqwest::header; use super::options::*; use serde_json::Value; use std::collections::HashMap; @@ -10,6 +11,7 @@ use colored::Colorize; use crate::ipfs::http::HttpHandler; use std::time::{Duration, SystemTime}; use std::thread::sleep; +use walkdir::WalkDir; pub struct IpfsViaDaemon { http:HttpHandler, @@ -60,8 +62,12 @@ impl IpfsViaDaemon { } async fn send_request(&mut self, options:&CmdOptions) -> Result>{ self.await_ready().await?; - let response = self.http.try_send_request(options); - anyhow::Ok(response.await?) + let result = self.http.try_send_request(options, Some(|response_data:Vec| { + let response_str = std::str::from_utf8(response_data.as_slice())?; + //TODO: do a better job of checking here + anyhow::Ok(!(response_str.contains("\"Type\":\"error\""))) + })).await?; + anyhow::Ok(result)//it always return Some if a handler is given } async fn await_ready(&mut self) -> Result<()>{ if self.is_ipfs_ready == true { return anyhow::Ok(());} @@ -132,9 +138,8 @@ impl Ipfs for IpfsViaDaemon { ]); let disposition = format!("form-data; name=\"{}\"; filename=\"{}\"", name, file_name); let headers = HashMap::from([ - ("Abspath", path), - ("Content-Disposition", &disposition), - ("Content-Type", "application/octet-stream") + ("Content-Type", "application/octet-stream"), + ("Content-Disposition", &disposition) ]); let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); let result_data = self.send_request(&cmd_options).await?; @@ -143,7 +148,10 @@ impl Ipfs for IpfsViaDaemon { } async fn add_directory(&mut self, path:&str) -> Result { - todo!() + for entry in WalkDir::new(path) { + print!("{}", std::fs::read_to_string(entry?.path())?) + } + anyhow::Ok("Done".to_string()) } async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { @@ -232,6 +240,7 @@ mod tests { use proptest::prelude::*; use super::*; + //TODO: Setup pizza const PEER_ADDRS:&'static [&'static str] = &[ "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", @@ -271,4 +280,11 @@ mod tests { // assert!(true); // } // } + #[test] + fn can_add_directory(){ + let testdir = "./test-dir"; + let mut ipfs = connect_to_peers(); + block_on(ipfs.add_directory(testdir)).unwrap(); + assert!(true); + } } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index 4b1c38d..36adb1a 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -39,9 +39,11 @@ impl HttpHandler { println!("response recieved"); anyhow::Ok(response_bytes.into()) } - pub async fn try_send_request(&mut self, options:&CmdOptions) -> Result>{ - let mut attempt:u16 = 1; + pub async fn try_send_request(&mut self, options:&CmdOptions, handler_option:Option) -> Result> + where F: Fn(Vec) -> Result{ + let mut attempt:u16 = 0; 'attempt_loop: loop { + attempt += 1; if attempt != 1 { std::thread::sleep(Duration::new(get_fibinaci(attempt), 0)) } @@ -52,12 +54,19 @@ impl HttpHandler { true => response_result?, false => { match response_result { Ok(x) => x, - Err(_) => { - attempt += 1; - continue 'attempt_loop - } + Err(_) => continue 'attempt_loop }} }; + if is_final_attempt && handler_option.as_ref().is_some(){ + (handler_option.unwrap())(response.clone())?; + }else if handler_option.is_some(){ + let handler_result = (handler_option.as_ref().unwrap())(response.clone()); + if handler_result.is_err() { + continue 'attempt_loop; + }else if !(handler_result.unwrap()) { + continue 'attempt_loop; + } + } return anyhow::Ok(response); } } diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index c70d208..aa18abc 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; pub const IPFS_API_PORT:u16 = 4867; pub const IPFS_HTTP_PORT:u16 = 5742; -pub const IPFS_RETRY_ATTEMPTS:u16 = 10; +pub const IPFS_RETRY_ATTEMPTS:u16 = 7; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const BOOT_TIME_OUT:u16 = 120;//In seconds diff --git a/test-dir/more/also-test.txt b/test-dir/more/also-test.txt new file mode 100644 index 0000000..3ca99b2 --- /dev/null +++ b/test-dir/more/also-test.txt @@ -0,0 +1,76 @@ +We're no strangers to love +You know the rules and so do I +A full commitment's what I'm thinking of +You wouldn't get this from any other guy + +I just wanna tell you how I'm feeling +Gotta make you understand + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +We've known each other for so long +Your heart's been aching, but +You're too shy to say it +Inside, we both know what's been going on +We know the game and we're gonna play it + +And if you ask me how I'm feeling +Don't tell me you're too blind to see + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +(Ooh, give you up) +(Ooh, give you up) +Never gonna give, never gonna give +(Give you up) +Never gonna give, never gonna give +(Give you up) + +We've known each other for so long +Your heart's been aching, but +You're too shy to say it +Inside, we both know what's been going on +We know the game and we're gonna play it + +I just wanna tell you how I'm feeling +Gotta make you understand + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +He-he, you just got Rickrolled! \ No newline at end of file diff --git a/test-dir/text.txt b/test-dir/text.txt new file mode 100644 index 0000000..45d1d67 --- /dev/null +++ b/test-dir/text.txt @@ -0,0 +1 @@ +WEEEE! I am a test!! \ No newline at end of file From cc4f983020d142de036f20bf0c516cc16f062f1a Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 18:29:15 -0600 Subject: [PATCH 08/63] refactor and more --- Cargo.lock | 413 +------------------------------- Cargo.toml | 3 +- src/ipfs.rs | 2 +- src/ipfs/daemon.rs | 152 +++++++----- src/ipfs/http.rs | 137 ++++++++--- src/ipfs/options.rs | 42 +--- src/lib.rs | 1 + src/utils.rs | 3 + src/utils/file_management.rs | 69 ++++++ src/utils/json.rs | 30 +++ src/utils/math.rs | 6 + test-dir/more/fission_logo.png | Bin 0 -> 31609 bytes test-dir/{text.txt => test.txt} | 0 13 files changed, 322 insertions(+), 536 deletions(-) create mode 100644 src/utils.rs create mode 100644 src/utils/file_management.rs create mode 100644 src/utils/json.rs create mode 100644 src/utils/math.rs create mode 100644 test-dir/more/fission_logo.png rename test-dir/{text.txt => test.txt} (100%) diff --git a/Cargo.lock b/Cargo.lock index 4bad6f1..7085ab5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,12 +60,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "az" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" - [[package]] name = "bare-metal" version = "0.2.5" @@ -193,12 +187,6 @@ version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" -[[package]] -name = "bytemuck" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" - [[package]] name = "byteorder" version = "1.4.3" @@ -211,12 +199,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" -[[package]] -name = "cc" -version = "1.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" - [[package]] name = "cfg-if" version = "1.0.0" @@ -279,22 +261,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - [[package]] name = "cortex-m" version = "0.7.6" @@ -491,15 +457,6 @@ dependencies = [ "void", ] -[[package]] -name = "encoding_rs" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" -dependencies = [ - "cfg-if", -] - [[package]] name = "fastrand" version = "1.8.0" @@ -543,49 +500,21 @@ dependencies = [ "clap", "colored", "did-key", - "fixed", "futures", + "hyper", "proptest", - "reqwest", "serde", "serde_json", "tokio", "walkdir", ] -[[package]] -name = "fixed" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418922d2c280b8c68f82699494cc8c48f392233233a9a8b9a48a57a36c0ad0ef" -dependencies = [ - "az", - "bytemuck", - "half", - "typenum", -] - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.1.0" @@ -767,15 +696,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "half" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554" -dependencies = [ - "crunchy", -] - [[package]] name = "hash32" version = "0.2.1" @@ -918,29 +838,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" version = "1.9.1" @@ -960,12 +857,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "ipnet" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" - [[package]] name = "itoa" version = "1.0.4" @@ -1066,12 +957,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - [[package]] name = "mio" version = "0.8.5" @@ -1081,25 +966,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "windows-sys", ] [[package]] @@ -1148,51 +1015,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "openssl" -version = "0.10.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "os_str_bytes" version = "6.1.0" @@ -1248,7 +1070,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -1279,12 +1101,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - [[package]] name = "ppv-lite86" version = "0.2.16" @@ -1486,43 +1302,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "reqwest" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" -dependencies = [ - "base64 0.13.0", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - [[package]] name = "riscv" version = "0.7.0" @@ -1589,45 +1368,12 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" -dependencies = [ - "lazy_static", - "windows-sys 0.36.1", -] - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "security-framework" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "0.9.0" @@ -1689,18 +1435,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "sha2" version = "0.9.9" @@ -1871,21 +1605,6 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - [[package]] name = "tokio" version = "1.21.2" @@ -1917,16 +1636,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.4" @@ -1979,56 +1688,24 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - [[package]] name = "unicode-ident" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "vcell" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -2133,18 +1810,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.83" @@ -2174,16 +1839,6 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "winapi" version = "0.3.9" @@ -2215,19 +1870,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - [[package]] name = "windows-sys" version = "0.42.0" @@ -2235,12 +1877,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_x86_64_msvc", ] [[package]] @@ -2249,48 +1891,24 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - [[package]] name = "windows_aarch64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - [[package]] name = "windows_i686_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - [[package]] name = "windows_i686_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - [[package]] name = "windows_x86_64_gnu" version = "0.42.0" @@ -2303,27 +1921,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - [[package]] name = "windows_x86_64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - [[package]] name = "wyz" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 895e6a6..9875754 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,12 +15,11 @@ did-key = "0.1.1" colored = "2.0.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.87" -reqwest = "0.11.12" +hyper = { version = "0.14", features = ["full"] } bytes = "1.2.1" tokio = { version = "1", features = ["full"] } async-trait = "0.1.58" futures = "0.3.25" -fixed = "1.20.0" walkdir = "2.3.2" [dev-dependencies] diff --git a/src/ipfs.rs b/src/ipfs.rs index 109e67b..3c3d78e 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -11,7 +11,7 @@ pub mod options; #[async_trait] pub trait Ipfs { - async fn add_file(&mut self, name:&str, file_name:&str, path:&str, contents:Vec) -> Result; + async fn add_file(&mut self, path:&str) -> Result; async fn add_directory(&mut self, path:&str) -> Result; async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; async fn connect_to(&mut self, peer_id:&str) -> Result>; diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 1fb8ee8..fa9b5d3 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,7 +1,8 @@ use crate::ipfs::Ipfs; +use crate::utils::*; use anyhow::{Result, bail}; use futures::executor::block_on; -use reqwest::header; +use super::http::HttpRequest; use super::options::*; use serde_json::Value; use std::collections::HashMap; @@ -11,7 +12,6 @@ use colored::Colorize; use crate::ipfs::http::HttpHandler; use std::time::{Duration, SystemTime}; use std::thread::sleep; -use walkdir::WalkDir; pub struct IpfsViaDaemon { http:HttpHandler, @@ -60,7 +60,7 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } - async fn send_request(&mut self, options:&CmdOptions) -> Result>{ + async fn send_request(&mut self, options:&HttpRequest) -> Result>{ self.await_ready().await?; let result = self.http.try_send_request(options, Some(|response_data:Vec| { let response_str = std::str::from_utf8(response_data.as_slice())?; @@ -92,7 +92,8 @@ impl IpfsViaDaemon { } async fn poll_ipfs_ready(&mut self) -> bool{ let args = HashMap::new(); - let cmd = CmdOptions::new("config/show", &args); + let addr = HttpRequest::get_ipfs_addr() + "/config/show"; + let cmd = HttpRequest::new(&addr, &args); let response = self.http.send_request(&cmd).await; return match response { Ok(_) => true, @@ -106,14 +107,15 @@ impl IpfsViaDaemon { let args = HashMap::from([ ("arg", peer_id) ]); - let cmd_options = CmdOptions::new(cmd, &args); + let addr = HttpRequest::get_ipfs_addr()+cmd; + let cmd_options = HttpRequest::new(&addr, &args); let result_data = self.send_request(&cmd_options).await?; let result_str =std::str::from_utf8(result_data.as_slice())?; let result_json:Value = match serde_json::from_str(result_str){ Ok(x) => x, Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) }; - let peer_list = match value_to_vec::(&result_json, "Strings"){ + let peer_list = match json::value_to_vec::(&result_json, "Strings"){ Ok(peers) => { for peer in peers.iter() { if !peer.contains("success"){ @@ -130,46 +132,88 @@ impl IpfsViaDaemon { } #[async_trait] impl Ipfs for IpfsViaDaemon { - async fn add_file(&mut self, name:&str, file_name:&str, path:&str, contents:Vec) -> Result { - let cmd = "add"; + async fn add_file(&mut self, path:&str) -> Result { + let name = format!("\"{}\"", file_management::get_name_from_path(path, false)); + let cmd = HttpRequest::get_ipfs_addr()+ "/add"; let args = HashMap::from([ ("quieter", "true"), - ("cid-version", "1") + ("cid-version", "1"), + ("path", &path) ]); - let disposition = format!("form-data; name=\"{}\"; filename=\"{}\"", name, file_name); let headers = HashMap::from([ - ("Content-Type", "application/octet-stream"), - ("Content-Disposition", &disposition) + // ("Content-Disposition", "form-data"), + ("name", &name as &str), + ("filename", &path), + ("path", &path) ]); - let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); + let mut cmd_options = HttpRequest::new(&cmd, &args); + let contents = std::fs::read(path)?; + cmd_options.add_part(&headers, "application/octet-stream", contents.as_slice()); let result_data = self.send_request(&cmd_options).await?; let result = std::str::from_utf8(result_data.as_slice())?.to_string(); return anyhow::Ok(result); } async fn add_directory(&mut self, path:&str) -> Result { - for entry in WalkDir::new(path) { - print!("{}", std::fs::read_to_string(entry?.path())?) + let cmd = HttpRequest::get_ipfs_addr()+ "/add"; + let args = HashMap::from([ + ("quieter", "true"), + ("cid-version", "1") + ]); + let mut request = HttpRequest::new(&cmd, &args); + println!("{}", "Adding the following directories..".blue()); + + let dirs = file_management::get_dirs_in(path)?; + for dir in dirs{ + let name = format!("\"{}\"", file_management::get_name_from_path(path, true)); + let headers = HashMap::from([ + ("Content-Disposition", " form-data: name=\"files\""), + ("filename", &name) + ]); + request.add_part(&headers, "application/x-directory", &[]); + println!("{}", dir.blue()); } - anyhow::Ok("Done".to_string()) + + println!("{}", "Adding the following files..".blue()); + let files = file_management::get_files_in(path)?; + + for (file_path, data) in files { + let name = format!("\"{}\"", file_management::get_name_from_path(path, true)); + let headers = HashMap::from([ + ("Content-Disposition", " form-data: name=\"files\""), + ("filename", &file_path) + ]); + request.add_part(&headers, "application/octet-stream", data.as_slice()); + println!("{}", file_path.blue()); + + } + let response_data = self.send_request(&request).await?; + let response = std::str::from_utf8(response_data.as_slice())?.to_string(); + anyhow::Ok(response) } async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { - self.swarm_or_bootstrap_cmd("bootstrap/add", peer_id).await + self.swarm_or_bootstrap_cmd("/bootstrap/add", peer_id).await } async fn connect_to(&mut self, peer_id:&str) -> Result> { - let response = self.swarm_or_bootstrap_cmd("swarm/connect", peer_id).await?; + let response = self.swarm_or_bootstrap_cmd("/swarm/connect", peer_id).await?; self.connected_peers.push(peer_id.to_string()); - print!("Connected Peers: "); - self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); + // print!("Connected Peers: "); + // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); anyhow::Ok(response) } async fn disconect_from(&mut self, peer_id:&str)-> Result> { - let response = self.swarm_or_bootstrap_cmd("swarm/disconnect", peer_id).await?; - self.connected_peers.iter_mut() - .filter(|peer_id_to_check| (peer_id_to_check.to_string() != peer_id.to_string())); + let response = self.swarm_or_bootstrap_cmd("/swarm/disconnect", peer_id).await?; + self.connected_peers = self.connected_peers.iter() + .filter_map(|peer_id_to_check| { + let checkable = peer_id_to_check.to_string(); + match peer_id != checkable{ + true => Some(checkable), + false => None + } + }).collect(); print!("Connected Peers: "); self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); anyhow::Ok(response) @@ -187,16 +231,13 @@ impl Ipfs for IpfsViaDaemon { false => "false" }; let args = HashMap::from([ - ("arg".to_string(), setting.to_string()), - ("arg".to_string(), value.to_string()), - ("bool".to_string(), is_bool.to_string()), - ("json".to_string(), is_json.to_string()) + ("bool", is_bool), + ("json", is_json), + ("arg", &setting), + ("arg", &value) ]); - let cmd_options = CmdOptions{ - cmd:"config".to_string(), - post_options:None, - args - }; + let addr = HttpRequest::get_ipfs_addr()+"config"; + let cmd_options = HttpRequest::new(&addr, &args); self.send_request(&cmd_options).await?; } anyhow::Ok(()) @@ -205,33 +246,15 @@ impl Ipfs for IpfsViaDaemon { impl Drop for IpfsViaDaemon { fn drop(&mut self) { for peer in self.connected_peers.clone(){ - block_on(self.disconect_from(&peer)); + match block_on(self.disconect_from(&peer)){ + Ok(_) => (), + Err(e) => println!("{}\n{}", "Ipfs was unable to properly disconect from peers before closing".red(), e) + }; } self.ipfs_process.kill().unwrap(); println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } } -//TODO: This needs to be move to utils -fn value_to_vec(json:&Value, index:&str) -> Result> - where A:Clone + for<'de> serde::Deserialize<'de>{ - anyhow::Ok( match json.get(index) { - Some(list_json) => { - match list_json.as_array() { - Some(list) => { - list.iter().map(|item_json| { - let item:A = match serde_json::from_value(item_json.clone()){ - Ok(x) => x, - Err(_) => panic!("Improperly formatted Json: cannot format type") - }; - item - }).collect() - }, - None => panic!("Improperly formatted Json: Not an Array") - } - }, - None => bail!("Improperly formatted Json: Cant locate index {}", index) - }) -} #[cfg(test)] mod tests { @@ -266,11 +289,11 @@ mod tests { } - #[test] - fn can_connect(){ - connect_to_peers(); - assert!(true); - } + // #[test] + // fn can_connect(){ + // connect_to_peers(); + // assert!(true); + // } // proptest! { // #[test] // #[serial] @@ -284,7 +307,16 @@ mod tests { fn can_add_directory(){ let testdir = "./test-dir"; let mut ipfs = connect_to_peers(); - block_on(ipfs.add_directory(testdir)).unwrap(); + let res = block_on(ipfs.add_directory(testdir)).unwrap(); + println!("Server responded with:\n {}", res.green()); assert!(true); } + // #[test] + // fn can_add_file(){ + // let test_file = "./test-dir/more/fission_logo.png"; + // let mut ipfs = connect_to_peers(); + // let res = block_on(ipfs.add_file(test_file)).unwrap(); + // println!("Server responded with:\n {}", res.green()); + // assert!(true); + // } } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index 36adb1a..05422a6 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -1,15 +1,64 @@ -use std::time::Duration; +use std::{ + time::Duration, + collections::HashMap, + io::Write +}; use bytes::Bytes; - use colored::Colorize; use anyhow::Result; use tokio::runtime::Runtime; -use reqwest::Client; -use super::options::{CmdOptions, IPFS_RETRY_ATTEMPTS}; +use hyper::{ + Client, Body, Method, Request, + client::HttpConnector, + body::HttpBody +}; +use crate::utils::math; + +use super::options::*; + + +pub struct PostOptions { + pub headers:HashMap, + pub mime_type: String, + pub body: Vec +} +pub struct HttpRequest { + pub addr: String, + pub args: HashMap, + post_options: Vec +} +impl HttpRequest { + pub fn new(addr: &str, args: &HashMap<&str, &str>) -> Self{ + let owned_args:HashMap = args.iter() + .map(|(key, val)| (key.to_string(), val.to_string())) + .collect(); + Self { addr:addr.to_string(), args:owned_args, post_options: vec![] } + } + pub fn add_part(&mut self, headers: &HashMap<&str, &str>, mime_type:&str, body: &[u8]){ + let owned_body = body.to_vec(); + let owned_headers:HashMap = headers.iter() + .map(|(key, val)| (key.to_string(), val.to_string())) + .collect(); + self.post_options.push(PostOptions { headers: owned_headers, mime_type:mime_type.to_string(), body: owned_body }); + } + pub fn get_url(&self) -> String { + let mut arg_str:String = self.args.iter() + .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) + .collect(); + arg_str.pop(); + return match arg_str.len() == 0{ + true => self.addr.to_owned(), + false => format!("{}?{}", self.addr, arg_str) + } + } + pub fn get_ipfs_addr() -> String { + format!("http://{}:{}/api/v0", IPFS_ADDR, IPFS_API_PORT) + } +} pub struct HttpHandler{ - http_client:Client, + http_client:Client, tokio:Runtime } impl HttpHandler { @@ -22,33 +71,72 @@ impl HttpHandler { }; } - pub async fn send_request(&mut self, options:&CmdOptions) -> Result>{ + pub async fn send_request(&mut self, options:&HttpRequest) -> Result>{ let request_url = options.get_url(); - let body = match &options.post_options { - Some(post_options) => Bytes::copy_from_slice(post_options.body.as_slice()), - None => Bytes::new() + println!("{}", (format!("sending get or post request to \"{}\"", request_url).blue())); + let mut request_builder = Request::builder() + .method(Method::POST) + .uri(request_url); + let request = match options.post_options.len() { + 0 | 1 => { + for post in options.post_options.iter(){ + for (header_key, header_val) in post.headers.iter(){ + request_builder = request_builder.header(header_key, header_val) + } + } + match options.post_options.get(0) { + Some(options) => { + let data = options.body.clone(); + request_builder + .header("Content-Type", options.mime_type.to_string()) + .body(Body::from(data))? + }, + None => request_builder.body(Body::from(Bytes::new()))? + } + } + _ => { + let mut body_parts = vec![]; + for post_options in &options.post_options { + write!(body_parts, "--{}\r\n", HTTP_BOUNDARY)?; + for (header_prop, header_val) in &post_options.headers { + write!(body_parts, "{}:{}; ", header_prop, header_val)?; + } + let data_text = unsafe { + //TODO: find a way to do this safely + std::str::from_utf8_unchecked(post_options.body.as_slice()) + }; + write!(body_parts, "\r\nContent-Type: {}\r\n", post_options.mime_type)?; + write!(body_parts, "\r\n{}", data_text)?; + } + write!(body_parts, "--{}--\r\n", HTTP_BOUNDARY)?; + request_builder + .header("Content-Type", &*format!("multipart/form-data; boundary={}", HTTP_BOUNDARY)) + .body(Body::from(body_parts))? + } }; - println!("{}", (format!("sending get or post request to \"{}\"", request_url).green())); - let response = self.tokio.block_on(async { - self.http_client - .post(request_url) - .body(body) - .send().await + let mut response = self.tokio.block_on(async { + self.http_client.request(request).await })?; - let response_bytes = response.bytes().await?; + let mut response_data: Vec = vec![]; + while let Some(chunk) = response.body_mut().data().await { + for byte in chunk? { + response_data.push(byte); + } + } println!("response recieved"); - anyhow::Ok(response_bytes.into()) + anyhow::Ok(response_data) + } - pub async fn try_send_request(&mut self, options:&CmdOptions, handler_option:Option) -> Result> + pub async fn try_send_request(&mut self, options:&HttpRequest, handler_option:Option) -> Result> where F: Fn(Vec) -> Result{ - let mut attempt:u16 = 0; + let mut attempt:u32 = 0; 'attempt_loop: loop { attempt += 1; if attempt != 1 { - std::thread::sleep(Duration::new(get_fibinaci(attempt), 0)) + std::thread::sleep(Duration::new(math::get_fibinaci(attempt), 0)) } println!("attempting to send post request: attempt {} of {}", attempt, IPFS_RETRY_ATTEMPTS); - let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS; + let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS as u32; let response_result = self.send_request(options).await; let response = match is_final_attempt { true => response_result?, @@ -72,10 +160,3 @@ impl HttpHandler { } } - -fn get_fibinaci(n:u16) -> u64{ - let phi:f64 = fixed::consts::PHI.to_num(); - let numerator:f64 = phi.powi(n as i32)-((-phi).powi(n as i32)); - let denominator:f64 = f64::sqrt(5 as f64); - return (numerator/denominator).round() as u64; -} \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index aa18abc..e902041 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -1,46 +1,8 @@ -use std::collections::HashMap; - pub const IPFS_API_PORT:u16 = 4867; pub const IPFS_HTTP_PORT:u16 = 5742; pub const IPFS_RETRY_ATTEMPTS:u16 = 7; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; +pub const HTTP_BOUNDARY:&str = "------------------------I_am_a_boundary_123A123"; pub const BOOT_TIME_OUT:u16 = 120;//In seconds -pub const SLEEP_LENGTH:u8 = 1;//In seconds - -pub struct PostOptions { - pub headers:HashMap, - pub body: Vec -} -pub struct CmdOptions { - pub cmd: String, - pub args: HashMap, - pub post_options: Option -} -impl CmdOptions { - pub fn new(cmd: &str, args: &HashMap<&str, &str>) -> Self{ - let owned_args:HashMap = args.iter() - .map(|(key, val)| (key.to_string(), val.to_string())) - .collect(); - Self { cmd:cmd.to_string(), args:owned_args, post_options: None } - } - pub fn to_post(mut self, headers: &HashMap<&str, &str>, body: &[u8]) -> Self{ - let owned_body = body.to_vec(); - let owned_headers:HashMap = headers.iter() - .map(|(key, val)| (key.to_string(), val.to_string())) - .collect(); - self.post_options = Some(PostOptions { headers: owned_headers, body: owned_body }); - return self; - } - pub fn get_url(&self) -> String { - let mut arg_str:String = self.args.iter() - .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) - .collect(); - arg_str.pop(); - let url = format!("http://{}:{}/api/v0/{}", IPFS_ADDR, IPFS_API_PORT, self.cmd); - return match arg_str.len() == 0{ - true => url, - false => format!("{}?{}", url, arg_str) - } - } -} \ No newline at end of file +pub const SLEEP_LENGTH:u8 = 1;//In seconds \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 97e4791..85bf540 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,3 @@ pub mod cmd; pub mod ipfs; +pub mod utils; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..44937d4 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,3 @@ +pub mod file_management; +pub mod json; +pub mod math; \ No newline at end of file diff --git a/src/utils/file_management.rs b/src/utils/file_management.rs new file mode 100644 index 0000000..dc39637 --- /dev/null +++ b/src/utils/file_management.rs @@ -0,0 +1,69 @@ + +use walkdir::WalkDir; +use std::collections::HashMap; +use anyhow::{Result, bail}; +use colored::Colorize; + +//TODO: This needs to move to utils +pub fn get_files_in(dir:&str) -> Result>> { + let mut files = HashMap::new(); + for entry_result in WalkDir::new(dir) { + let entry = match entry_result { + Ok(x) => x, + Err(e) => bail!("{}\n{}", "failled to get item in directory, failed with error:".red(), e) + }; + if entry.path().is_file() { + let file_data = match std::fs::read(entry.path()) { + Ok(x) => x, + Err(e) => bail!("{}\n{}", "failed to read file in directory into a byte vector, failed with error:".red(), e) + }; + let path = match entry.path().to_str() { + Some(x) => x, + None => bail!("failed to get path as string a file") + }.to_string(); + files.insert(path, file_data); + } + } + return anyhow::Ok(files); +} +//TODO: This needs to move to utils +pub fn get_dirs_in(root:&str) -> Result> { + let mut dirs = vec![]; + for entry_result in WalkDir::new(root) { + let entry = match entry_result { + Ok(x) => x, + Err(e) => bail!("{}\n{}", "failled to get item in directory, failed with error:".red(), e) + }; + if entry.path().is_dir() { + let path = match entry.path().to_str() { + Some(x) => x, + None => bail!("failed to get path as string a file") + }.to_string(); + dirs.push(path); + } + } + return anyhow::Ok(dirs); +} +//TODO: This needs to move to utils +pub fn get_name_from_path(path:&str, include_extention:bool) -> String{ + let file_name = path + .split("/") + .filter(|seg|!seg.is_empty()) + .last() + .unwrap(); + if !include_extention{ + let dot_parts = file_name.split(".").map(|s|s.to_string()); + return match dot_parts.clone().count() { + 1 => dot_parts.collect::>()[0].to_owned(), //this handles the case in-which there is no file extention + _ => { + //This collects all but the last segment into a single string + dot_parts.fold([String::new(), String::new()], |accum, current| { + [format!("{}.{}", accum[0], accum[1]), current.to_string()] + })[0].to_owned() + } + } + + }else { + return file_name.to_string(); + } +} \ No newline at end of file diff --git a/src/utils/json.rs b/src/utils/json.rs new file mode 100644 index 0000000..c2f94f8 --- /dev/null +++ b/src/utils/json.rs @@ -0,0 +1,30 @@ +/* +Ipfs often returns json with a single property with the value being an array. +This function simply takes the array in that property and turns it into a vector that can be used in rust. +It will return an error result if the json is not formatted in this way. +*/ + +use serde_json::Value; +use anyhow::{Result, bail}; + +pub fn value_to_vec(json:&Value, index:&str) -> Result> + where A:Clone + for<'de> serde::Deserialize<'de>{ + anyhow::Ok( match json.get(index) { + Some(list_json) => { + match list_json.as_array() { + Some(list) => { + let mut result_list:Vec = vec![]; + for item_json in list { + result_list.push(match serde_json::from_value(item_json.clone()){ + Ok(x) => x, + Err(_) => bail!("Improperly formatted Json: cannot format value {} in index {} to specified type", item_json, index) + }); + } + result_list + }, + None => bail!("Improperly formatted Json: Value at index {} is not an Array", index) + } + }, + None => bail!("Improperly formatted Json: Cant locate index {}", index) + }) +} \ No newline at end of file diff --git a/src/utils/math.rs b/src/utils/math.rs new file mode 100644 index 0000000..2f3f8e0 --- /dev/null +++ b/src/utils/math.rs @@ -0,0 +1,6 @@ +pub fn get_fibinaci(n:u32) -> u64{ + if n <= 1 { + return n as u64; + } + return get_fibinaci(n - 1) + get_fibinaci(n - 2); +} \ No newline at end of file diff --git a/test-dir/more/fission_logo.png b/test-dir/more/fission_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7261ccb8a524c9b9c38fe5789d92609cc57454a7 GIT binary patch literal 31609 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 Mv--8%)GhA+0XalX00000 literal 0 HcmV?d00001 diff --git a/test-dir/text.txt b/test-dir/test.txt similarity index 100% rename from test-dir/text.txt rename to test-dir/test.txt From faede3215deac5552b45de15e1cf660f0f00b330 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 19:47:49 -0600 Subject: [PATCH 09/63] files upload to ipfs finnally --- src/ipfs/daemon.rs | 69 +++++++++++++++++++++++------------- src/ipfs/http.rs | 48 +++++++++++++------------ src/utils/file_management.rs | 25 +------------ 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index fa9b5d3..6d6c18d 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -93,7 +93,7 @@ impl IpfsViaDaemon { async fn poll_ipfs_ready(&mut self) -> bool{ let args = HashMap::new(); let addr = HttpRequest::get_ipfs_addr() + "/config/show"; - let cmd = HttpRequest::new(&addr, &args); + let cmd = HttpRequest::new(&addr, &args, false); let response = self.http.send_request(&cmd).await; return match response { Ok(_) => true, @@ -103,12 +103,13 @@ impl IpfsViaDaemon { } }; } + //TODO: Better name? async fn swarm_or_bootstrap_cmd(&mut self, cmd:&str, peer_id:&str) -> Result>{ let args = HashMap::from([ ("arg", peer_id) ]); let addr = HttpRequest::get_ipfs_addr()+cmd; - let cmd_options = HttpRequest::new(&addr, &args); + let cmd_options = HttpRequest::new(&addr, &args, false); let result_data = self.send_request(&cmd_options).await?; let result_str =std::str::from_utf8(result_data.as_slice())?; let result_json:Value = match serde_json::from_str(result_str){ @@ -133,22 +134,20 @@ impl IpfsViaDaemon { #[async_trait] impl Ipfs for IpfsViaDaemon { async fn add_file(&mut self, path:&str) -> Result { - let name = format!("\"{}\"", file_management::get_name_from_path(path, false)); let cmd = HttpRequest::get_ipfs_addr()+ "/add"; let args = HashMap::from([ ("quieter", "true"), ("cid-version", "1"), ("path", &path) ]); + let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &path); let headers = HashMap::from([ - // ("Content-Disposition", "form-data"), - ("name", &name as &str), - ("filename", &path), - ("path", &path) + ("Content-Disposition", &disposition as &str), + ("Content-Type", "application/octet-stream") ]); - let mut cmd_options = HttpRequest::new(&cmd, &args); + let mut cmd_options = HttpRequest::new(&cmd, &args, true); let contents = std::fs::read(path)?; - cmd_options.add_part(&headers, "application/octet-stream", contents.as_slice()); + cmd_options.add_body(&headers, contents.as_slice()); let result_data = self.send_request(&cmd_options).await?; let result = std::str::from_utf8(result_data.as_slice())?.to_string(); return anyhow::Ok(result); @@ -160,17 +159,17 @@ impl Ipfs for IpfsViaDaemon { ("quieter", "true"), ("cid-version", "1") ]); - let mut request = HttpRequest::new(&cmd, &args); + let mut request = HttpRequest::new(&cmd, &args, true); println!("{}", "Adding the following directories..".blue()); let dirs = file_management::get_dirs_in(path)?; for dir in dirs{ - let name = format!("\"{}\"", file_management::get_name_from_path(path, true)); + let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &dir); let headers = HashMap::from([ - ("Content-Disposition", " form-data: name=\"files\""), - ("filename", &name) + ("Content-Disposition", &disposition as &str), + ("Content-Type", "application/x-directory") ]); - request.add_part(&headers, "application/x-directory", &[]); + request.add_body(&headers, &[]); println!("{}", dir.blue()); } @@ -178,12 +177,12 @@ impl Ipfs for IpfsViaDaemon { let files = file_management::get_files_in(path)?; for (file_path, data) in files { - let name = format!("\"{}\"", file_management::get_name_from_path(path, true)); + let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &file_path); let headers = HashMap::from([ - ("Content-Disposition", " form-data: name=\"files\""), - ("filename", &file_path) + ("Content-Disposition", &disposition as &str), + ("Content-Type", "application/octet-stream") ]); - request.add_part(&headers, "application/octet-stream", data.as_slice()); + request.add_body(&headers, data.as_slice()); println!("{}", file_path.blue()); } @@ -237,7 +236,7 @@ impl Ipfs for IpfsViaDaemon { ("arg", &value) ]); let addr = HttpRequest::get_ipfs_addr()+"config"; - let cmd_options = HttpRequest::new(&addr, &args); + let cmd_options = HttpRequest::new(&addr, &args, false); self.send_request(&cmd_options).await?; } anyhow::Ok(()) @@ -259,8 +258,9 @@ impl Drop for IpfsViaDaemon { #[cfg(test)] mod tests { use futures::executor::block_on; - use anyhow::Result; - use proptest::prelude::*; + use crate::utils::file_management; + // use anyhow::Result; + // use proptest::prelude::*; use super::*; //TODO: Setup pizza @@ -305,11 +305,32 @@ mod tests { // } #[test] fn can_add_directory(){ - let testdir = "./test-dir"; + let test_dir = "./test-dir"; let mut ipfs = connect_to_peers(); - let res = block_on(ipfs.add_directory(testdir)).unwrap(); + let res = block_on(ipfs.add_directory(test_dir)).unwrap(); println!("Server responded with:\n {}", res.green()); - assert!(true); + + let files = file_management::get_files_in(test_dir).unwrap(); + let folders = file_management::get_dirs_in(test_dir).unwrap(); + + files.iter() + .map(|(path, _)| path) + .chain(folders.iter()) + .for_each(|path| { + //This removes the "./" at the begginning of paths as the ipfs server responds without them + let fixed_path:String = path + .split("/") + .enumerate() + .filter_map(|(i, seg)| { + match i { + 0 => None, + 1 => Some(seg.to_string()), + _ => Some("/".to_string() + seg) + } + }).collect(); + println!("checking if response contains path {}", fixed_path); + assert!(res.contains(&fixed_path)); + }); } // #[test] // fn can_add_file(){ diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index 05422a6..bf42a43 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -20,27 +20,28 @@ use super::options::*; pub struct PostOptions { pub headers:HashMap, - pub mime_type: String, pub body: Vec } pub struct HttpRequest { pub addr: String, pub args: HashMap, - post_options: Vec + pub is_multipart:bool, + post_options: Vec//TODO: Better name? } impl HttpRequest { - pub fn new(addr: &str, args: &HashMap<&str, &str>) -> Self{ + pub fn new(addr: &str, args: &HashMap<&str, &str>, is_multipart:bool) -> Self{ let owned_args:HashMap = args.iter() .map(|(key, val)| (key.to_string(), val.to_string())) .collect(); - Self { addr:addr.to_string(), args:owned_args, post_options: vec![] } + Self { addr:addr.to_string(), args:owned_args, post_options: vec![], is_multipart } } - pub fn add_part(&mut self, headers: &HashMap<&str, &str>, mime_type:&str, body: &[u8]){ + //TODO: Better name? + pub fn add_body(&mut self, headers: &HashMap<&str, &str>, body: &[u8]){ let owned_body = body.to_vec(); let owned_headers:HashMap = headers.iter() .map(|(key, val)| (key.to_string(), val.to_string())) .collect(); - self.post_options.push(PostOptions { headers: owned_headers, mime_type:mime_type.to_string(), body: owned_body }); + self.post_options.push(PostOptions { headers: owned_headers, body: owned_body }); } pub fn get_url(&self) -> String { let mut arg_str:String = self.args.iter() @@ -77,41 +78,42 @@ impl HttpHandler { let mut request_builder = Request::builder() .method(Method::POST) .uri(request_url); - let request = match options.post_options.len() { - 0 | 1 => { - for post in options.post_options.iter(){ - for (header_key, header_val) in post.headers.iter(){ - request_builder = request_builder.header(header_key, header_val) - } - } + let request = match options.is_multipart { + false => { match options.post_options.get(0) { Some(options) => { + for (header_key, header_val) in options.headers.iter(){ + request_builder = request_builder.header(header_key, header_val) + } + let data = options.body.clone(); - request_builder - .header("Content-Type", options.mime_type.to_string()) - .body(Body::from(data))? + request_builder.body(Body::from(data))? }, None => request_builder.body(Body::from(Bytes::new()))? } } - _ => { + true => { let mut body_parts = vec![]; for post_options in &options.post_options { write!(body_parts, "--{}\r\n", HTTP_BOUNDARY)?; for (header_prop, header_val) in &post_options.headers { - write!(body_parts, "{}:{}; ", header_prop, header_val)?; + write!(body_parts, "{}: {}\r\n", header_prop, header_val)?; } let data_text = unsafe { //TODO: find a way to do this safely std::str::from_utf8_unchecked(post_options.body.as_slice()) }; - write!(body_parts, "\r\nContent-Type: {}\r\n", post_options.mime_type)?; - write!(body_parts, "\r\n{}", data_text)?; + write!(body_parts, "\r\n{}\r\n", data_text)?; } write!(body_parts, "--{}--\r\n", HTTP_BOUNDARY)?; - request_builder - .header("Content-Type", &*format!("multipart/form-data; boundary={}", HTTP_BOUNDARY)) - .body(Body::from(body_parts))? + match options.post_options.len() { + 0 => request_builder.body(Body::from(Bytes::new()))?, + _ => { + request_builder + .header("Content-Type", &*format!("multipart/form-data; boundary=\"{}\"", HTTP_BOUNDARY)) + .body(Body::from(body_parts))? + } + } } }; let mut response = self.tokio.block_on(async { diff --git a/src/utils/file_management.rs b/src/utils/file_management.rs index dc39637..d8aad66 100644 --- a/src/utils/file_management.rs +++ b/src/utils/file_management.rs @@ -26,7 +26,7 @@ pub fn get_files_in(dir:&str) -> Result>> { } return anyhow::Ok(files); } -//TODO: This needs to move to utils + pub fn get_dirs_in(root:&str) -> Result> { let mut dirs = vec![]; for entry_result in WalkDir::new(root) { @@ -43,27 +43,4 @@ pub fn get_dirs_in(root:&str) -> Result> { } } return anyhow::Ok(dirs); -} -//TODO: This needs to move to utils -pub fn get_name_from_path(path:&str, include_extention:bool) -> String{ - let file_name = path - .split("/") - .filter(|seg|!seg.is_empty()) - .last() - .unwrap(); - if !include_extention{ - let dot_parts = file_name.split(".").map(|s|s.to_string()); - return match dot_parts.clone().count() { - 1 => dot_parts.collect::>()[0].to_owned(), //this handles the case in-which there is no file extention - _ => { - //This collects all but the last segment into a single string - dot_parts.fold([String::new(), String::new()], |accum, current| { - [format!("{}.{}", accum[0], accum[1]), current.to_string()] - })[0].to_owned() - } - } - - }else { - return file_name.to_string(); - } } \ No newline at end of file From 7c4d77941dc8d65f3702882dd261758c48da42a0 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 20:15:42 -0600 Subject: [PATCH 10/63] removing auto disconnect for now --- src/ipfs/daemon.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 6d6c18d..19ad6bc 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -120,7 +120,7 @@ impl IpfsViaDaemon { Ok(peers) => { for peer in peers.iter() { if !peer.contains("success"){ - bail!("The following peer did not successfully connect: {}", peer) + bail!("The following peer did not successfully connect or disconnect: {}", peer) } } peers @@ -244,12 +244,12 @@ impl Ipfs for IpfsViaDaemon { } impl Drop for IpfsViaDaemon { fn drop(&mut self) { - for peer in self.connected_peers.clone(){ - match block_on(self.disconect_from(&peer)){ - Ok(_) => (), - Err(e) => println!("{}\n{}", "Ipfs was unable to properly disconect from peers before closing".red(), e) - }; - } + // for peer in self.connected_peers.clone(){ + // match block_on(self.disconect_from(&peer)){ + // Ok(_) => (), + // Err(e) => println!("{}\n{}", "Ipfs was unable to properly disconect from peers before closing".red(), e) + // }; + // } self.ipfs_process.kill().unwrap(); println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } @@ -283,10 +283,12 @@ mod tests { fn connect_to_peers() -> IpfsViaDaemon{ let mut ipfs = IpfsViaDaemon::new().unwrap(); for peer in PEER_ADDRS { - block_on(ipfs.connect_to(peer)).unwrap(); + let result_peers = block_on(ipfs.connect_to(peer)).unwrap() ; + for result_peer in result_peers { + println!("Connected to peer! {}", result_peer); + } } - ipfs - + return ipfs; } // #[test] From c4442dee7b7d22ba7ce2f83f95e31a1f20b800f9 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 20:16:28 -0600 Subject: [PATCH 11/63] oops --- src/ipfs/daemon.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 19ad6bc..3d11323 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,7 +1,6 @@ use crate::ipfs::Ipfs; use crate::utils::*; use anyhow::{Result, bail}; -use futures::executor::block_on; use super::http::HttpRequest; use super::options::*; use serde_json::Value; From a8114fe5eba31109c9bc23dc087147face9387ea Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 20:45:49 -0600 Subject: [PATCH 12/63] testing add file --- Cargo.lock | 48 +++++++++++++-- Cargo.toml | 3 +- src/ipfs/daemon.rs | 57 +++++------------- src/ipfs/options.rs | 5 +- test-dir/{more => more-tests}/also-test.txt | 0 test-dir/more-tests/even more/noper.nope | 1 + .../{more => more-tests}/fission_logo.png | Bin 7 files changed, 64 insertions(+), 50 deletions(-) rename test-dir/{more => more-tests}/also-test.txt (100%) create mode 100644 test-dir/more-tests/even more/noper.nope rename test-dir/{more => more-tests}/fission_logo.png (100%) diff --git a/Cargo.lock b/Cargo.lock index 7085ab5..ad497c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -345,6 +345,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "der" version = "0.4.5" @@ -505,6 +518,7 @@ dependencies = [ "proptest", "serde", "serde_json", + "serial_test", "tokio", "walkdir", ] @@ -707,9 +721,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heapless" @@ -1005,9 +1019,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "opaque-debug" @@ -1435,6 +1449,32 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92761393ee4dc3ff8f4af487bd58f4307c9329bbedea02cac0089ad9c411e153" +dependencies = [ + "dashmap", + "futures", + "lazy_static", + "log", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6f5d1c3087fb119617cff2966fe3808a80e5eb59a8c1601d5994d66f4346a5" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha2" version = "0.9.9" diff --git a/Cargo.toml b/Cargo.toml index 9875754..10a88d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,4 +23,5 @@ futures = "0.3.25" walkdir = "2.3.2" [dev-dependencies] -proptest = "1.0.0" \ No newline at end of file +proptest = "1.0.0" +serial_test = "0.9.0" \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 3d11323..a988f83 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -20,10 +20,11 @@ pub struct IpfsViaDaemon { } impl IpfsViaDaemon { pub fn new() -> Result { - println!("{}", "Configuring ipfs...".green()); - IpfsViaDaemon::configure()?; println!("{}", "Starting ipfs...".green()); + let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); let proccess = Command::new(IPFS_EXE) + .arg("--api") + .arg(&api_addr) .arg("daemon") .spawn()?; println!("{}", ("⚠️ Warning: Ipfs Proccess Started. Please do NOT force close this app⚠️".yellow())); @@ -34,31 +35,6 @@ impl IpfsViaDaemon { connected_peers: vec![] }) } - fn configure() -> Result<()>{ - //This sets the API's address - //let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); - let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); - let http_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_HTTP_PORT); - //let http_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_HTTP_PORT); - IpfsViaDaemon::config_option("Addresses.API", &api_addr)?; - IpfsViaDaemon::config_option("Addresses.Gateway", &http_addr)?; - anyhow::Ok(()) - } - fn config_option(option:&str, value:&str)-> Result<()>{ - let cmd_str = format!("ipfs {} Addresses.API {}", option, value); - println!("running cmd \"{}\"", cmd_str.blue()); - let is_addr_set = Command::new(IPFS_EXE) - .arg("config") - .arg(option) - .arg(value) - .spawn()? - .wait()? - .success(); - if !is_addr_set { - bail!("Attempted to set the api address, but failed!"); - } - anyhow::Ok(()) - } async fn send_request(&mut self, options:&HttpRequest) -> Result>{ self.await_ready().await?; let result = self.http.try_send_request(options, Some(|response_data:Vec| { @@ -243,12 +219,6 @@ impl Ipfs for IpfsViaDaemon { } impl Drop for IpfsViaDaemon { fn drop(&mut self) { - // for peer in self.connected_peers.clone(){ - // match block_on(self.disconect_from(&peer)){ - // Ok(_) => (), - // Err(e) => println!("{}\n{}", "Ipfs was unable to properly disconect from peers before closing".red(), e) - // }; - // } self.ipfs_process.kill().unwrap(); println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } @@ -261,6 +231,7 @@ mod tests { // use anyhow::Result; // use proptest::prelude::*; use super::*; + use serial_test::serial; //TODO: Setup pizza const PEER_ADDRS:&'static [&'static str] = &[ @@ -305,8 +276,9 @@ mod tests { // } // } #[test] + #[serial] fn can_add_directory(){ - let test_dir = "./test-dir"; + let test_dir = "./test-dir/more-tests"; let mut ipfs = connect_to_peers(); let res = block_on(ipfs.add_directory(test_dir)).unwrap(); println!("Server responded with:\n {}", res.green()); @@ -333,12 +305,13 @@ mod tests { assert!(res.contains(&fixed_path)); }); } - // #[test] - // fn can_add_file(){ - // let test_file = "./test-dir/more/fission_logo.png"; - // let mut ipfs = connect_to_peers(); - // let res = block_on(ipfs.add_file(test_file)).unwrap(); - // println!("Server responded with:\n {}", res.green()); - // assert!(true); - // } + #[test] + #[serial] + fn can_add_file(){ + let test_file = "./test-dir/test.txt"; + let mut ipfs = connect_to_peers(); + let res = block_on(ipfs.add_file(test_file)).unwrap(); + println!("Server responded with:\n {}", res.green()); + assert!(true); + } } \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index e902041..c7b8943 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -1,8 +1,7 @@ -pub const IPFS_API_PORT:u16 = 4867; -pub const IPFS_HTTP_PORT:u16 = 5742; +pub const IPFS_API_PORT:u16 = 4869; pub const IPFS_RETRY_ATTEMPTS:u16 = 7; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const HTTP_BOUNDARY:&str = "------------------------I_am_a_boundary_123A123"; -pub const BOOT_TIME_OUT:u16 = 120;//In seconds +pub const BOOT_TIME_OUT:u16 = 45;//In seconds pub const SLEEP_LENGTH:u8 = 1;//In seconds \ No newline at end of file diff --git a/test-dir/more/also-test.txt b/test-dir/more-tests/also-test.txt similarity index 100% rename from test-dir/more/also-test.txt rename to test-dir/more-tests/also-test.txt diff --git a/test-dir/more-tests/even more/noper.nope b/test-dir/more-tests/even more/noper.nope new file mode 100644 index 0000000..06e94c7 --- /dev/null +++ b/test-dir/more-tests/even more/noper.nope @@ -0,0 +1 @@ +Nope Nope \ No newline at end of file diff --git a/test-dir/more/fission_logo.png b/test-dir/more-tests/fission_logo.png similarity index 100% rename from test-dir/more/fission_logo.png rename to test-dir/more-tests/fission_logo.png From 66c040e2d1418d9720a63e10fd4e200d39880d95 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 29 Nov 2022 13:21:20 -0600 Subject: [PATCH 13/63] finnishing add file --- src/ipfs.rs | 4 +-- src/ipfs/daemon.rs | 85 +++++++++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index 3c3d78e..773d742 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -11,8 +11,8 @@ pub mod options; #[async_trait] pub trait Ipfs { - async fn add_file(&mut self, path:&str) -> Result; - async fn add_directory(&mut self, path:&str) -> Result; + async fn add_file(&mut self, path:&str) -> Result>; + async fn add_directory(&mut self, path:&str) -> Result>; async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; async fn connect_to(&mut self, peer_id:&str) -> Result>; async fn disconect_from(&mut self, peer_id:&str)-> Result>; diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index a988f83..9340323 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -105,10 +105,38 @@ impl IpfsViaDaemon { return anyhow::Ok(peer_list); } + fn response_to_hashes(response:&str) -> Result> { + let mut res = response.to_string(); + let mut ret = HashMap::new(); + return loop { + //get location to take segment to + let json_seg_end = match res.find("}") { + Some(seg_loc) => seg_loc, + None => break anyhow::Ok(ret) + }; + //get segment to convert to json and remove the segment from res + let res_vec = res.chars().collect::>(); + let json_seg = res_vec[..(json_seg_end+1)].iter().collect::(); + res = res_vec[(json_seg_end+1)..].iter().collect(); + //convert that segment to json and value + // println!("{}", res.yellow()); + // println!("{}", json_seg.blue()); + let json:Value = serde_json::from_str(&json_seg)?; + let path = match json.get("Name"){ + Some(val) => val.to_string(), + None => bail!("Could not find Name property in ipfs's response to an add") + }; + let hash = match json.get("Hash"){ + Some(val) => val.to_string(), + None => bail!("Could not find Hash property in ipfs's response to an add") + }; + ret.insert(path, hash); + }; + } } #[async_trait] impl Ipfs for IpfsViaDaemon { - async fn add_file(&mut self, path:&str) -> Result { + async fn add_file(&mut self, path:&str) -> Result> { let cmd = HttpRequest::get_ipfs_addr()+ "/add"; let args = HashMap::from([ ("quieter", "true"), @@ -124,11 +152,12 @@ impl Ipfs for IpfsViaDaemon { let contents = std::fs::read(path)?; cmd_options.add_body(&headers, contents.as_slice()); let result_data = self.send_request(&cmd_options).await?; - let result = std::str::from_utf8(result_data.as_slice())?.to_string(); - return anyhow::Ok(result); + let response = std::str::from_utf8(result_data.as_slice())?.to_string(); + let hashes = Self::response_to_hashes(&response)?; + anyhow::Ok(hashes) } - async fn add_directory(&mut self, path:&str) -> Result { + async fn add_directory(&mut self, path:&str) -> Result> { let cmd = HttpRequest::get_ipfs_addr()+ "/add"; let args = HashMap::from([ ("quieter", "true"), @@ -159,11 +188,11 @@ impl Ipfs for IpfsViaDaemon { ]); request.add_body(&headers, data.as_slice()); println!("{}", file_path.blue()); - } let response_data = self.send_request(&request).await?; let response = std::str::from_utf8(response_data.as_slice())?.to_string(); - anyhow::Ok(response) + let hashes = Self::response_to_hashes(&response)?; + anyhow::Ok(hashes) } async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { @@ -175,7 +204,7 @@ impl Ipfs for IpfsViaDaemon { self.connected_peers.push(peer_id.to_string()); // print!("Connected Peers: "); // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); - anyhow::Ok(response) + anyhow::Ok(self.connected_peers.clone()) } async fn disconect_from(&mut self, peer_id:&str)-> Result> { @@ -190,7 +219,7 @@ impl Ipfs for IpfsViaDaemon { }).collect(); print!("Connected Peers: "); self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); - anyhow::Ok(response) + anyhow::Ok(self.connected_peers.clone()) } async fn config(&mut self, options:HashMap) -> Result<()> { @@ -226,6 +255,8 @@ impl Drop for IpfsViaDaemon { #[cfg(test)] mod tests { + use std::hash; + use futures::executor::block_on; use crate::utils::file_management; // use anyhow::Result; @@ -280,8 +311,11 @@ mod tests { fn can_add_directory(){ let test_dir = "./test-dir/more-tests"; let mut ipfs = connect_to_peers(); - let res = block_on(ipfs.add_directory(test_dir)).unwrap(); - println!("Server responded with:\n {}", res.green()); + let hashes = block_on(ipfs.add_directory(test_dir)).unwrap(); + println!("{}","Finnished Hashes:".green()); + for (path, hash) in &hashes { + println!("{}: {}", path.green(), hash.blue()) + } let files = file_management::get_files_in(test_dir).unwrap(); let folders = file_management::get_dirs_in(test_dir).unwrap(); @@ -289,29 +323,26 @@ mod tests { files.iter() .map(|(path, _)| path) .chain(folders.iter()) - .for_each(|path| { - //This removes the "./" at the begginning of paths as the ipfs server responds without them - let fixed_path:String = path - .split("/") - .enumerate() - .filter_map(|(i, seg)| { - match i { - 0 => None, - 1 => Some(seg.to_string()), - _ => Some("/".to_string() + seg) - } - }).collect(); - println!("checking if response contains path {}", fixed_path); - assert!(res.contains(&fixed_path)); + .for_each(|path_to_match| { + assert!(hashes.iter().any(|(path, _)|path_to_match ==path)) }); + + } #[test] #[serial] fn can_add_file(){ let test_file = "./test-dir/test.txt"; let mut ipfs = connect_to_peers(); - let res = block_on(ipfs.add_file(test_file)).unwrap(); - println!("Server responded with:\n {}", res.green()); - assert!(true); + let hashes = block_on(ipfs.add_file(test_file)).unwrap(); + println!("{}","Finnished Hashes:\n".green()); + for (path, hash) in &hashes { + println!("{}: {}", path.green(), hash.blue()) + } + assert!(hashes.iter().any(|(path, _)|test_file ==path)); + } + #[test] + fn can_config(){ + } } \ No newline at end of file From 03bf7a4bf85a45fbe10d54d5694fbd34b1c0d05b Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 29 Nov 2022 16:57:48 -0600 Subject: [PATCH 14/63] quick fix for file adding --- src/ipfs/daemon.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 9340323..d870115 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -119,15 +119,13 @@ impl IpfsViaDaemon { let json_seg = res_vec[..(json_seg_end+1)].iter().collect::(); res = res_vec[(json_seg_end+1)..].iter().collect(); //convert that segment to json and value - // println!("{}", res.yellow()); - // println!("{}", json_seg.blue()); let json:Value = serde_json::from_str(&json_seg)?; let path = match json.get("Name"){ - Some(val) => val.to_string(), + Some(val) => "/".to_string() + &val.to_string().split("\"").collect::(), None => bail!("Could not find Name property in ipfs's response to an add") }; let hash = match json.get("Hash"){ - Some(val) => val.to_string(), + Some(val) => "/".to_string() + &val.to_string().split("\"").collect::(), None => bail!("Could not find Hash property in ipfs's response to an add") }; ret.insert(path, hash); @@ -200,7 +198,7 @@ impl Ipfs for IpfsViaDaemon { } async fn connect_to(&mut self, peer_id:&str) -> Result> { - let response = self.swarm_or_bootstrap_cmd("/swarm/connect", peer_id).await?; + self.swarm_or_bootstrap_cmd("/swarm/connect", peer_id).await?; self.connected_peers.push(peer_id.to_string()); // print!("Connected Peers: "); // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); @@ -208,7 +206,7 @@ impl Ipfs for IpfsViaDaemon { } async fn disconect_from(&mut self, peer_id:&str)-> Result> { - let response = self.swarm_or_bootstrap_cmd("/swarm/disconnect", peer_id).await?; + self.swarm_or_bootstrap_cmd("/swarm/disconnect", peer_id).await?; self.connected_peers = self.connected_peers.iter() .filter_map(|peer_id_to_check| { let checkable = peer_id_to_check.to_string(); @@ -324,7 +322,12 @@ mod tests { .map(|(path, _)| path) .chain(folders.iter()) .for_each(|path_to_match| { - assert!(hashes.iter().any(|(path, _)|path_to_match ==path)) + let fixed_path_to_match:String = path_to_match + .split("/") + .filter(|seg| seg != &"." && !seg.is_empty()) + .map(|seg| "/".to_string() + seg) + .collect(); + assert!(hashes.iter().any(|(path, _)|fixed_path_to_match == path.to_owned())) }); @@ -339,7 +342,13 @@ mod tests { for (path, hash) in &hashes { println!("{}: {}", path.green(), hash.blue()) } - assert!(hashes.iter().any(|(path, _)|test_file ==path)); + let matchable_path:String = test_file + .split("/") + .filter(|seg| seg != &"." && !seg.is_empty()) + .map(|seg| "/".to_string() + seg) + .collect(); + println!("{}", matchable_path.red()); + assert!(hashes.iter().any(|(path, _)|matchable_path == path.to_owned())); } #[test] fn can_config(){ From 72911e0be26288b9963da8f8d1ca759767b0b674 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 29 Nov 2022 17:03:04 -0600 Subject: [PATCH 15/63] remove warnings --- src/ipfs/daemon.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index d870115..a762251 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -125,7 +125,7 @@ impl IpfsViaDaemon { None => bail!("Could not find Name property in ipfs's response to an add") }; let hash = match json.get("Hash"){ - Some(val) => "/".to_string() + &val.to_string().split("\"").collect::(), + Some(val) => val.to_string().split("\"").collect::(), None => bail!("Could not find Hash property in ipfs's response to an add") }; ret.insert(path, hash); @@ -253,8 +253,6 @@ impl Drop for IpfsViaDaemon { #[cfg(test)] mod tests { - use std::hash; - use futures::executor::block_on; use crate::utils::file_management; // use anyhow::Result; From 31c0dee0f8db7eae7759ee550d40ad3fa179fc1a Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 30 Nov 2022 21:18:20 -0600 Subject: [PATCH 16/63] fixing config --- src/ipfs.rs | 2 +- src/ipfs/daemon.rs | 88 +++++++++++++++++++++++++++------------------ src/ipfs/options.rs | 2 +- src/utils/json.rs | 36 ++++++++++++++++--- 4 files changed, 86 insertions(+), 42 deletions(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index 773d742..e8f2bc8 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -16,5 +16,5 @@ pub trait Ipfs { async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; async fn connect_to(&mut self, peer_id:&str) -> Result>; async fn disconect_from(&mut self, peer_id:&str)-> Result>; - async fn config(&mut self, options:HashMap) -> Result<()>; + async fn config(&mut self, options:&HashMap<&str, &str>) -> Result<()>; } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index a762251..684d64b 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -220,28 +220,50 @@ impl Ipfs for IpfsViaDaemon { anyhow::Ok(self.connected_peers.clone()) } - async fn config(&mut self, options:HashMap) -> Result<()> { + async fn config(&mut self, options:&HashMap<&str, &str>) -> Result<()> { + let get_profile = HttpRequest::new(&(HttpRequest::get_ipfs_addr()+"/config/show"), &(HashMap::new()), false); + let profile_vec = self.send_request(&get_profile).await?; + let profile_str = std::str::from_utf8(profile_vec.as_slice())?; + let mut profile:Value = serde_json::from_str(profile_str)?; for (setting, value) in options { - let cleaned_value = value.to_lowercase(); - let is_bool = match cleaned_value.trim() == "true" || cleaned_value.trim() == "false" { - true => "true", - false => "false" - }; - let is_json = match serde_json::from_str::(&value).is_ok() { - true => "true", - false => "false" + let number_value = value.to_string().parse::(); + let bool_value = value.to_string().parse::(); + let json_value = serde_json::from_str::(value); + let value_parsed = match number_value { + Ok(v) => Value::Number(serde_json::Number::from_f64(v).unwrap()), + Err(_) => { + match bool_value { + Ok(v) => Value::Bool(v), + Err(_) => { + match json_value { + Ok(v) => v, + Err(_) => Value::String(value.to_string()) + } + } + } + } }; - let args = HashMap::from([ - ("bool", is_bool), - ("json", is_json), - ("arg", &setting), - ("arg", &value) - ]); - let addr = HttpRequest::get_ipfs_addr()+"config"; - let cmd_options = HttpRequest::new(&addr, &args, false); - self.send_request(&cmd_options).await?; + let location = setting.split(".").map(|s| s.to_string()); + profile = json::change_json_part(&profile, location, &value_parsed)?; + } + let json_str = profile.to_string(); + + let args = HashMap::new(); + let headers = HashMap::from([ + ("Content-Disposition"," form-data; name=\"files\"; filename=\"config\""), + ("Content-Type", "application/octet-stream") + ]); + + let addr = HttpRequest::get_ipfs_addr()+"/config/replace"; + let mut request = HttpRequest::new(&addr, &args, true); + request.add_body(&headers, json_str.as_bytes()); + let response = self.send_request(&request).await?; + let res_str = std::str::from_utf8(response.as_slice())?; + if res_str.trim().is_empty(){ + return anyhow::Ok(()) + }else{ + bail!("There was error changing the settings in ipfs. The failure was: {}", res_str.red()); } - anyhow::Ok(()) } } impl Drop for IpfsViaDaemon { @@ -255,6 +277,7 @@ impl Drop for IpfsViaDaemon { mod tests { use futures::executor::block_on; use crate::utils::file_management; + use std::collections::HashMap; // use anyhow::Result; // use proptest::prelude::*; use super::*; @@ -288,20 +311,6 @@ mod tests { return ipfs; } - // #[test] - // fn can_connect(){ - // connect_to_peers(); - // assert!(true); - // } - // proptest! { - // #[test] - // #[serial] - // fn can_add_file(s: &str){ - // let mut ipfs = connect_to_peers(); - // ipf.add_file() - // assert!(true); - // } - // } #[test] #[serial] fn can_add_directory(){ @@ -345,11 +354,20 @@ mod tests { .filter(|seg| seg != &"." && !seg.is_empty()) .map(|seg| "/".to_string() + seg) .collect(); - println!("{}", matchable_path.red()); assert!(hashes.iter().any(|(path, _)|matchable_path == path.to_owned())); } #[test] + #[serial] fn can_config(){ - + let mut ipfs = IpfsViaDaemon::new().unwrap(); + block_on(ipfs.config(&HashMap::from([ + ("Datastore.StorageMax", "11GB"), + ("Datastore.GCPeriod", "2h") + ]))).unwrap(); + block_on(ipfs.config(&HashMap::from([ + ("Datastore.StorageMax", "10GB"), + ("Datastore.GCPeriod", "1h") + ]))).unwrap(); + assert!(true) } } \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index c7b8943..3fe7629 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -1,5 +1,5 @@ pub const IPFS_API_PORT:u16 = 4869; -pub const IPFS_RETRY_ATTEMPTS:u16 = 7; +pub const IPFS_RETRY_ATTEMPTS:u16 = 4; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const HTTP_BOUNDARY:&str = "------------------------I_am_a_boundary_123A123"; diff --git a/src/utils/json.rs b/src/utils/json.rs index c2f94f8..967bfb6 100644 --- a/src/utils/json.rs +++ b/src/utils/json.rs @@ -1,12 +1,11 @@ +use serde_json::{Map, Value}; +use anyhow::{Result, bail}; + /* Ipfs often returns json with a single property with the value being an array. This function simply takes the array in that property and turns it into a vector that can be used in rust. It will return an error result if the json is not formatted in this way. */ - -use serde_json::Value; -use anyhow::{Result, bail}; - pub fn value_to_vec(json:&Value, index:&str) -> Result> where A:Clone + for<'de> serde::Deserialize<'de>{ anyhow::Ok( match json.get(index) { @@ -27,4 +26,31 @@ pub fn value_to_vec(json:&Value, index:&str) -> Result> }, None => bail!("Improperly formatted Json: Cant locate index {}", index) }) -} \ No newline at end of file +} + +pub fn change_json_part(root:&Value, loc:I, to:&Value) -> Result + where I: Iterator + Clone{ + if loc.clone().count() == 0 { + // println!("{}", "found it!".red()); + return Ok(to.clone()); + }else if !root.is_object(){ + return Ok(root.clone()); + }else{ + let root_iter = match root.as_object() { + Some(o) => o.iter(), + None => return Ok(Value::Object(serde_json::Map::new())) + }; + let mut new_root:Map = Map::new(); + for (prop, val) in root_iter { + let mut new_loc = loc.clone(); + let prop_to_match = new_loc.next().unwrap().to_string() ; + // println!("{} <=> {} = {}", prop, prop_to_match, prop.to_owned() == prop_to_match); + let new_val = match prop.to_owned() == prop_to_match{ + true => change_json_part(val, new_loc, to)?, + false => change_json_part(val, loc.clone(), to)? + }; + new_root.insert(prop.to_owned(), new_val); + } + return Ok(Value::Object(new_root)); + } +} From 3750b4f929df7cb5c334bea97d43f9104fdfa371 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 26 Oct 2022 12:56:08 -0500 Subject: [PATCH 17/63] Moving stuff from other branch I am creating this new branch and moving my changes over, so I don't have to deal commit merging issues --- Cargo.lock | 2 + Cargo.toml | 4 +- src/ipfs.rs | 40 +++++++++++++++++++ src/ipfs/daemon.rs | 97 ++++++++++++++++++++++++++++++++++++++++++++++ src/ipfs/error.rs | 4 ++ src/ipfs/result.rs | 22 +++++++++++ src/lib.rs | 1 + 7 files changed, 169 insertions(+), 1 deletion(-) create mode 100644 src/ipfs.rs create mode 100644 src/ipfs/daemon.rs create mode 100644 src/ipfs/error.rs create mode 100644 src/ipfs/result.rs diff --git a/Cargo.lock b/Cargo.lock index 53b9655..73625c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -457,6 +457,8 @@ dependencies = [ "clap", "colored", "did-key", + "serde", + "serde_json", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8d05ff0..e72a364 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,4 +12,6 @@ bs58 = "0.4.0" base64 = "0.13.0" clap = { version = "3.2.12", features = ["derive"] } did-key = "0.1.1" -colored = "2.0.0" \ No newline at end of file +colored = "2.0.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0.87" \ No newline at end of file diff --git a/src/ipfs.rs b/src/ipfs.rs new file mode 100644 index 0000000..b8fc085 --- /dev/null +++ b/src/ipfs.rs @@ -0,0 +1,40 @@ +use std::collections::HashMap; + +use serde_json::Value; + +use self::{error::IpfsError, result::*}; + +pub mod daemon; +pub mod error; +pub mod result; + +pub trait Ipfs { + fn add(name:&str, path:&str, is_directory:bool) -> Result; + fn bitswap_ledger(peer_id:&str) -> Result; + fn bitswap_reprovide() -> Result; + //Note bitswap_stat is left out because it for diagonostic purposes + fn bitswap_wantlist(peer: &str) -> Result, IpfsError>; + fn get_block(block_cid: &str) -> Result; + //TODO: multihash_alg should be enum + fn put_block(data: &str, multihash_alg: &str, multihash_length: &str, is_pin:bool, allow_big_block:bool, cid_codec:Option) + -> Result; + fn remove_block(block_cid:&str, force:bool) -> Result; + fn block_stats(block_cid:&str) -> Result; + fn get_bootstrap_peers() -> Result, IpfsError>; + fn add_bootstrap_peer(peer:&str) -> Result, IpfsError>; + fn add_bootstrap_defaults() -> Result, IpfsError>; + fn remove_bootstrap_peer(peer:&str) -> Result, IpfsError>; + fn remove_all_bootstrap_peer(peer:&str) -> Result, IpfsError>; + fn get_object_data(path:&str, start:Option, length:Option) + -> Result; + fn cid_to_base32(cid: &str) -> Result; + //format, bases, hashes, commands, and codes endpoints were not included as I think they are mainly for debug + fn edit_config(key:&str, value:Option<&str>, is_bool:bool, is_object:bool) -> Result; + fn apply_profile_config(profile:&str) -> Result; + fn replace_config(path:&str) -> Result; + fn get_config() -> Result; + fn export_dag(cid: &str) -> Result; + //TODO: format should be enum + fn get_dag(cid: &str, codec: &str) -> Result; + fn import_dag(path:&str, pin_roots:bool, allow_big_block:bool) -> Result<(), IpfsError>; +} \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs new file mode 100644 index 0000000..6ebaee4 --- /dev/null +++ b/src/ipfs/daemon.rs @@ -0,0 +1,97 @@ +use crate::ipfs::Ipfs; +use super::{error::IpfsError, result::*}; +use std::collections::HashMap; +pub struct IpfsViaDaemon { + +} +impl Ipfs for IpfsViaDaemon { + fn add(name:&str, path:&str, is_directory:bool) -> Result { + todo!() + } + + fn bitswap_ledger(peer_id:&str) -> Result { + todo!() + } + + fn bitswap_reprovide() -> Result { + todo!() + } + + fn bitswap_wantlist(peer: &str) -> Result, IpfsError> { + todo!() + } + + fn get_block(block_cid: &str) -> Result { + todo!() + } + + fn put_block(data: &str, multihash_alg: &str, multihash_length: &str, is_pin:bool, allow_big_block:bool, cid_codec:Option) + -> Result { + todo!() + } + + fn remove_block(block_cid:&str, force:bool) -> Result { + todo!() + } + + fn block_stats(block_cid:&str) -> Result { + todo!() + } + + fn get_bootstrap_peers() -> Result, IpfsError> { + todo!() + } + + fn add_bootstrap_peer(peer:&str) -> Result, IpfsError> { + todo!() + } + + fn add_bootstrap_defaults() -> Result, IpfsError> { + todo!() + } + + fn remove_bootstrap_peer(peer:&str) -> Result, IpfsError> { + todo!() + } + + fn remove_all_bootstrap_peer(peer:&str) -> Result, IpfsError> { + todo!() + } + + fn get_object_data(path:&str, start:Option, length:Option) + -> Result { + todo!() + } + + fn cid_to_base32(cid: &str) -> Result { + todo!() + } + + fn edit_config(key:&str, value:Option<&str>, is_bool:bool, is_object:bool) -> Result { + todo!() + } + + fn apply_profile_config(profile:&str) -> Result { + todo!() + } + + fn replace_config(path:&str) -> Result { + todo!() + } + + fn get_config() -> Result { + todo!() + } + + fn export_dag(cid: &str) -> Result { + todo!() + } + + fn get_dag(cid: &str, codec: &str) -> Result { + todo!() + } + + fn import_dag(path:&str, pin_roots:bool, allow_big_block:bool) -> Result<(), IpfsError> { + todo!() + } +} \ No newline at end of file diff --git a/src/ipfs/error.rs b/src/ipfs/error.rs new file mode 100644 index 0000000..1954ea9 --- /dev/null +++ b/src/ipfs/error.rs @@ -0,0 +1,4 @@ + +pub struct IpfsError{ + +} \ No newline at end of file diff --git a/src/ipfs/result.rs b/src/ipfs/result.rs new file mode 100644 index 0000000..2102c67 --- /dev/null +++ b/src/ipfs/result.rs @@ -0,0 +1,22 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct AddedData{ + bytes:i64, + hash:String, + name:String, + size:String +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct Ledger{ + exchanged: i64, + peer: String, + recv: i64, + sent: i64, + value: i64 +} +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct IpfsBlock{ + key: String, + size: i32 +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index dac0599..2b62138 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod cmd; pub mod legacy; pub mod utils; +pub mod ipfs; From 5c665bebaf02efbacd4e37b5b9ac5cc33d75048f Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Fri, 28 Oct 2022 18:52:06 -0500 Subject: [PATCH 18/63] IPFS Trait Complete --- src/ipfs.rs | 51 ++++++++++------------------ src/ipfs/daemon.rs | 84 +++++++--------------------------------------- src/ipfs/error.rs | 4 --- src/ipfs/result.rs | 22 ------------ 4 files changed, 30 insertions(+), 131 deletions(-) delete mode 100644 src/ipfs/error.rs delete mode 100644 src/ipfs/result.rs diff --git a/src/ipfs.rs b/src/ipfs.rs index b8fc085..bf8702f 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -1,40 +1,25 @@ -use std::collections::HashMap; +//use std::collections::{HashMap, btree_map::OccupiedError}; -use serde_json::Value; +use std::collections::HashMap; -use self::{error::IpfsError, result::*}; +use anyhow::Result; +use serde::{Deserialize, Serialize}; pub mod daemon; -pub mod error; -pub mod result; pub trait Ipfs { - fn add(name:&str, path:&str, is_directory:bool) -> Result; - fn bitswap_ledger(peer_id:&str) -> Result; - fn bitswap_reprovide() -> Result; - //Note bitswap_stat is left out because it for diagonostic purposes - fn bitswap_wantlist(peer: &str) -> Result, IpfsError>; - fn get_block(block_cid: &str) -> Result; - //TODO: multihash_alg should be enum - fn put_block(data: &str, multihash_alg: &str, multihash_length: &str, is_pin:bool, allow_big_block:bool, cid_codec:Option) - -> Result; - fn remove_block(block_cid:&str, force:bool) -> Result; - fn block_stats(block_cid:&str) -> Result; - fn get_bootstrap_peers() -> Result, IpfsError>; - fn add_bootstrap_peer(peer:&str) -> Result, IpfsError>; - fn add_bootstrap_defaults() -> Result, IpfsError>; - fn remove_bootstrap_peer(peer:&str) -> Result, IpfsError>; - fn remove_all_bootstrap_peer(peer:&str) -> Result, IpfsError>; - fn get_object_data(path:&str, start:Option, length:Option) - -> Result; - fn cid_to_base32(cid: &str) -> Result; - //format, bases, hashes, commands, and codes endpoints were not included as I think they are mainly for debug - fn edit_config(key:&str, value:Option<&str>, is_bool:bool, is_object:bool) -> Result; - fn apply_profile_config(profile:&str) -> Result; - fn replace_config(path:&str) -> Result; - fn get_config() -> Result; - fn export_dag(cid: &str) -> Result; - //TODO: format should be enum - fn get_dag(cid: &str, codec: &str) -> Result; - fn import_dag(path:&str, pin_roots:bool, allow_big_block:bool) -> Result<(), IpfsError>; + fn add_file(path:&str) -> Result; + fn add_directory(path:&str) -> Result; + fn add_bootstrap(peer_id:&str) -> Result>; + fn connect_to(peer_id:&str) -> Result>; + fn disconect_from(peer_id:&str)-> Result>; + fn config(options:HashMap) -> Result>; +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CidData{ + bytes:i64, + hash:String, + name:String, + size:String } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 6ebaee4..168a5b6 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,97 +1,37 @@ use crate::ipfs::Ipfs; -use super::{error::IpfsError, result::*}; +use super::CidData; +use anyhow::Result; use std::collections::HashMap; pub struct IpfsViaDaemon { } -impl Ipfs for IpfsViaDaemon { - fn add(name:&str, path:&str, is_directory:bool) -> Result { - todo!() - } - - fn bitswap_ledger(peer_id:&str) -> Result { - todo!() - } - - fn bitswap_reprovide() -> Result { - todo!() - } - - fn bitswap_wantlist(peer: &str) -> Result, IpfsError> { - todo!() - } - - fn get_block(block_cid: &str) -> Result { - todo!() - } - - fn put_block(data: &str, multihash_alg: &str, multihash_length: &str, is_pin:bool, allow_big_block:bool, cid_codec:Option) - -> Result { - todo!() - } - - fn remove_block(block_cid:&str, force:bool) -> Result { - todo!() - } - - fn block_stats(block_cid:&str) -> Result { - todo!() - } - - fn get_bootstrap_peers() -> Result, IpfsError> { +impl IpfsViaDaemon { + pub fn new() -> Result { todo!() } - - fn add_bootstrap_peer(peer:&str) -> Result, IpfsError> { - todo!() - } - - fn add_bootstrap_defaults() -> Result, IpfsError> { - todo!() - } - - fn remove_bootstrap_peer(peer:&str) -> Result, IpfsError> { - todo!() - } - - fn remove_all_bootstrap_peer(peer:&str) -> Result, IpfsError> { - todo!() - } - - fn get_object_data(path:&str, start:Option, length:Option) - -> Result { - todo!() - } - - fn cid_to_base32(cid: &str) -> Result { - todo!() - } - - fn edit_config(key:&str, value:Option<&str>, is_bool:bool, is_object:bool) -> Result { - todo!() - } - - fn apply_profile_config(profile:&str) -> Result { +} +impl Ipfs for IpfsViaDaemon { + fn add_file(path:&str) -> Result { todo!() } - fn replace_config(path:&str) -> Result { + fn add_directory(path:&str) -> Result { todo!() } - fn get_config() -> Result { + fn add_bootstrap(peer_id:&str) -> Result> { todo!() } - fn export_dag(cid: &str) -> Result { + fn connect_to(peer_id:&str) -> Result> { todo!() } - fn get_dag(cid: &str, codec: &str) -> Result { + fn disconect_from(peer_id:&str)-> Result> { todo!() } - fn import_dag(path:&str, pin_roots:bool, allow_big_block:bool) -> Result<(), IpfsError> { + fn config(options:HashMap) -> Result> { todo!() } } \ No newline at end of file diff --git a/src/ipfs/error.rs b/src/ipfs/error.rs deleted file mode 100644 index 1954ea9..0000000 --- a/src/ipfs/error.rs +++ /dev/null @@ -1,4 +0,0 @@ - -pub struct IpfsError{ - -} \ No newline at end of file diff --git a/src/ipfs/result.rs b/src/ipfs/result.rs deleted file mode 100644 index 2102c67..0000000 --- a/src/ipfs/result.rs +++ /dev/null @@ -1,22 +0,0 @@ -use serde::{Deserialize, Serialize}; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct AddedData{ - bytes:i64, - hash:String, - name:String, - size:String -} -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Ledger{ - exchanged: i64, - peer: String, - recv: i64, - sent: i64, - value: i64 -} -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct IpfsBlock{ - key: String, - size: i32 -} \ No newline at end of file From 617cf35c6c801acebf6b05f82eeee37ebaa9e2d0 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 8 Nov 2022 13:42:48 -0700 Subject: [PATCH 19/63] adding what I got so I can review brian's pr --- Cargo.lock | 313 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 4 +- src/ipfs.rs | 25 ++-- src/ipfs/daemon.rs | 149 +++++++++++++++++++-- src/ipfs/http.rs | 44 +++++++ src/ipfs/options.rs | 34 +++++ 6 files changed, 541 insertions(+), 28 deletions(-) create mode 100644 src/ipfs/http.rs create mode 100644 src/ipfs/options.rs diff --git a/Cargo.lock b/Cargo.lock index 73625c1..0b27680 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,17 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +[[package]] +name = "async-trait" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "atomic-polyfill" version = "0.1.10" @@ -167,6 +178,12 @@ version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +[[package]] +name = "bytes" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" + [[package]] name = "cfg-if" version = "1.0.0" @@ -452,15 +469,23 @@ name = "fission" version = "0.1.0" dependencies = [ "anyhow", + "async-trait", "base64 0.13.0", "bs58", "clap", "colored", "did-key", + "hyper", "serde", "serde_json", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -476,6 +501,45 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" +[[package]] +name = "futures-channel" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" + +[[package]] +name = "futures-sink" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" + +[[package]] +name = "futures-task" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" + +[[package]] +name = "futures-util" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +dependencies = [ + "futures-core", + "futures-task", + "pin-project-lite", + "pin-utils", +] + [[package]] name = "generic-array" version = "0.14.6" @@ -534,6 +598,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "hash32" version = "0.2.1" @@ -618,6 +701,64 @@ dependencies = [ "hmac 0.8.1", ] +[[package]] +name = "http" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "hyper" +version = "0.14.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "indexmap" version = "1.9.1" @@ -728,6 +869,18 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "mio" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + [[package]] name = "nb" version = "0.1.3" @@ -796,6 +949,18 @@ version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + [[package]] name = "pkcs8" version = "0.7.6" @@ -1091,6 +1256,25 @@ dependencies = [ "zeroize", ] +[[package]] +name = "slab" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +dependencies = [ + "autocfg", +] + +[[package]] +name = "socket2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "spin" version = "0.9.4" @@ -1171,6 +1355,68 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +[[package]] +name = "tokio" +version = "1.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "pin-project-lite", + "socket2", + "winapi", +] + +[[package]] +name = "tokio-util" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + [[package]] name = "typenum" version = "1.15.0" @@ -1232,6 +1478,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -1329,6 +1585,63 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" + [[package]] name = "wyz" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index e72a364..adb4a4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,6 @@ clap = { version = "3.2.12", features = ["derive"] } did-key = "0.1.1" colored = "2.0.0" serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0.87" \ No newline at end of file +serde_json = "1.0.87" +hyper = {version = "0.14", features = ["client", "http2", "tcp"]} +async-trait = "0.1.58" \ No newline at end of file diff --git a/src/ipfs.rs b/src/ipfs.rs index bf8702f..c1b30e9 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -1,25 +1,20 @@ //use std::collections::{HashMap, btree_map::OccupiedError}; +use async_trait::async_trait; use std::collections::HashMap; use anyhow::Result; -use serde::{Deserialize, Serialize}; pub mod daemon; +pub mod http; +pub mod options; +#[async_trait] pub trait Ipfs { - fn add_file(path:&str) -> Result; - fn add_directory(path:&str) -> Result; - fn add_bootstrap(peer_id:&str) -> Result>; - fn connect_to(peer_id:&str) -> Result>; - fn disconect_from(peer_id:&str)-> Result>; - fn config(options:HashMap) -> Result>; -} - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct CidData{ - bytes:i64, - hash:String, - name:String, - size:String + async fn add_file(&mut self, name:&str, file_name:&str, path:&str, contents:Vec) -> Result; + async fn add_directory(&mut self, path:&str) -> Result; + async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; + async fn connect_to(&mut self, peer_id:&str) -> Result>; + async fn disconect_from(&mut self, peer_id:&str)-> Result>; + async fn config(&mut self, options:HashMap) -> Result>; } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 168a5b6..41433b2 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,37 +1,162 @@ use crate::ipfs::Ipfs; -use super::CidData; -use anyhow::Result; +use anyhow::{Result, bail}; +use super::options::*; +use serde_json::Value; +use std::io::Read; use std::collections::HashMap; +use async_trait::async_trait; +use std::process::{Command, Child}; +use colored::Colorize; +use crate::ipfs::http::HttpHandler; +use std::time::{Duration, SystemTime}; +use std::thread::sleep; + pub struct IpfsViaDaemon { - + http:HttpHandler, + ipfs_process:Child, + is_ipfs_ready:bool, + last_ipfs_output:Vec } impl IpfsViaDaemon { pub fn new() -> Result { - todo!() + IpfsViaDaemon::configure()?; + let proccess = Command::new(IPFS_EXE) + .arg("daemon") + .spawn()?; + println!("{}", ("⚠️ Warning: Ipfs Proccess Started. Please do NOT force close this app⚠️".yellow())); + anyhow::Ok(IpfsViaDaemon{ + ipfs_process: proccess, + http: HttpHandler::new(), + is_ipfs_ready: false, + last_ipfs_output: vec![] + }) + } + fn configure() -> Result<()>{ + //This sets the API's address + let address = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_PORT); + let is_addr_set = Command::new(IPFS_EXE) + .arg("config") + .arg("Addresses.API") + .arg(address) + .spawn()? + .wait()? + .success(); + if !is_addr_set { + bail!("Attempted to set the api address, but failed!"); + } + anyhow::Ok(()) + } + async fn send_request(&mut self, options:&CmdOptions) -> Result>{ + self.await_ready()?; + let response = self.http.send_request(options); + anyhow::Ok(response.await?) + } + fn await_ready(&mut self) -> Result<()>{ + if self.is_ipfs_ready == true { return anyhow::Ok(());} + let start_time = SystemTime::now(); + loop { + match &mut self.ipfs_process.stdout { + Some(out) => { + let mut buffer:Vec = vec![]; + out.read_to_end(&mut buffer)?; + self.last_ipfs_output.append(&mut buffer); + drop(buffer); + + let text_so_far = match std::str::from_utf8(self.last_ipfs_output.as_slice()){ + Ok(text) => text, + Err(_) => "" + }; + if text_so_far.contains(READY_TEXT){ + self.is_ipfs_ready = true; + break; + }else if text_so_far.contains("\n") { + self.last_ipfs_output.clear(); + } + }, + None => () + } + + sleep(Duration::new(SLEEP_LENGTH as u64, 0)); + + let now = SystemTime::now(); + if now.duration_since(start_time)? > Duration::new(BOOT_TIME_OUT as u64, 0) { + bail!("{}","Failed to start ipfs because the timeout reached!!".red()) + } + } + anyhow::Ok(()) } } +#[async_trait] impl Ipfs for IpfsViaDaemon { - fn add_file(path:&str) -> Result { - todo!() + async fn add_file(&mut self, name:&str, file_name:&str, path:&str, contents:Vec) -> Result { + let cmd = "add"; + let args = HashMap::from([ + ("quieter", "true"), + ("cid-version", "1") + ]); + let disposition = format!("form-data; name=\"{}\"; filename=\"{}\"", name, file_name); + let headers = HashMap::from([ + ("Abspath", path), + ("Content-Disposition", &disposition), + ("Content-Type", "application/octet-stream") + ]); + let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); + let result_data = self.send_request(&cmd_options).await?; + return anyhow::Ok(std::str::from_utf8(result_data.as_slice())?.to_string()); } - fn add_directory(path:&str) -> Result { + async fn add_directory(&mut self, path:&str) -> Result { todo!() } - fn add_bootstrap(peer_id:&str) -> Result> { - todo!() + async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { + let cmd = "bootstrap/add"; + let args = HashMap::from([ + ("arg", peer_id) + ]); + let cmd_options = CmdOptions::new(cmd, &args); + let result_data = self.send_request(&cmd_options).await?; + let result_json:Value = serde_json::from_str(std::str::from_utf8(result_data.as_slice())?)?; + let peer_list:Vec = value_to_vec(&result_json, "peer")?; + return anyhow::Ok(peer_list); } - fn connect_to(peer_id:&str) -> Result> { + async fn connect_to(&mut self, peer_id:&str) -> Result> { todo!() } - fn disconect_from(peer_id:&str)-> Result> { + async fn disconect_from(&mut self, peer_id:&str)-> Result> { todo!() } - fn config(options:HashMap) -> Result> { + async fn config(&mut self, options:HashMap) -> Result> { todo!() } +} +impl Drop for IpfsViaDaemon { + fn drop(&mut self) { + self.ipfs_process.kill().unwrap(); + println!("{}", ("Ipfs proccess closed. Feel free to close app whenever. ✅".bright_green())) + } +} +//TODO: This needs to be move to utils +fn value_to_vec(json:&Value, index:&str) -> Result> + where A:Clone + for<'de> serde::Deserialize<'de>{ + anyhow::Ok( match json.get(index) { + Some(list_json) => { + match list_json.as_array() { + Some(list) => { + list.iter().map(|item_json| { + let item:A = match serde_json::from_value(item_json.clone()){ + Ok(x) => x, + Err(_) => panic!("Improperly formatted Json: cannot format type") + }; + item + }).collect() + }, + None => panic!("Improperly formatted Json: Not an Array") + } + }, + None => bail!("Improperly formatted Json: Cant locate index {}", index) + }) } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs new file mode 100644 index 0000000..6ed6b4a --- /dev/null +++ b/src/ipfs/http.rs @@ -0,0 +1,44 @@ +use hyper::body::{HttpBody, Bytes}; +use hyper::{Uri, Client, Request, Method, Body}; +use hyper::client::connect::HttpConnector; +use anyhow::{Result}; +use super::options::{CmdOptions, IPFS_PORT, IPFS_ADDR}; + +pub struct HttpHandler{ + http_client:Client, +} +impl HttpHandler { + pub fn new() -> HttpHandler{ + let client = Client::new(); + return HttpHandler{ + http_client:client + }; + } + pub async fn send_request(&self, options:&CmdOptions) -> Result>{ + let mut arg_str:String = options.args.iter() + .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) + .collect(); + arg_str.pop(); + let request_url = format!("{}:{}/api/v0/{}?{}", IPFS_ADDR, IPFS_PORT, options.cmd, arg_str); + drop(arg_str); + + let mut response = match &options.post_options { + Some(post_options) => { + let mut request = Request::builder() + .method(Method::POST) + .uri(request_url); + for (key, value) in &post_options.headers { + request = request.header(key, value); + } + self.http_client.request(request.body(Body::from((&post_options.body).clone()))?).await? + }, + None => { + let request:Uri = request_url.parse()?; + self.http_client.get(request).await? + } + }; + let response_body = response.body_mut(); + let response_bytes = response_body.data().await.unwrap_or( Ok(Bytes::new()))?.to_vec(); + anyhow::Ok(response_bytes) + } +} \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs new file mode 100644 index 0000000..26a75bc --- /dev/null +++ b/src/ipfs/options.rs @@ -0,0 +1,34 @@ +use std::collections::HashMap; + +pub const IPFS_PORT:u16 = 4867; +pub const IPFS_ADDR:&str = "127.0.0.1"; +pub const IPFS_EXE:&str = "ipfs"; +pub const BOOT_TIME_OUT:u16 = 120;//In seconds +pub const SLEEP_LENGTH:u8 = 1;//In seconds +pub const READY_TEXT:&str = "Daemon is ready"; + +pub struct PostOptions { + pub headers:HashMap, + pub body: Vec +} +pub struct CmdOptions { + pub cmd: String, + pub args: HashMap, + pub post_options: Option +} +impl CmdOptions { + pub fn new(cmd: &str, args: &HashMap<&str, &str>) -> Self{ + let owned_args:HashMap = args.iter() + .map(|(key, val)| (key.to_string(), val.to_string())) + .collect(); + Self { cmd:cmd.to_string(), args:owned_args, post_options: None } + } + pub fn to_post(mut self, headers: &HashMap<&str, &str>, body: &[u8]) -> Self{ + let owned_body = body.to_vec(); + let owned_headers:HashMap = headers.iter() + .map(|(key, val)| (key.to_string(), val.to_string())) + .collect(); + self.post_options = Some(PostOptions { headers: owned_headers, body: owned_body }); + return self; + } +} \ No newline at end of file From a8024c2d0349a7a223778ad749f83012ec57ead8 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 9 Nov 2022 11:08:12 -0700 Subject: [PATCH 20/63] ready for testing for a lot of it --- Cargo.lock | 51 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 ++- src/ipfs.rs | 2 +- src/ipfs/daemon.rs | 52 ++++++++++++++++++++++++++++++++++------------ 4 files changed, 93 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0b27680..f8885a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -475,6 +475,7 @@ dependencies = [ "clap", "colored", "did-key", + "futures", "hyper", "serde", "serde_json", @@ -501,6 +502,21 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" +[[package]] +name = "futures" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + [[package]] name = "futures-channel" version = "0.3.25" @@ -508,6 +524,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" dependencies = [ "futures-core", + "futures-sink", ] [[package]] @@ -516,6 +533,34 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +[[package]] +name = "futures-executor" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" + +[[package]] +name = "futures-macro" +version = "0.3.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "futures-sink" version = "0.3.25" @@ -534,10 +579,16 @@ version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" dependencies = [ + "futures-channel", "futures-core", + "futures-io", + "futures-macro", + "futures-sink", "futures-task", + "memchr", "pin-project-lite", "pin-utils", + "slab", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index adb4a4a..28614d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,4 +16,5 @@ colored = "2.0.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.87" hyper = {version = "0.14", features = ["client", "http2", "tcp"]} -async-trait = "0.1.58" \ No newline at end of file +async-trait = "0.1.58" +futures = "0.3.25" \ No newline at end of file diff --git a/src/ipfs.rs b/src/ipfs.rs index c1b30e9..109e67b 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -16,5 +16,5 @@ pub trait Ipfs { async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; async fn connect_to(&mut self, peer_id:&str) -> Result>; async fn disconect_from(&mut self, peer_id:&str)-> Result>; - async fn config(&mut self, options:HashMap) -> Result>; + async fn config(&mut self, options:HashMap) -> Result<()>; } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 41433b2..5a3240d 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -2,6 +2,7 @@ use crate::ipfs::Ipfs; use anyhow::{Result, bail}; use super::options::*; use serde_json::Value; +use futures::{join, Future}; use std::io::Read; use std::collections::HashMap; use async_trait::async_trait; @@ -85,6 +86,16 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } + async fn swarm_or_bootstrap_cmd(&mut self, cmd:&str, peer_id:&str) -> Result>{ + let args = HashMap::from([ + ("arg", peer_id) + ]); + let cmd_options = CmdOptions::new(cmd, &args); + let result_data = self.send_request(&cmd_options).await?; + let result_json:Value = serde_json::from_str(std::str::from_utf8(result_data.as_slice())?)?; + let peer_list:Vec = value_to_vec(&result_json, "peer")?; + return anyhow::Ok(peer_list); + } } #[async_trait] impl Ipfs for IpfsViaDaemon { @@ -110,27 +121,42 @@ impl Ipfs for IpfsViaDaemon { } async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { - let cmd = "bootstrap/add"; - let args = HashMap::from([ - ("arg", peer_id) - ]); - let cmd_options = CmdOptions::new(cmd, &args); - let result_data = self.send_request(&cmd_options).await?; - let result_json:Value = serde_json::from_str(std::str::from_utf8(result_data.as_slice())?)?; - let peer_list:Vec = value_to_vec(&result_json, "peer")?; - return anyhow::Ok(peer_list); + self.swarm_or_bootstrap_cmd("bootstrap/add", peer_id).await } async fn connect_to(&mut self, peer_id:&str) -> Result> { - todo!() + self.swarm_or_bootstrap_cmd("swarm/connect", peer_id).await } async fn disconect_from(&mut self, peer_id:&str)-> Result> { - todo!() + self.swarm_or_bootstrap_cmd("swarm/disconnect", peer_id).await } - async fn config(&mut self, options:HashMap) -> Result> { - todo!() + async fn config(&mut self, options:HashMap) -> Result<()> { + for (setting, value) in options { + let cleaned_value = value.to_lowercase(); + let is_bool = match cleaned_value.trim() == "true" || cleaned_value.trim() == "false" { + true => "true", + false => "false" + }; + let is_json = match serde_json::from_str::(&value).is_ok() { + true => "true", + false => "false" + }; + let args = HashMap::from([ + ("arg".to_string(), setting.to_string()), + ("arg".to_string(), value.to_string()), + ("bool".to_string(), is_bool.to_string()), + ("json".to_string(), is_json.to_string()) + ]); + let cmd_options = CmdOptions{ + cmd:"config".to_string(), + post_options:None, + args + }; + self.send_request(&cmd_options).await?; + } + anyhow::Ok(()) } } impl Drop for IpfsViaDaemon { From 3c06f282e49f31b036c689bba1681c4118bc52db Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 15 Nov 2022 13:19:53 -0700 Subject: [PATCH 21/63] first test done We can connect! YAY --- Cargo.lock | 492 +++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 4 +- src/ipfs/daemon.rs | 121 +++++++---- src/ipfs/http.rs | 93 ++++++--- src/ipfs/options.rs | 16 +- src/main.rs | 1 + 6 files changed, 645 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8885a0..59e32b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -184,6 +184,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +[[package]] +name = "cc" +version = "1.0.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" + [[package]] name = "cfg-if" version = "1.0.0" @@ -246,6 +252,22 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" + [[package]] name = "cortex-m" version = "0.7.6" @@ -442,6 +464,24 @@ dependencies = [ "void", ] +[[package]] +name = "encoding_rs" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + [[package]] name = "ff" version = "0.10.1" @@ -472,13 +512,15 @@ dependencies = [ "async-trait", "base64 0.13.0", "bs58", + "bytes", "clap", "colored", "did-key", "futures", - "hyper", + "reqwest", "serde", "serde_json", + "tokio", ] [[package]] @@ -487,6 +529,21 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" version = "1.1.0" @@ -810,6 +867,29 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper", + "native-tls", + "tokio", + "tokio-native-tls", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "1.9.1" @@ -820,6 +900,21 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" + [[package]] name = "itoa" version = "1.0.4" @@ -920,6 +1015,12 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + [[package]] name = "mio" version = "0.8.5" @@ -929,7 +1030,25 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys", + "windows-sys 0.42.0", +] + +[[package]] +name = "native-tls" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" +dependencies = [ + "lazy_static", + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] @@ -947,6 +1066,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi", + "libc", +] + [[package]] name = "once_cell" version = "1.13.0" @@ -959,6 +1088,51 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "openssl" +version = "0.10.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" +dependencies = [ + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" +dependencies = [ + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "os_str_bytes" version = "6.1.0" @@ -994,6 +1168,29 @@ dependencies = [ "group 0.11.0", ] +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys 0.42.0", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -1022,6 +1219,12 @@ dependencies = [ "spki", ] +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + [[package]] name = "ppv-lite86" version = "0.2.16" @@ -1136,6 +1339,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.6.0" @@ -1153,6 +1365,52 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "reqwest" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" +dependencies = [ + "base64 0.13.0", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-tls", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-native-tls", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "winreg", +] + [[package]] name = "riscv" version = "0.7.0" @@ -1198,12 +1456,45 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +[[package]] +name = "schannel" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" +dependencies = [ + "lazy_static", + "windows-sys 0.36.1", +] + [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "security-framework" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.9.0" @@ -1265,6 +1556,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "sha2" version = "0.9.9" @@ -1278,6 +1581,15 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + [[package]] name = "signature" version = "1.3.2" @@ -1316,6 +1628,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + [[package]] name = "socket2" version = "0.4.7" @@ -1391,6 +1709,20 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + [[package]] name = "termcolor" version = "1.1.3" @@ -1406,6 +1738,21 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "tokio" version = "1.21.2" @@ -1417,11 +1764,36 @@ dependencies = [ "libc", "memchr", "mio", + "num_cpus", + "parking_lot", "pin-project-lite", + "signal-hook-registry", "socket2", + "tokio-macros", "winapi", ] +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" +dependencies = [ + "native-tls", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.4" @@ -1474,24 +1846,56 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + [[package]] name = "unicode-ident" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "vcell" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" @@ -1576,6 +1980,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.83" @@ -1605,6 +2021,16 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +[[package]] +name = "web-sys" +version = "0.3.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -1636,6 +2062,19 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc 0.36.1", + "windows_i686_gnu 0.36.1", + "windows_i686_msvc 0.36.1", + "windows_x86_64_gnu 0.36.1", + "windows_x86_64_msvc 0.36.1", +] + [[package]] name = "windows-sys" version = "0.42.0" @@ -1643,12 +2082,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", + "windows_aarch64_msvc 0.42.0", + "windows_i686_gnu 0.42.0", + "windows_i686_msvc 0.42.0", + "windows_x86_64_gnu 0.42.0", "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_x86_64_msvc 0.42.0", ] [[package]] @@ -1657,24 +2096,48 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + [[package]] name = "windows_aarch64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + [[package]] name = "windows_i686_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + [[package]] name = "windows_i686_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + [[package]] name = "windows_x86_64_gnu" version = "0.42.0" @@ -1687,12 +2150,27 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" + [[package]] name = "windows_x86_64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + [[package]] name = "wyz" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 28614d2..4397dc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,8 @@ did-key = "0.1.1" colored = "2.0.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.87" -hyper = {version = "0.14", features = ["client", "http2", "tcp"]} +reqwest = "0.11.12" +bytes = "1.2.1" +tokio = { version = "1", features = ["full"] } async-trait = "0.1.58" futures = "0.3.25" \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 5a3240d..0d9ed0e 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -2,8 +2,6 @@ use crate::ipfs::Ipfs; use anyhow::{Result, bail}; use super::options::*; use serde_json::Value; -use futures::{join, Future}; -use std::io::Read; use std::collections::HashMap; use async_trait::async_trait; use std::process::{Command, Child}; @@ -15,12 +13,13 @@ use std::thread::sleep; pub struct IpfsViaDaemon { http:HttpHandler, ipfs_process:Child, - is_ipfs_ready:bool, - last_ipfs_output:Vec + is_ipfs_ready:bool } impl IpfsViaDaemon { pub fn new() -> Result { + println!("{}", "Configuring ipfs...".green()); IpfsViaDaemon::configure()?; + println!("{}", "Starting ipfs...".green()); let proccess = Command::new(IPFS_EXE) .arg("daemon") .spawn()?; @@ -28,17 +27,26 @@ impl IpfsViaDaemon { anyhow::Ok(IpfsViaDaemon{ ipfs_process: proccess, http: HttpHandler::new(), - is_ipfs_ready: false, - last_ipfs_output: vec![] + is_ipfs_ready: false }) } fn configure() -> Result<()>{ //This sets the API's address - let address = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_PORT); + //let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); + let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); + let http_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_HTTP_PORT); + //let http_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_HTTP_PORT); + IpfsViaDaemon::config_option("Addresses.API", &api_addr)?; + IpfsViaDaemon::config_option("Addresses.Gateway", &http_addr)?; + anyhow::Ok(()) + } + fn config_option(option:&str, value:&str)-> Result<()>{ + let cmd_str = format!("ipfs {} Addresses.API {}", option, value); + println!("running cmd \"{}\"", cmd_str.blue()); let is_addr_set = Command::new(IPFS_EXE) .arg("config") - .arg("Addresses.API") - .arg(address) + .arg(option) + .arg(value) .spawn()? .wait()? .success(); @@ -47,34 +55,22 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } - async fn send_request(&mut self, options:&CmdOptions) -> Result>{ - self.await_ready()?; - let response = self.http.send_request(options); + async fn send_request(&mut self, options:&CmdOptions, response_handler:F) -> Result + where F: Fn(Vec) -> Result{ + self.await_ready().await?; + let response = self.http.try_send_request(options, response_handler); anyhow::Ok(response.await?) } - fn await_ready(&mut self) -> Result<()>{ + async fn await_ready(&mut self) -> Result<()>{ if self.is_ipfs_ready == true { return anyhow::Ok(());} let start_time = SystemTime::now(); loop { - match &mut self.ipfs_process.stdout { - Some(out) => { - let mut buffer:Vec = vec![]; - out.read_to_end(&mut buffer)?; - self.last_ipfs_output.append(&mut buffer); - drop(buffer); - - let text_so_far = match std::str::from_utf8(self.last_ipfs_output.as_slice()){ - Ok(text) => text, - Err(_) => "" - }; - if text_so_far.contains(READY_TEXT){ - self.is_ipfs_ready = true; - break; - }else if text_so_far.contains("\n") { - self.last_ipfs_output.clear(); - } - }, - None => () + println!("{}", "checking if ipfs is ready...".green()); + + if self.poll_ipfs_ready().await { + println!("{}", "IPFS is ready!!".green()); + self.is_ipfs_ready = true; + break; } sleep(Duration::new(SLEEP_LENGTH as u64, 0)); @@ -86,14 +82,43 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } + async fn poll_ipfs_ready(&mut self) -> bool{ + let args = HashMap::new(); + let cmd = CmdOptions::new("config/show", &args); + let response = self.http.send_request(&cmd).await; + return match response { + Ok(_) => true, + Err(e) => { + eprint!("{}", e); + false + } + }; + } async fn swarm_or_bootstrap_cmd(&mut self, cmd:&str, peer_id:&str) -> Result>{ let args = HashMap::from([ ("arg", peer_id) ]); let cmd_options = CmdOptions::new(cmd, &args); - let result_data = self.send_request(&cmd_options).await?; - let result_json:Value = serde_json::from_str(std::str::from_utf8(result_data.as_slice())?)?; - let peer_list:Vec = value_to_vec(&result_json, "peer")?; + let peer_list = self.send_request(&cmd_options, |result_data| { + let result_str =std::str::from_utf8(result_data.as_slice())?; + let result_json:Value = match serde_json::from_str(result_str){ + Ok(x) => x, + Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) + }; + let peer_list = match value_to_vec::(&result_json, "Strings"){ + Ok(peers) => { + for peer in peers.iter() { + if !peer.contains("success"){ + bail!("The following peer did not successfully connect: {}", peer) + } + } + anyhow::Ok(peers) + }, + Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) + }; + anyhow::Ok(peer_list?) + }).await?; + return anyhow::Ok(peer_list); } } @@ -112,8 +137,10 @@ impl Ipfs for IpfsViaDaemon { ("Content-Type", "application/octet-stream") ]); let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); - let result_data = self.send_request(&cmd_options).await?; - return anyhow::Ok(std::str::from_utf8(result_data.as_slice())?.to_string()); + let result = self.send_request(&cmd_options, |result_data| { + anyhow::Ok(std::str::from_utf8(result_data.as_slice())?.to_string()) + }).await?; + return anyhow::Ok(result); } async fn add_directory(&mut self, path:&str) -> Result { @@ -154,7 +181,7 @@ impl Ipfs for IpfsViaDaemon { post_options:None, args }; - self.send_request(&cmd_options).await?; + self.send_request(&cmd_options, |_| anyhow::Ok(())).await?; } anyhow::Ok(()) } @@ -162,7 +189,7 @@ impl Ipfs for IpfsViaDaemon { impl Drop for IpfsViaDaemon { fn drop(&mut self) { self.ipfs_process.kill().unwrap(); - println!("{}", ("Ipfs proccess closed. Feel free to close app whenever. ✅".bright_green())) + println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } } //TODO: This needs to be move to utils @@ -185,4 +212,20 @@ fn value_to_vec(json:&Value, index:&str) -> Result> }, None => bail!("Improperly formatted Json: Cant locate index {}", index) }) +} + +#[cfg(test)] +mod tests { + use futures::executor::block_on; + + use super::*; + + #[test] + fn can_connect(){ + println!("starting test"); + let peer_id = "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ"; + let mut ipfs = IpfsViaDaemon::new().unwrap(); + block_on(ipfs.connect_to(peer_id)).unwrap(); + assert!(true); + } } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index 6ed6b4a..efefa57 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -1,44 +1,71 @@ -use hyper::body::{HttpBody, Bytes}; -use hyper::{Uri, Client, Request, Method, Body}; -use hyper::client::connect::HttpConnector; -use anyhow::{Result}; -use super::options::{CmdOptions, IPFS_PORT, IPFS_ADDR}; +use bytes::Bytes; + +use colored::Colorize; +use anyhow::Result; +use tokio::runtime::Runtime; +use reqwest::{Client, Response}; +use super::options::{CmdOptions, IPFS_RETRY_ATTEMPTS}; pub struct HttpHandler{ - http_client:Client, + http_client:Client, + tokio:Runtime } impl HttpHandler { pub fn new() -> HttpHandler{ let client = Client::new(); + let runtime = tokio::runtime::Runtime::new().unwrap(); return HttpHandler{ - http_client:client + http_client:client, + tokio:runtime }; } - pub async fn send_request(&self, options:&CmdOptions) -> Result>{ - let mut arg_str:String = options.args.iter() - .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) - .collect(); - arg_str.pop(); - let request_url = format!("{}:{}/api/v0/{}?{}", IPFS_ADDR, IPFS_PORT, options.cmd, arg_str); - drop(arg_str); - - let mut response = match &options.post_options { - Some(post_options) => { - let mut request = Request::builder() - .method(Method::POST) - .uri(request_url); - for (key, value) in &post_options.headers { - request = request.header(key, value); - } - self.http_client.request(request.body(Body::from((&post_options.body).clone()))?).await? - }, - None => { - let request:Uri = request_url.parse()?; - self.http_client.get(request).await? - } + + pub async fn send_request(&mut self, options:&CmdOptions) -> Result>{ + let request_url = options.get_url(); + let body = match &options.post_options { + Some(post_options) => Bytes::copy_from_slice(post_options.body.as_slice()), + None => Bytes::new() }; - let response_body = response.body_mut(); - let response_bytes = response_body.data().await.unwrap_or( Ok(Bytes::new()))?.to_vec(); - anyhow::Ok(response_bytes) + println!("{}", (format!("sending get or post request to \"{}\"", request_url).green())); + let response = self.tokio.block_on(async { + self.http_client + .post(request_url) + .body(body) + .send().await + })?; + let response_bytes = response.bytes().await?; + println!("response recieved"); + anyhow::Ok(response_bytes.into()) } -} \ No newline at end of file + pub async fn try_send_request(&mut self, options:&CmdOptions, response_handler:F) -> Result + where F: Fn(Vec) -> Result{ + let mut attempt:u8 = 1; + 'attempt_loop: loop { + println!("attempting to send post request: attempt {} of {}", attempt, IPFS_RETRY_ATTEMPTS); + let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS; + let response_result = self.send_request(options).await; + let response = match is_final_attempt { + true => response_result?, + false => { match response_result { + Ok(x) => x, + Err(_) => { + attempt += 1; + continue 'attempt_loop + } + }} + }; + let handled_result = match is_final_attempt { + true => response_handler(response), + false => { match response_handler(response) { + Ok(x) => Ok(x), + Err(_) => { + attempt += 1; + continue 'attempt_loop + } + }} + }; + return Ok(handled_result?); + } + } + +} diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index 26a75bc..56df4b7 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -1,11 +1,12 @@ use std::collections::HashMap; -pub const IPFS_PORT:u16 = 4867; +pub const IPFS_API_PORT:u16 = 4867; +pub const IPFS_HTTP_PORT:u16 = 5742; +pub const IPFS_RETRY_ATTEMPTS:u8 = 3; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const BOOT_TIME_OUT:u16 = 120;//In seconds pub const SLEEP_LENGTH:u8 = 1;//In seconds -pub const READY_TEXT:&str = "Daemon is ready"; pub struct PostOptions { pub headers:HashMap, @@ -31,4 +32,15 @@ impl CmdOptions { self.post_options = Some(PostOptions { headers: owned_headers, body: owned_body }); return self; } + pub fn get_url(&self) -> String { + let mut arg_str:String = self.args.iter() + .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) + .collect(); + arg_str.pop(); + let url = format!("http://{}:{}/api/v0/{}", IPFS_ADDR, IPFS_API_PORT, self.cmd); + return match arg_str.len() == 0{ + true => url, + false => format!("{}?{}", url, arg_str) + } + } } \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index baa6261..7312a9c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,6 +55,7 @@ enum Commands { remote: Option, }, } + fn main() { let cli = Cli::parse(); From bf7db0670a486545cf6c102e1d32a5ddd457a6db Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Fri, 18 Nov 2022 14:32:00 -0700 Subject: [PATCH 22/63] fibonacci http retry wait --- Cargo.lock | 136 +++++++++++++++++++++++++++++++++++++++++++- Cargo.toml | 6 +- src/ipfs/daemon.rs | 111 +++++++++++++++++++++++++----------- src/ipfs/http.rs | 31 +++++----- src/ipfs/options.rs | 2 +- 5 files changed, 233 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 59e32b3..cb44aeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,6 +60,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "az" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" + [[package]] name = "bare-metal" version = "0.2.5" @@ -87,6 +93,21 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + [[package]] name = "bit_field" version = "0.10.1" @@ -172,6 +193,12 @@ version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +[[package]] +name = "bytemuck" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" + [[package]] name = "byteorder" version = "1.4.3" @@ -432,7 +459,7 @@ checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ "curve25519-dalek", "ed25519", - "rand", + "rand 0.7.3", "serde", "sha2", "zeroize", @@ -516,13 +543,27 @@ dependencies = [ "clap", "colored", "did-key", + "fixed", "futures", + "proptest", "reqwest", "serde", "serde_json", "tokio", ] +[[package]] +name = "fixed" +version = "1.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418922d2c280b8c68f82699494cc8c48f392233233a9a8b9a48a57a36c0ad0ef" +dependencies = [ + "az", + "bytemuck", + "half", + "typenum", +] + [[package]] name = "fnv" version = "1.0.7" @@ -725,6 +766,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "half" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554" +dependencies = [ + "crunchy", +] + [[package]] name = "hash32" version = "0.2.1" @@ -955,7 +1005,7 @@ dependencies = [ "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", - "rand", + "rand 0.7.3", "serde", "sha2", "typenum", @@ -1066,6 +1116,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.14.0" @@ -1264,6 +1323,38 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" +dependencies = [ + "bit-set", + "bitflags", + "byteorder", + "lazy_static", + "num-traits", + "quick-error 2.0.1", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + [[package]] name = "quote" version = "1.0.20" @@ -1292,6 +1383,17 @@ dependencies = [ "rand_hc", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -1339,6 +1441,15 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -1450,6 +1561,18 @@ dependencies = [ "semver 1.0.14", ] +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.11" @@ -1933,6 +2056,15 @@ dependencies = [ "zeroize", ] +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 4397dc0..440b905 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,4 +19,8 @@ reqwest = "0.11.12" bytes = "1.2.1" tokio = { version = "1", features = ["full"] } async-trait = "0.1.58" -futures = "0.3.25" \ No newline at end of file +futures = "0.3.25" +fixed = "1.20.0" + +[dev-dependencies] +proptest = "1.0.0" \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 0d9ed0e..3aa7428 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,5 +1,6 @@ use crate::ipfs::Ipfs; use anyhow::{Result, bail}; +use futures::executor::block_on; use super::options::*; use serde_json::Value; use std::collections::HashMap; @@ -13,7 +14,8 @@ use std::thread::sleep; pub struct IpfsViaDaemon { http:HttpHandler, ipfs_process:Child, - is_ipfs_ready:bool + is_ipfs_ready:bool, + connected_peers:Vec } impl IpfsViaDaemon { pub fn new() -> Result { @@ -27,7 +29,8 @@ impl IpfsViaDaemon { anyhow::Ok(IpfsViaDaemon{ ipfs_process: proccess, http: HttpHandler::new(), - is_ipfs_ready: false + is_ipfs_ready: false, + connected_peers: vec![] }) } fn configure() -> Result<()>{ @@ -55,10 +58,9 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } - async fn send_request(&mut self, options:&CmdOptions, response_handler:F) -> Result - where F: Fn(Vec) -> Result{ + async fn send_request(&mut self, options:&CmdOptions) -> Result>{ self.await_ready().await?; - let response = self.http.try_send_request(options, response_handler); + let response = self.http.try_send_request(options); anyhow::Ok(response.await?) } async fn await_ready(&mut self) -> Result<()>{ @@ -99,25 +101,23 @@ impl IpfsViaDaemon { ("arg", peer_id) ]); let cmd_options = CmdOptions::new(cmd, &args); - let peer_list = self.send_request(&cmd_options, |result_data| { - let result_str =std::str::from_utf8(result_data.as_slice())?; - let result_json:Value = match serde_json::from_str(result_str){ - Ok(x) => x, - Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) - }; - let peer_list = match value_to_vec::(&result_json, "Strings"){ - Ok(peers) => { - for peer in peers.iter() { - if !peer.contains("success"){ - bail!("The following peer did not successfully connect: {}", peer) - } + let result_data = self.send_request(&cmd_options).await?; + let result_str =std::str::from_utf8(result_data.as_slice())?; + let result_json:Value = match serde_json::from_str(result_str){ + Ok(x) => x, + Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) + }; + let peer_list = match value_to_vec::(&result_json, "Strings"){ + Ok(peers) => { + for peer in peers.iter() { + if !peer.contains("success"){ + bail!("The following peer did not successfully connect: {}", peer) } - anyhow::Ok(peers) - }, - Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) - }; - anyhow::Ok(peer_list?) - }).await?; + } + peers + }, + Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) + }; return anyhow::Ok(peer_list); } @@ -137,9 +137,8 @@ impl Ipfs for IpfsViaDaemon { ("Content-Type", "application/octet-stream") ]); let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); - let result = self.send_request(&cmd_options, |result_data| { - anyhow::Ok(std::str::from_utf8(result_data.as_slice())?.to_string()) - }).await?; + let result_data = self.send_request(&cmd_options).await?; + let result = std::str::from_utf8(result_data.as_slice())?.to_string(); return anyhow::Ok(result); } @@ -152,11 +151,20 @@ impl Ipfs for IpfsViaDaemon { } async fn connect_to(&mut self, peer_id:&str) -> Result> { - self.swarm_or_bootstrap_cmd("swarm/connect", peer_id).await + let response = self.swarm_or_bootstrap_cmd("swarm/connect", peer_id).await?; + self.connected_peers.push(peer_id.to_string()); + print!("Connected Peers: "); + self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); + anyhow::Ok(response) } async fn disconect_from(&mut self, peer_id:&str)-> Result> { - self.swarm_or_bootstrap_cmd("swarm/disconnect", peer_id).await + let response = self.swarm_or_bootstrap_cmd("swarm/disconnect", peer_id).await?; + self.connected_peers.iter_mut() + .filter(|peer_id_to_check| (peer_id_to_check.to_string() != peer_id.to_string())); + print!("Connected Peers: "); + self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); + anyhow::Ok(response) } async fn config(&mut self, options:HashMap) -> Result<()> { @@ -181,13 +189,16 @@ impl Ipfs for IpfsViaDaemon { post_options:None, args }; - self.send_request(&cmd_options, |_| anyhow::Ok(())).await?; + self.send_request(&cmd_options).await?; } anyhow::Ok(()) } } impl Drop for IpfsViaDaemon { fn drop(&mut self) { + for peer in self.connected_peers.clone(){ + block_on(self.disconect_from(&peer)); + } self.ipfs_process.kill().unwrap(); println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } @@ -217,15 +228,47 @@ fn value_to_vec(json:&Value, index:&str) -> Result> #[cfg(test)] mod tests { use futures::executor::block_on; - + use anyhow::Result; + use proptest::prelude::*; use super::*; + const PEER_ADDRS:&'static [&'static str] = &[ + "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", + "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", + "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4001/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", + "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/ip4/54.235.17.70/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/ip4/54.235.17.70/udp/4001/quic/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4001/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", + "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4001/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", + "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4001/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", + "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", + "/ip4/54.235.17.70/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", + ]; + + fn connect_to_peers() -> IpfsViaDaemon{ + let mut ipfs = IpfsViaDaemon::new().unwrap(); + for peer in PEER_ADDRS { + block_on(ipfs.connect_to(peer)).unwrap(); + } + ipfs + + } + #[test] fn can_connect(){ - println!("starting test"); - let peer_id = "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ"; - let mut ipfs = IpfsViaDaemon::new().unwrap(); - block_on(ipfs.connect_to(peer_id)).unwrap(); + connect_to_peers(); assert!(true); } + // proptest! { + // #[test] + // #[serial] + // fn can_add_file(s: &str){ + // let mut ipfs = connect_to_peers(); + // ipf.add_file() + // assert!(true); + // } + // } } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index efefa57..4b1c38d 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -1,9 +1,11 @@ +use std::time::Duration; + use bytes::Bytes; use colored::Colorize; use anyhow::Result; use tokio::runtime::Runtime; -use reqwest::{Client, Response}; +use reqwest::Client; use super::options::{CmdOptions, IPFS_RETRY_ATTEMPTS}; pub struct HttpHandler{ @@ -37,10 +39,12 @@ impl HttpHandler { println!("response recieved"); anyhow::Ok(response_bytes.into()) } - pub async fn try_send_request(&mut self, options:&CmdOptions, response_handler:F) -> Result - where F: Fn(Vec) -> Result{ - let mut attempt:u8 = 1; + pub async fn try_send_request(&mut self, options:&CmdOptions) -> Result>{ + let mut attempt:u16 = 1; 'attempt_loop: loop { + if attempt != 1 { + std::thread::sleep(Duration::new(get_fibinaci(attempt), 0)) + } println!("attempting to send post request: attempt {} of {}", attempt, IPFS_RETRY_ATTEMPTS); let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS; let response_result = self.send_request(options).await; @@ -54,18 +58,15 @@ impl HttpHandler { } }} }; - let handled_result = match is_final_attempt { - true => response_handler(response), - false => { match response_handler(response) { - Ok(x) => Ok(x), - Err(_) => { - attempt += 1; - continue 'attempt_loop - } - }} - }; - return Ok(handled_result?); + return anyhow::Ok(response); } } } + +fn get_fibinaci(n:u16) -> u64{ + let phi:f64 = fixed::consts::PHI.to_num(); + let numerator:f64 = phi.powi(n as i32)-((-phi).powi(n as i32)); + let denominator:f64 = f64::sqrt(5 as f64); + return (numerator/denominator).round() as u64; +} \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index 56df4b7..c70d208 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; pub const IPFS_API_PORT:u16 = 4867; pub const IPFS_HTTP_PORT:u16 = 5742; -pub const IPFS_RETRY_ATTEMPTS:u8 = 3; +pub const IPFS_RETRY_ATTEMPTS:u16 = 10; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const BOOT_TIME_OUT:u16 = 120;//In seconds From 0999da9811b900008f42c4373bc34c512df37bda Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Fri, 25 Nov 2022 10:40:44 -0600 Subject: [PATCH 23/63] try fail http fixed --- Cargo.lock | 21 ++++++++++ Cargo.toml | 1 + src/ipfs/daemon.rs | 28 +++++++++++--- src/ipfs/http.rs | 21 +++++++--- src/ipfs/options.rs | 2 +- test-dir/more/also-test.txt | 76 +++++++++++++++++++++++++++++++++++++ test-dir/text.txt | 1 + 7 files changed, 137 insertions(+), 13 deletions(-) create mode 100644 test-dir/more/also-test.txt create mode 100644 test-dir/text.txt diff --git a/Cargo.lock b/Cargo.lock index cb44aeb..4bad6f1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -550,6 +550,7 @@ dependencies = [ "serde", "serde_json", "tokio", + "walkdir", ] [[package]] @@ -1579,6 +1580,15 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "schannel" version = "0.1.20" @@ -2065,6 +2075,17 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "want" version = "0.3.0" diff --git a/Cargo.toml b/Cargo.toml index 440b905..895e6a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,7 @@ tokio = { version = "1", features = ["full"] } async-trait = "0.1.58" futures = "0.3.25" fixed = "1.20.0" +walkdir = "2.3.2" [dev-dependencies] proptest = "1.0.0" \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 3aa7428..1fb8ee8 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,6 +1,7 @@ use crate::ipfs::Ipfs; use anyhow::{Result, bail}; use futures::executor::block_on; +use reqwest::header; use super::options::*; use serde_json::Value; use std::collections::HashMap; @@ -10,6 +11,7 @@ use colored::Colorize; use crate::ipfs::http::HttpHandler; use std::time::{Duration, SystemTime}; use std::thread::sleep; +use walkdir::WalkDir; pub struct IpfsViaDaemon { http:HttpHandler, @@ -60,8 +62,12 @@ impl IpfsViaDaemon { } async fn send_request(&mut self, options:&CmdOptions) -> Result>{ self.await_ready().await?; - let response = self.http.try_send_request(options); - anyhow::Ok(response.await?) + let result = self.http.try_send_request(options, Some(|response_data:Vec| { + let response_str = std::str::from_utf8(response_data.as_slice())?; + //TODO: do a better job of checking here + anyhow::Ok(!(response_str.contains("\"Type\":\"error\""))) + })).await?; + anyhow::Ok(result)//it always return Some if a handler is given } async fn await_ready(&mut self) -> Result<()>{ if self.is_ipfs_ready == true { return anyhow::Ok(());} @@ -132,9 +138,8 @@ impl Ipfs for IpfsViaDaemon { ]); let disposition = format!("form-data; name=\"{}\"; filename=\"{}\"", name, file_name); let headers = HashMap::from([ - ("Abspath", path), - ("Content-Disposition", &disposition), - ("Content-Type", "application/octet-stream") + ("Content-Type", "application/octet-stream"), + ("Content-Disposition", &disposition) ]); let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); let result_data = self.send_request(&cmd_options).await?; @@ -143,7 +148,10 @@ impl Ipfs for IpfsViaDaemon { } async fn add_directory(&mut self, path:&str) -> Result { - todo!() + for entry in WalkDir::new(path) { + print!("{}", std::fs::read_to_string(entry?.path())?) + } + anyhow::Ok("Done".to_string()) } async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { @@ -232,6 +240,7 @@ mod tests { use proptest::prelude::*; use super::*; + //TODO: Setup pizza const PEER_ADDRS:&'static [&'static str] = &[ "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", @@ -271,4 +280,11 @@ mod tests { // assert!(true); // } // } + #[test] + fn can_add_directory(){ + let testdir = "./test-dir"; + let mut ipfs = connect_to_peers(); + block_on(ipfs.add_directory(testdir)).unwrap(); + assert!(true); + } } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index 4b1c38d..36adb1a 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -39,9 +39,11 @@ impl HttpHandler { println!("response recieved"); anyhow::Ok(response_bytes.into()) } - pub async fn try_send_request(&mut self, options:&CmdOptions) -> Result>{ - let mut attempt:u16 = 1; + pub async fn try_send_request(&mut self, options:&CmdOptions, handler_option:Option) -> Result> + where F: Fn(Vec) -> Result{ + let mut attempt:u16 = 0; 'attempt_loop: loop { + attempt += 1; if attempt != 1 { std::thread::sleep(Duration::new(get_fibinaci(attempt), 0)) } @@ -52,12 +54,19 @@ impl HttpHandler { true => response_result?, false => { match response_result { Ok(x) => x, - Err(_) => { - attempt += 1; - continue 'attempt_loop - } + Err(_) => continue 'attempt_loop }} }; + if is_final_attempt && handler_option.as_ref().is_some(){ + (handler_option.unwrap())(response.clone())?; + }else if handler_option.is_some(){ + let handler_result = (handler_option.as_ref().unwrap())(response.clone()); + if handler_result.is_err() { + continue 'attempt_loop; + }else if !(handler_result.unwrap()) { + continue 'attempt_loop; + } + } return anyhow::Ok(response); } } diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index c70d208..aa18abc 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; pub const IPFS_API_PORT:u16 = 4867; pub const IPFS_HTTP_PORT:u16 = 5742; -pub const IPFS_RETRY_ATTEMPTS:u16 = 10; +pub const IPFS_RETRY_ATTEMPTS:u16 = 7; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const BOOT_TIME_OUT:u16 = 120;//In seconds diff --git a/test-dir/more/also-test.txt b/test-dir/more/also-test.txt new file mode 100644 index 0000000..3ca99b2 --- /dev/null +++ b/test-dir/more/also-test.txt @@ -0,0 +1,76 @@ +We're no strangers to love +You know the rules and so do I +A full commitment's what I'm thinking of +You wouldn't get this from any other guy + +I just wanna tell you how I'm feeling +Gotta make you understand + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +We've known each other for so long +Your heart's been aching, but +You're too shy to say it +Inside, we both know what's been going on +We know the game and we're gonna play it + +And if you ask me how I'm feeling +Don't tell me you're too blind to see + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +(Ooh, give you up) +(Ooh, give you up) +Never gonna give, never gonna give +(Give you up) +Never gonna give, never gonna give +(Give you up) + +We've known each other for so long +Your heart's been aching, but +You're too shy to say it +Inside, we both know what's been going on +We know the game and we're gonna play it + +I just wanna tell you how I'm feeling +Gotta make you understand + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +Never gonna give you up +Never gonna let you down +Never gonna run around and desert you +Never gonna make you cry +Never gonna say goodbye +Never gonna tell a lie and hurt you + +He-he, you just got Rickrolled! \ No newline at end of file diff --git a/test-dir/text.txt b/test-dir/text.txt new file mode 100644 index 0000000..45d1d67 --- /dev/null +++ b/test-dir/text.txt @@ -0,0 +1 @@ +WEEEE! I am a test!! \ No newline at end of file From 262c6e74d9884a8bae3e7878b8d79f2fa9134d6d Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 18:29:15 -0600 Subject: [PATCH 24/63] refactor and more --- Cargo.lock | 413 +------------------------------- Cargo.toml | 3 +- src/ipfs.rs | 2 +- src/ipfs/daemon.rs | 152 +++++++----- src/ipfs/http.rs | 137 ++++++++--- src/ipfs/options.rs | 42 +--- src/lib.rs | 1 + src/utils.rs | 4 + src/utils/file_management.rs | 69 ++++++ src/utils/json.rs | 30 +++ src/utils/math.rs | 6 + test-dir/more/fission_logo.png | Bin 0 -> 31609 bytes test-dir/{text.txt => test.txt} | 0 13 files changed, 323 insertions(+), 536 deletions(-) create mode 100644 src/utils/file_management.rs create mode 100644 src/utils/json.rs create mode 100644 src/utils/math.rs create mode 100644 test-dir/more/fission_logo.png rename test-dir/{text.txt => test.txt} (100%) diff --git a/Cargo.lock b/Cargo.lock index 4bad6f1..7085ab5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,12 +60,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" -[[package]] -name = "az" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" - [[package]] name = "bare-metal" version = "0.2.5" @@ -193,12 +187,6 @@ version = "3.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" -[[package]] -name = "bytemuck" -version = "1.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f" - [[package]] name = "byteorder" version = "1.4.3" @@ -211,12 +199,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" -[[package]] -name = "cc" -version = "1.0.76" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a284da2e6fe2092f2353e51713435363112dfd60030e22add80be333fb928f" - [[package]] name = "cfg-if" version = "1.0.0" @@ -279,22 +261,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - [[package]] name = "cortex-m" version = "0.7.6" @@ -491,15 +457,6 @@ dependencies = [ "void", ] -[[package]] -name = "encoding_rs" -version = "0.8.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" -dependencies = [ - "cfg-if", -] - [[package]] name = "fastrand" version = "1.8.0" @@ -543,49 +500,21 @@ dependencies = [ "clap", "colored", "did-key", - "fixed", "futures", + "hyper", "proptest", - "reqwest", "serde", "serde_json", "tokio", "walkdir", ] -[[package]] -name = "fixed" -version = "1.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418922d2c280b8c68f82699494cc8c48f392233233a9a8b9a48a57a36c0ad0ef" -dependencies = [ - "az", - "bytemuck", - "half", - "typenum", -] - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - [[package]] name = "form_urlencoded" version = "1.1.0" @@ -767,15 +696,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "half" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad6a9459c9c30b177b925162351f97e7d967c7ea8bab3b8352805327daf45554" -dependencies = [ - "crunchy", -] - [[package]] name = "hash32" version = "0.2.1" @@ -918,29 +838,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-tls" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" -dependencies = [ - "bytes", - "hyper", - "native-tls", - "tokio", - "tokio-native-tls", -] - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "indexmap" version = "1.9.1" @@ -960,12 +857,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "ipnet" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" - [[package]] name = "itoa" version = "1.0.4" @@ -1066,12 +957,6 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" -[[package]] -name = "mime" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" - [[package]] name = "mio" version = "0.8.5" @@ -1081,25 +966,7 @@ dependencies = [ "libc", "log", "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.42.0", -] - -[[package]] -name = "native-tls" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", + "windows-sys", ] [[package]] @@ -1148,51 +1015,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" -[[package]] -name = "openssl" -version = "0.10.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-macros", - "openssl-sys", -] - -[[package]] -name = "openssl-macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - [[package]] name = "os_str_bytes" version = "6.1.0" @@ -1248,7 +1070,7 @@ dependencies = [ "libc", "redox_syscall", "smallvec", - "windows-sys 0.42.0", + "windows-sys", ] [[package]] @@ -1279,12 +1101,6 @@ dependencies = [ "spki", ] -[[package]] -name = "pkg-config" -version = "0.3.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" - [[package]] name = "ppv-lite86" version = "0.2.16" @@ -1486,43 +1302,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "reqwest" -version = "0.11.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc" -dependencies = [ - "base64 0.13.0", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-tls", - "ipnet", - "js-sys", - "log", - "mime", - "native-tls", - "once_cell", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-native-tls", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "winreg", -] - [[package]] name = "riscv" version = "0.7.0" @@ -1589,45 +1368,12 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "schannel" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2" -dependencies = [ - "lazy_static", - "windows-sys 0.36.1", -] - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "security-framework" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "semver" version = "0.9.0" @@ -1689,18 +1435,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - [[package]] name = "sha2" version = "0.9.9" @@ -1871,21 +1605,6 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - [[package]] name = "tokio" version = "1.21.2" @@ -1917,16 +1636,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-native-tls" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" -dependencies = [ - "native-tls", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.4" @@ -1979,56 +1688,24 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - [[package]] name = "unicode-ident" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - [[package]] name = "vcell" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "version_check" version = "0.9.4" @@ -2133,18 +1810,6 @@ dependencies = [ "wasm-bindgen-shared", ] -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "wasm-bindgen-macro" version = "0.2.83" @@ -2174,16 +1839,6 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "winapi" version = "0.3.9" @@ -2215,19 +1870,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows-sys" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" -dependencies = [ - "windows_aarch64_msvc 0.36.1", - "windows_i686_gnu 0.36.1", - "windows_i686_msvc 0.36.1", - "windows_x86_64_gnu 0.36.1", - "windows_x86_64_msvc 0.36.1", -] - [[package]] name = "windows-sys" version = "0.42.0" @@ -2235,12 +1877,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" dependencies = [ "windows_aarch64_gnullvm", - "windows_aarch64_msvc 0.42.0", - "windows_i686_gnu 0.42.0", - "windows_i686_msvc 0.42.0", - "windows_x86_64_gnu 0.42.0", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", "windows_x86_64_gnullvm", - "windows_x86_64_msvc 0.42.0", + "windows_x86_64_msvc", ] [[package]] @@ -2249,48 +1891,24 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" -[[package]] -name = "windows_aarch64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" - [[package]] name = "windows_aarch64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" -[[package]] -name = "windows_i686_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" - [[package]] name = "windows_i686_gnu" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" -[[package]] -name = "windows_i686_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" - [[package]] name = "windows_i686_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" -[[package]] -name = "windows_x86_64_gnu" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" - [[package]] name = "windows_x86_64_gnu" version = "0.42.0" @@ -2303,27 +1921,12 @@ version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" -[[package]] -name = "windows_x86_64_msvc" -version = "0.36.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" - [[package]] name = "windows_x86_64_msvc" version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - [[package]] name = "wyz" version = "0.4.0" diff --git a/Cargo.toml b/Cargo.toml index 895e6a6..9875754 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,12 +15,11 @@ did-key = "0.1.1" colored = "2.0.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0.87" -reqwest = "0.11.12" +hyper = { version = "0.14", features = ["full"] } bytes = "1.2.1" tokio = { version = "1", features = ["full"] } async-trait = "0.1.58" futures = "0.3.25" -fixed = "1.20.0" walkdir = "2.3.2" [dev-dependencies] diff --git a/src/ipfs.rs b/src/ipfs.rs index 109e67b..3c3d78e 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -11,7 +11,7 @@ pub mod options; #[async_trait] pub trait Ipfs { - async fn add_file(&mut self, name:&str, file_name:&str, path:&str, contents:Vec) -> Result; + async fn add_file(&mut self, path:&str) -> Result; async fn add_directory(&mut self, path:&str) -> Result; async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; async fn connect_to(&mut self, peer_id:&str) -> Result>; diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 1fb8ee8..fa9b5d3 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,7 +1,8 @@ use crate::ipfs::Ipfs; +use crate::utils::*; use anyhow::{Result, bail}; use futures::executor::block_on; -use reqwest::header; +use super::http::HttpRequest; use super::options::*; use serde_json::Value; use std::collections::HashMap; @@ -11,7 +12,6 @@ use colored::Colorize; use crate::ipfs::http::HttpHandler; use std::time::{Duration, SystemTime}; use std::thread::sleep; -use walkdir::WalkDir; pub struct IpfsViaDaemon { http:HttpHandler, @@ -60,7 +60,7 @@ impl IpfsViaDaemon { } anyhow::Ok(()) } - async fn send_request(&mut self, options:&CmdOptions) -> Result>{ + async fn send_request(&mut self, options:&HttpRequest) -> Result>{ self.await_ready().await?; let result = self.http.try_send_request(options, Some(|response_data:Vec| { let response_str = std::str::from_utf8(response_data.as_slice())?; @@ -92,7 +92,8 @@ impl IpfsViaDaemon { } async fn poll_ipfs_ready(&mut self) -> bool{ let args = HashMap::new(); - let cmd = CmdOptions::new("config/show", &args); + let addr = HttpRequest::get_ipfs_addr() + "/config/show"; + let cmd = HttpRequest::new(&addr, &args); let response = self.http.send_request(&cmd).await; return match response { Ok(_) => true, @@ -106,14 +107,15 @@ impl IpfsViaDaemon { let args = HashMap::from([ ("arg", peer_id) ]); - let cmd_options = CmdOptions::new(cmd, &args); + let addr = HttpRequest::get_ipfs_addr()+cmd; + let cmd_options = HttpRequest::new(&addr, &args); let result_data = self.send_request(&cmd_options).await?; let result_str =std::str::from_utf8(result_data.as_slice())?; let result_json:Value = match serde_json::from_str(result_str){ Ok(x) => x, Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) }; - let peer_list = match value_to_vec::(&result_json, "Strings"){ + let peer_list = match json::value_to_vec::(&result_json, "Strings"){ Ok(peers) => { for peer in peers.iter() { if !peer.contains("success"){ @@ -130,46 +132,88 @@ impl IpfsViaDaemon { } #[async_trait] impl Ipfs for IpfsViaDaemon { - async fn add_file(&mut self, name:&str, file_name:&str, path:&str, contents:Vec) -> Result { - let cmd = "add"; + async fn add_file(&mut self, path:&str) -> Result { + let name = format!("\"{}\"", file_management::get_name_from_path(path, false)); + let cmd = HttpRequest::get_ipfs_addr()+ "/add"; let args = HashMap::from([ ("quieter", "true"), - ("cid-version", "1") + ("cid-version", "1"), + ("path", &path) ]); - let disposition = format!("form-data; name=\"{}\"; filename=\"{}\"", name, file_name); let headers = HashMap::from([ - ("Content-Type", "application/octet-stream"), - ("Content-Disposition", &disposition) + // ("Content-Disposition", "form-data"), + ("name", &name as &str), + ("filename", &path), + ("path", &path) ]); - let cmd_options = CmdOptions::new(cmd, &args).to_post(&headers, contents.as_slice()); + let mut cmd_options = HttpRequest::new(&cmd, &args); + let contents = std::fs::read(path)?; + cmd_options.add_part(&headers, "application/octet-stream", contents.as_slice()); let result_data = self.send_request(&cmd_options).await?; let result = std::str::from_utf8(result_data.as_slice())?.to_string(); return anyhow::Ok(result); } async fn add_directory(&mut self, path:&str) -> Result { - for entry in WalkDir::new(path) { - print!("{}", std::fs::read_to_string(entry?.path())?) + let cmd = HttpRequest::get_ipfs_addr()+ "/add"; + let args = HashMap::from([ + ("quieter", "true"), + ("cid-version", "1") + ]); + let mut request = HttpRequest::new(&cmd, &args); + println!("{}", "Adding the following directories..".blue()); + + let dirs = file_management::get_dirs_in(path)?; + for dir in dirs{ + let name = format!("\"{}\"", file_management::get_name_from_path(path, true)); + let headers = HashMap::from([ + ("Content-Disposition", " form-data: name=\"files\""), + ("filename", &name) + ]); + request.add_part(&headers, "application/x-directory", &[]); + println!("{}", dir.blue()); } - anyhow::Ok("Done".to_string()) + + println!("{}", "Adding the following files..".blue()); + let files = file_management::get_files_in(path)?; + + for (file_path, data) in files { + let name = format!("\"{}\"", file_management::get_name_from_path(path, true)); + let headers = HashMap::from([ + ("Content-Disposition", " form-data: name=\"files\""), + ("filename", &file_path) + ]); + request.add_part(&headers, "application/octet-stream", data.as_slice()); + println!("{}", file_path.blue()); + + } + let response_data = self.send_request(&request).await?; + let response = std::str::from_utf8(response_data.as_slice())?.to_string(); + anyhow::Ok(response) } async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { - self.swarm_or_bootstrap_cmd("bootstrap/add", peer_id).await + self.swarm_or_bootstrap_cmd("/bootstrap/add", peer_id).await } async fn connect_to(&mut self, peer_id:&str) -> Result> { - let response = self.swarm_or_bootstrap_cmd("swarm/connect", peer_id).await?; + let response = self.swarm_or_bootstrap_cmd("/swarm/connect", peer_id).await?; self.connected_peers.push(peer_id.to_string()); - print!("Connected Peers: "); - self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); + // print!("Connected Peers: "); + // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); anyhow::Ok(response) } async fn disconect_from(&mut self, peer_id:&str)-> Result> { - let response = self.swarm_or_bootstrap_cmd("swarm/disconnect", peer_id).await?; - self.connected_peers.iter_mut() - .filter(|peer_id_to_check| (peer_id_to_check.to_string() != peer_id.to_string())); + let response = self.swarm_or_bootstrap_cmd("/swarm/disconnect", peer_id).await?; + self.connected_peers = self.connected_peers.iter() + .filter_map(|peer_id_to_check| { + let checkable = peer_id_to_check.to_string(); + match peer_id != checkable{ + true => Some(checkable), + false => None + } + }).collect(); print!("Connected Peers: "); self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); anyhow::Ok(response) @@ -187,16 +231,13 @@ impl Ipfs for IpfsViaDaemon { false => "false" }; let args = HashMap::from([ - ("arg".to_string(), setting.to_string()), - ("arg".to_string(), value.to_string()), - ("bool".to_string(), is_bool.to_string()), - ("json".to_string(), is_json.to_string()) + ("bool", is_bool), + ("json", is_json), + ("arg", &setting), + ("arg", &value) ]); - let cmd_options = CmdOptions{ - cmd:"config".to_string(), - post_options:None, - args - }; + let addr = HttpRequest::get_ipfs_addr()+"config"; + let cmd_options = HttpRequest::new(&addr, &args); self.send_request(&cmd_options).await?; } anyhow::Ok(()) @@ -205,33 +246,15 @@ impl Ipfs for IpfsViaDaemon { impl Drop for IpfsViaDaemon { fn drop(&mut self) { for peer in self.connected_peers.clone(){ - block_on(self.disconect_from(&peer)); + match block_on(self.disconect_from(&peer)){ + Ok(_) => (), + Err(e) => println!("{}\n{}", "Ipfs was unable to properly disconect from peers before closing".red(), e) + }; } self.ipfs_process.kill().unwrap(); println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } } -//TODO: This needs to be move to utils -fn value_to_vec(json:&Value, index:&str) -> Result> - where A:Clone + for<'de> serde::Deserialize<'de>{ - anyhow::Ok( match json.get(index) { - Some(list_json) => { - match list_json.as_array() { - Some(list) => { - list.iter().map(|item_json| { - let item:A = match serde_json::from_value(item_json.clone()){ - Ok(x) => x, - Err(_) => panic!("Improperly formatted Json: cannot format type") - }; - item - }).collect() - }, - None => panic!("Improperly formatted Json: Not an Array") - } - }, - None => bail!("Improperly formatted Json: Cant locate index {}", index) - }) -} #[cfg(test)] mod tests { @@ -266,11 +289,11 @@ mod tests { } - #[test] - fn can_connect(){ - connect_to_peers(); - assert!(true); - } + // #[test] + // fn can_connect(){ + // connect_to_peers(); + // assert!(true); + // } // proptest! { // #[test] // #[serial] @@ -284,7 +307,16 @@ mod tests { fn can_add_directory(){ let testdir = "./test-dir"; let mut ipfs = connect_to_peers(); - block_on(ipfs.add_directory(testdir)).unwrap(); + let res = block_on(ipfs.add_directory(testdir)).unwrap(); + println!("Server responded with:\n {}", res.green()); assert!(true); } + // #[test] + // fn can_add_file(){ + // let test_file = "./test-dir/more/fission_logo.png"; + // let mut ipfs = connect_to_peers(); + // let res = block_on(ipfs.add_file(test_file)).unwrap(); + // println!("Server responded with:\n {}", res.green()); + // assert!(true); + // } } \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index 36adb1a..05422a6 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -1,15 +1,64 @@ -use std::time::Duration; +use std::{ + time::Duration, + collections::HashMap, + io::Write +}; use bytes::Bytes; - use colored::Colorize; use anyhow::Result; use tokio::runtime::Runtime; -use reqwest::Client; -use super::options::{CmdOptions, IPFS_RETRY_ATTEMPTS}; +use hyper::{ + Client, Body, Method, Request, + client::HttpConnector, + body::HttpBody +}; +use crate::utils::math; + +use super::options::*; + + +pub struct PostOptions { + pub headers:HashMap, + pub mime_type: String, + pub body: Vec +} +pub struct HttpRequest { + pub addr: String, + pub args: HashMap, + post_options: Vec +} +impl HttpRequest { + pub fn new(addr: &str, args: &HashMap<&str, &str>) -> Self{ + let owned_args:HashMap = args.iter() + .map(|(key, val)| (key.to_string(), val.to_string())) + .collect(); + Self { addr:addr.to_string(), args:owned_args, post_options: vec![] } + } + pub fn add_part(&mut self, headers: &HashMap<&str, &str>, mime_type:&str, body: &[u8]){ + let owned_body = body.to_vec(); + let owned_headers:HashMap = headers.iter() + .map(|(key, val)| (key.to_string(), val.to_string())) + .collect(); + self.post_options.push(PostOptions { headers: owned_headers, mime_type:mime_type.to_string(), body: owned_body }); + } + pub fn get_url(&self) -> String { + let mut arg_str:String = self.args.iter() + .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) + .collect(); + arg_str.pop(); + return match arg_str.len() == 0{ + true => self.addr.to_owned(), + false => format!("{}?{}", self.addr, arg_str) + } + } + pub fn get_ipfs_addr() -> String { + format!("http://{}:{}/api/v0", IPFS_ADDR, IPFS_API_PORT) + } +} pub struct HttpHandler{ - http_client:Client, + http_client:Client, tokio:Runtime } impl HttpHandler { @@ -22,33 +71,72 @@ impl HttpHandler { }; } - pub async fn send_request(&mut self, options:&CmdOptions) -> Result>{ + pub async fn send_request(&mut self, options:&HttpRequest) -> Result>{ let request_url = options.get_url(); - let body = match &options.post_options { - Some(post_options) => Bytes::copy_from_slice(post_options.body.as_slice()), - None => Bytes::new() + println!("{}", (format!("sending get or post request to \"{}\"", request_url).blue())); + let mut request_builder = Request::builder() + .method(Method::POST) + .uri(request_url); + let request = match options.post_options.len() { + 0 | 1 => { + for post in options.post_options.iter(){ + for (header_key, header_val) in post.headers.iter(){ + request_builder = request_builder.header(header_key, header_val) + } + } + match options.post_options.get(0) { + Some(options) => { + let data = options.body.clone(); + request_builder + .header("Content-Type", options.mime_type.to_string()) + .body(Body::from(data))? + }, + None => request_builder.body(Body::from(Bytes::new()))? + } + } + _ => { + let mut body_parts = vec![]; + for post_options in &options.post_options { + write!(body_parts, "--{}\r\n", HTTP_BOUNDARY)?; + for (header_prop, header_val) in &post_options.headers { + write!(body_parts, "{}:{}; ", header_prop, header_val)?; + } + let data_text = unsafe { + //TODO: find a way to do this safely + std::str::from_utf8_unchecked(post_options.body.as_slice()) + }; + write!(body_parts, "\r\nContent-Type: {}\r\n", post_options.mime_type)?; + write!(body_parts, "\r\n{}", data_text)?; + } + write!(body_parts, "--{}--\r\n", HTTP_BOUNDARY)?; + request_builder + .header("Content-Type", &*format!("multipart/form-data; boundary={}", HTTP_BOUNDARY)) + .body(Body::from(body_parts))? + } }; - println!("{}", (format!("sending get or post request to \"{}\"", request_url).green())); - let response = self.tokio.block_on(async { - self.http_client - .post(request_url) - .body(body) - .send().await + let mut response = self.tokio.block_on(async { + self.http_client.request(request).await })?; - let response_bytes = response.bytes().await?; + let mut response_data: Vec = vec![]; + while let Some(chunk) = response.body_mut().data().await { + for byte in chunk? { + response_data.push(byte); + } + } println!("response recieved"); - anyhow::Ok(response_bytes.into()) + anyhow::Ok(response_data) + } - pub async fn try_send_request(&mut self, options:&CmdOptions, handler_option:Option) -> Result> + pub async fn try_send_request(&mut self, options:&HttpRequest, handler_option:Option) -> Result> where F: Fn(Vec) -> Result{ - let mut attempt:u16 = 0; + let mut attempt:u32 = 0; 'attempt_loop: loop { attempt += 1; if attempt != 1 { - std::thread::sleep(Duration::new(get_fibinaci(attempt), 0)) + std::thread::sleep(Duration::new(math::get_fibinaci(attempt), 0)) } println!("attempting to send post request: attempt {} of {}", attempt, IPFS_RETRY_ATTEMPTS); - let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS; + let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS as u32; let response_result = self.send_request(options).await; let response = match is_final_attempt { true => response_result?, @@ -72,10 +160,3 @@ impl HttpHandler { } } - -fn get_fibinaci(n:u16) -> u64{ - let phi:f64 = fixed::consts::PHI.to_num(); - let numerator:f64 = phi.powi(n as i32)-((-phi).powi(n as i32)); - let denominator:f64 = f64::sqrt(5 as f64); - return (numerator/denominator).round() as u64; -} \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index aa18abc..e902041 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -1,46 +1,8 @@ -use std::collections::HashMap; - pub const IPFS_API_PORT:u16 = 4867; pub const IPFS_HTTP_PORT:u16 = 5742; pub const IPFS_RETRY_ATTEMPTS:u16 = 7; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; +pub const HTTP_BOUNDARY:&str = "------------------------I_am_a_boundary_123A123"; pub const BOOT_TIME_OUT:u16 = 120;//In seconds -pub const SLEEP_LENGTH:u8 = 1;//In seconds - -pub struct PostOptions { - pub headers:HashMap, - pub body: Vec -} -pub struct CmdOptions { - pub cmd: String, - pub args: HashMap, - pub post_options: Option -} -impl CmdOptions { - pub fn new(cmd: &str, args: &HashMap<&str, &str>) -> Self{ - let owned_args:HashMap = args.iter() - .map(|(key, val)| (key.to_string(), val.to_string())) - .collect(); - Self { cmd:cmd.to_string(), args:owned_args, post_options: None } - } - pub fn to_post(mut self, headers: &HashMap<&str, &str>, body: &[u8]) -> Self{ - let owned_body = body.to_vec(); - let owned_headers:HashMap = headers.iter() - .map(|(key, val)| (key.to_string(), val.to_string())) - .collect(); - self.post_options = Some(PostOptions { headers: owned_headers, body: owned_body }); - return self; - } - pub fn get_url(&self) -> String { - let mut arg_str:String = self.args.iter() - .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) - .collect(); - arg_str.pop(); - let url = format!("http://{}:{}/api/v0/{}", IPFS_ADDR, IPFS_API_PORT, self.cmd); - return match arg_str.len() == 0{ - true => url, - false => format!("{}?{}", url, arg_str) - } - } -} \ No newline at end of file +pub const SLEEP_LENGTH:u8 = 1;//In seconds \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 2b62138..4f46bb6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,3 +2,4 @@ pub mod cmd; pub mod legacy; pub mod utils; pub mod ipfs; +pub mod utils; diff --git a/src/utils.rs b/src/utils.rs index 7cd3105..d66ed79 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,7 @@ +pub mod file_management; +pub mod json; +pub mod math; + use anyhow::{anyhow, Result}; use std::io::{self, Write}; use std::process::Output; diff --git a/src/utils/file_management.rs b/src/utils/file_management.rs new file mode 100644 index 0000000..dc39637 --- /dev/null +++ b/src/utils/file_management.rs @@ -0,0 +1,69 @@ + +use walkdir::WalkDir; +use std::collections::HashMap; +use anyhow::{Result, bail}; +use colored::Colorize; + +//TODO: This needs to move to utils +pub fn get_files_in(dir:&str) -> Result>> { + let mut files = HashMap::new(); + for entry_result in WalkDir::new(dir) { + let entry = match entry_result { + Ok(x) => x, + Err(e) => bail!("{}\n{}", "failled to get item in directory, failed with error:".red(), e) + }; + if entry.path().is_file() { + let file_data = match std::fs::read(entry.path()) { + Ok(x) => x, + Err(e) => bail!("{}\n{}", "failed to read file in directory into a byte vector, failed with error:".red(), e) + }; + let path = match entry.path().to_str() { + Some(x) => x, + None => bail!("failed to get path as string a file") + }.to_string(); + files.insert(path, file_data); + } + } + return anyhow::Ok(files); +} +//TODO: This needs to move to utils +pub fn get_dirs_in(root:&str) -> Result> { + let mut dirs = vec![]; + for entry_result in WalkDir::new(root) { + let entry = match entry_result { + Ok(x) => x, + Err(e) => bail!("{}\n{}", "failled to get item in directory, failed with error:".red(), e) + }; + if entry.path().is_dir() { + let path = match entry.path().to_str() { + Some(x) => x, + None => bail!("failed to get path as string a file") + }.to_string(); + dirs.push(path); + } + } + return anyhow::Ok(dirs); +} +//TODO: This needs to move to utils +pub fn get_name_from_path(path:&str, include_extention:bool) -> String{ + let file_name = path + .split("/") + .filter(|seg|!seg.is_empty()) + .last() + .unwrap(); + if !include_extention{ + let dot_parts = file_name.split(".").map(|s|s.to_string()); + return match dot_parts.clone().count() { + 1 => dot_parts.collect::>()[0].to_owned(), //this handles the case in-which there is no file extention + _ => { + //This collects all but the last segment into a single string + dot_parts.fold([String::new(), String::new()], |accum, current| { + [format!("{}.{}", accum[0], accum[1]), current.to_string()] + })[0].to_owned() + } + } + + }else { + return file_name.to_string(); + } +} \ No newline at end of file diff --git a/src/utils/json.rs b/src/utils/json.rs new file mode 100644 index 0000000..c2f94f8 --- /dev/null +++ b/src/utils/json.rs @@ -0,0 +1,30 @@ +/* +Ipfs often returns json with a single property with the value being an array. +This function simply takes the array in that property and turns it into a vector that can be used in rust. +It will return an error result if the json is not formatted in this way. +*/ + +use serde_json::Value; +use anyhow::{Result, bail}; + +pub fn value_to_vec(json:&Value, index:&str) -> Result> + where A:Clone + for<'de> serde::Deserialize<'de>{ + anyhow::Ok( match json.get(index) { + Some(list_json) => { + match list_json.as_array() { + Some(list) => { + let mut result_list:Vec = vec![]; + for item_json in list { + result_list.push(match serde_json::from_value(item_json.clone()){ + Ok(x) => x, + Err(_) => bail!("Improperly formatted Json: cannot format value {} in index {} to specified type", item_json, index) + }); + } + result_list + }, + None => bail!("Improperly formatted Json: Value at index {} is not an Array", index) + } + }, + None => bail!("Improperly formatted Json: Cant locate index {}", index) + }) +} \ No newline at end of file diff --git a/src/utils/math.rs b/src/utils/math.rs new file mode 100644 index 0000000..2f3f8e0 --- /dev/null +++ b/src/utils/math.rs @@ -0,0 +1,6 @@ +pub fn get_fibinaci(n:u32) -> u64{ + if n <= 1 { + return n as u64; + } + return get_fibinaci(n - 1) + get_fibinaci(n - 2); +} \ No newline at end of file diff --git a/test-dir/more/fission_logo.png b/test-dir/more/fission_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..7261ccb8a524c9b9c38fe5789d92609cc57454a7 GIT binary patch literal 31609 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 Mv--8%)GhA+0XalX00000 literal 0 HcmV?d00001 diff --git a/test-dir/text.txt b/test-dir/test.txt similarity index 100% rename from test-dir/text.txt rename to test-dir/test.txt From d27be6056d04c447e553f83f0d662dcf8d90389f Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 19:47:49 -0600 Subject: [PATCH 25/63] files upload to ipfs finnally --- src/ipfs/daemon.rs | 69 +++++++++++++++++++++++------------- src/ipfs/http.rs | 48 +++++++++++++------------ src/utils/file_management.rs | 25 +------------ 3 files changed, 71 insertions(+), 71 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index fa9b5d3..6d6c18d 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -93,7 +93,7 @@ impl IpfsViaDaemon { async fn poll_ipfs_ready(&mut self) -> bool{ let args = HashMap::new(); let addr = HttpRequest::get_ipfs_addr() + "/config/show"; - let cmd = HttpRequest::new(&addr, &args); + let cmd = HttpRequest::new(&addr, &args, false); let response = self.http.send_request(&cmd).await; return match response { Ok(_) => true, @@ -103,12 +103,13 @@ impl IpfsViaDaemon { } }; } + //TODO: Better name? async fn swarm_or_bootstrap_cmd(&mut self, cmd:&str, peer_id:&str) -> Result>{ let args = HashMap::from([ ("arg", peer_id) ]); let addr = HttpRequest::get_ipfs_addr()+cmd; - let cmd_options = HttpRequest::new(&addr, &args); + let cmd_options = HttpRequest::new(&addr, &args, false); let result_data = self.send_request(&cmd_options).await?; let result_str =std::str::from_utf8(result_data.as_slice())?; let result_json:Value = match serde_json::from_str(result_str){ @@ -133,22 +134,20 @@ impl IpfsViaDaemon { #[async_trait] impl Ipfs for IpfsViaDaemon { async fn add_file(&mut self, path:&str) -> Result { - let name = format!("\"{}\"", file_management::get_name_from_path(path, false)); let cmd = HttpRequest::get_ipfs_addr()+ "/add"; let args = HashMap::from([ ("quieter", "true"), ("cid-version", "1"), ("path", &path) ]); + let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &path); let headers = HashMap::from([ - // ("Content-Disposition", "form-data"), - ("name", &name as &str), - ("filename", &path), - ("path", &path) + ("Content-Disposition", &disposition as &str), + ("Content-Type", "application/octet-stream") ]); - let mut cmd_options = HttpRequest::new(&cmd, &args); + let mut cmd_options = HttpRequest::new(&cmd, &args, true); let contents = std::fs::read(path)?; - cmd_options.add_part(&headers, "application/octet-stream", contents.as_slice()); + cmd_options.add_body(&headers, contents.as_slice()); let result_data = self.send_request(&cmd_options).await?; let result = std::str::from_utf8(result_data.as_slice())?.to_string(); return anyhow::Ok(result); @@ -160,17 +159,17 @@ impl Ipfs for IpfsViaDaemon { ("quieter", "true"), ("cid-version", "1") ]); - let mut request = HttpRequest::new(&cmd, &args); + let mut request = HttpRequest::new(&cmd, &args, true); println!("{}", "Adding the following directories..".blue()); let dirs = file_management::get_dirs_in(path)?; for dir in dirs{ - let name = format!("\"{}\"", file_management::get_name_from_path(path, true)); + let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &dir); let headers = HashMap::from([ - ("Content-Disposition", " form-data: name=\"files\""), - ("filename", &name) + ("Content-Disposition", &disposition as &str), + ("Content-Type", "application/x-directory") ]); - request.add_part(&headers, "application/x-directory", &[]); + request.add_body(&headers, &[]); println!("{}", dir.blue()); } @@ -178,12 +177,12 @@ impl Ipfs for IpfsViaDaemon { let files = file_management::get_files_in(path)?; for (file_path, data) in files { - let name = format!("\"{}\"", file_management::get_name_from_path(path, true)); + let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &file_path); let headers = HashMap::from([ - ("Content-Disposition", " form-data: name=\"files\""), - ("filename", &file_path) + ("Content-Disposition", &disposition as &str), + ("Content-Type", "application/octet-stream") ]); - request.add_part(&headers, "application/octet-stream", data.as_slice()); + request.add_body(&headers, data.as_slice()); println!("{}", file_path.blue()); } @@ -237,7 +236,7 @@ impl Ipfs for IpfsViaDaemon { ("arg", &value) ]); let addr = HttpRequest::get_ipfs_addr()+"config"; - let cmd_options = HttpRequest::new(&addr, &args); + let cmd_options = HttpRequest::new(&addr, &args, false); self.send_request(&cmd_options).await?; } anyhow::Ok(()) @@ -259,8 +258,9 @@ impl Drop for IpfsViaDaemon { #[cfg(test)] mod tests { use futures::executor::block_on; - use anyhow::Result; - use proptest::prelude::*; + use crate::utils::file_management; + // use anyhow::Result; + // use proptest::prelude::*; use super::*; //TODO: Setup pizza @@ -305,11 +305,32 @@ mod tests { // } #[test] fn can_add_directory(){ - let testdir = "./test-dir"; + let test_dir = "./test-dir"; let mut ipfs = connect_to_peers(); - let res = block_on(ipfs.add_directory(testdir)).unwrap(); + let res = block_on(ipfs.add_directory(test_dir)).unwrap(); println!("Server responded with:\n {}", res.green()); - assert!(true); + + let files = file_management::get_files_in(test_dir).unwrap(); + let folders = file_management::get_dirs_in(test_dir).unwrap(); + + files.iter() + .map(|(path, _)| path) + .chain(folders.iter()) + .for_each(|path| { + //This removes the "./" at the begginning of paths as the ipfs server responds without them + let fixed_path:String = path + .split("/") + .enumerate() + .filter_map(|(i, seg)| { + match i { + 0 => None, + 1 => Some(seg.to_string()), + _ => Some("/".to_string() + seg) + } + }).collect(); + println!("checking if response contains path {}", fixed_path); + assert!(res.contains(&fixed_path)); + }); } // #[test] // fn can_add_file(){ diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index 05422a6..bf42a43 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -20,27 +20,28 @@ use super::options::*; pub struct PostOptions { pub headers:HashMap, - pub mime_type: String, pub body: Vec } pub struct HttpRequest { pub addr: String, pub args: HashMap, - post_options: Vec + pub is_multipart:bool, + post_options: Vec//TODO: Better name? } impl HttpRequest { - pub fn new(addr: &str, args: &HashMap<&str, &str>) -> Self{ + pub fn new(addr: &str, args: &HashMap<&str, &str>, is_multipart:bool) -> Self{ let owned_args:HashMap = args.iter() .map(|(key, val)| (key.to_string(), val.to_string())) .collect(); - Self { addr:addr.to_string(), args:owned_args, post_options: vec![] } + Self { addr:addr.to_string(), args:owned_args, post_options: vec![], is_multipart } } - pub fn add_part(&mut self, headers: &HashMap<&str, &str>, mime_type:&str, body: &[u8]){ + //TODO: Better name? + pub fn add_body(&mut self, headers: &HashMap<&str, &str>, body: &[u8]){ let owned_body = body.to_vec(); let owned_headers:HashMap = headers.iter() .map(|(key, val)| (key.to_string(), val.to_string())) .collect(); - self.post_options.push(PostOptions { headers: owned_headers, mime_type:mime_type.to_string(), body: owned_body }); + self.post_options.push(PostOptions { headers: owned_headers, body: owned_body }); } pub fn get_url(&self) -> String { let mut arg_str:String = self.args.iter() @@ -77,41 +78,42 @@ impl HttpHandler { let mut request_builder = Request::builder() .method(Method::POST) .uri(request_url); - let request = match options.post_options.len() { - 0 | 1 => { - for post in options.post_options.iter(){ - for (header_key, header_val) in post.headers.iter(){ - request_builder = request_builder.header(header_key, header_val) - } - } + let request = match options.is_multipart { + false => { match options.post_options.get(0) { Some(options) => { + for (header_key, header_val) in options.headers.iter(){ + request_builder = request_builder.header(header_key, header_val) + } + let data = options.body.clone(); - request_builder - .header("Content-Type", options.mime_type.to_string()) - .body(Body::from(data))? + request_builder.body(Body::from(data))? }, None => request_builder.body(Body::from(Bytes::new()))? } } - _ => { + true => { let mut body_parts = vec![]; for post_options in &options.post_options { write!(body_parts, "--{}\r\n", HTTP_BOUNDARY)?; for (header_prop, header_val) in &post_options.headers { - write!(body_parts, "{}:{}; ", header_prop, header_val)?; + write!(body_parts, "{}: {}\r\n", header_prop, header_val)?; } let data_text = unsafe { //TODO: find a way to do this safely std::str::from_utf8_unchecked(post_options.body.as_slice()) }; - write!(body_parts, "\r\nContent-Type: {}\r\n", post_options.mime_type)?; - write!(body_parts, "\r\n{}", data_text)?; + write!(body_parts, "\r\n{}\r\n", data_text)?; } write!(body_parts, "--{}--\r\n", HTTP_BOUNDARY)?; - request_builder - .header("Content-Type", &*format!("multipart/form-data; boundary={}", HTTP_BOUNDARY)) - .body(Body::from(body_parts))? + match options.post_options.len() { + 0 => request_builder.body(Body::from(Bytes::new()))?, + _ => { + request_builder + .header("Content-Type", &*format!("multipart/form-data; boundary=\"{}\"", HTTP_BOUNDARY)) + .body(Body::from(body_parts))? + } + } } }; let mut response = self.tokio.block_on(async { diff --git a/src/utils/file_management.rs b/src/utils/file_management.rs index dc39637..d8aad66 100644 --- a/src/utils/file_management.rs +++ b/src/utils/file_management.rs @@ -26,7 +26,7 @@ pub fn get_files_in(dir:&str) -> Result>> { } return anyhow::Ok(files); } -//TODO: This needs to move to utils + pub fn get_dirs_in(root:&str) -> Result> { let mut dirs = vec![]; for entry_result in WalkDir::new(root) { @@ -43,27 +43,4 @@ pub fn get_dirs_in(root:&str) -> Result> { } } return anyhow::Ok(dirs); -} -//TODO: This needs to move to utils -pub fn get_name_from_path(path:&str, include_extention:bool) -> String{ - let file_name = path - .split("/") - .filter(|seg|!seg.is_empty()) - .last() - .unwrap(); - if !include_extention{ - let dot_parts = file_name.split(".").map(|s|s.to_string()); - return match dot_parts.clone().count() { - 1 => dot_parts.collect::>()[0].to_owned(), //this handles the case in-which there is no file extention - _ => { - //This collects all but the last segment into a single string - dot_parts.fold([String::new(), String::new()], |accum, current| { - [format!("{}.{}", accum[0], accum[1]), current.to_string()] - })[0].to_owned() - } - } - - }else { - return file_name.to_string(); - } } \ No newline at end of file From 1660c8aa87f8f99022dea777d6847f1fe8ddac22 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 20:15:42 -0600 Subject: [PATCH 26/63] removing auto disconnect for now --- src/ipfs/daemon.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 6d6c18d..19ad6bc 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -120,7 +120,7 @@ impl IpfsViaDaemon { Ok(peers) => { for peer in peers.iter() { if !peer.contains("success"){ - bail!("The following peer did not successfully connect: {}", peer) + bail!("The following peer did not successfully connect or disconnect: {}", peer) } } peers @@ -244,12 +244,12 @@ impl Ipfs for IpfsViaDaemon { } impl Drop for IpfsViaDaemon { fn drop(&mut self) { - for peer in self.connected_peers.clone(){ - match block_on(self.disconect_from(&peer)){ - Ok(_) => (), - Err(e) => println!("{}\n{}", "Ipfs was unable to properly disconect from peers before closing".red(), e) - }; - } + // for peer in self.connected_peers.clone(){ + // match block_on(self.disconect_from(&peer)){ + // Ok(_) => (), + // Err(e) => println!("{}\n{}", "Ipfs was unable to properly disconect from peers before closing".red(), e) + // }; + // } self.ipfs_process.kill().unwrap(); println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } @@ -283,10 +283,12 @@ mod tests { fn connect_to_peers() -> IpfsViaDaemon{ let mut ipfs = IpfsViaDaemon::new().unwrap(); for peer in PEER_ADDRS { - block_on(ipfs.connect_to(peer)).unwrap(); + let result_peers = block_on(ipfs.connect_to(peer)).unwrap() ; + for result_peer in result_peers { + println!("Connected to peer! {}", result_peer); + } } - ipfs - + return ipfs; } // #[test] From 5928dde82e5e3b7dc2599ec602db001cb1c372c0 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 20:16:28 -0600 Subject: [PATCH 27/63] oops --- src/ipfs/daemon.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 19ad6bc..3d11323 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,7 +1,6 @@ use crate::ipfs::Ipfs; use crate::utils::*; use anyhow::{Result, bail}; -use futures::executor::block_on; use super::http::HttpRequest; use super::options::*; use serde_json::Value; From 6034492c1c6c4d6c63083cc242eb83b23ee7d63b Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 28 Nov 2022 20:45:49 -0600 Subject: [PATCH 28/63] testing add file --- Cargo.lock | 48 +++++++++++++-- Cargo.toml | 3 +- src/ipfs/daemon.rs | 57 +++++------------- src/ipfs/options.rs | 5 +- test-dir/{more => more-tests}/also-test.txt | 0 test-dir/more-tests/even more/noper.nope | 1 + .../{more => more-tests}/fission_logo.png | Bin 7 files changed, 64 insertions(+), 50 deletions(-) rename test-dir/{more => more-tests}/also-test.txt (100%) create mode 100644 test-dir/more-tests/even more/noper.nope rename test-dir/{more => more-tests}/fission_logo.png (100%) diff --git a/Cargo.lock b/Cargo.lock index 7085ab5..ad497c1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -345,6 +345,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "dashmap" +version = "5.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "der" version = "0.4.5" @@ -505,6 +518,7 @@ dependencies = [ "proptest", "serde", "serde_json", + "serial_test", "tokio", "walkdir", ] @@ -707,9 +721,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "607c8a29735385251a339424dd462993c0fed8fa09d378f259377df08c126022" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "heapless" @@ -1005,9 +1019,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.13.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" [[package]] name = "opaque-debug" @@ -1435,6 +1449,32 @@ dependencies = [ "serde", ] +[[package]] +name = "serial_test" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92761393ee4dc3ff8f4af487bd58f4307c9329bbedea02cac0089ad9c411e153" +dependencies = [ + "dashmap", + "futures", + "lazy_static", + "log", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b6f5d1c3087fb119617cff2966fe3808a80e5eb59a8c1601d5994d66f4346a5" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "sha2" version = "0.9.9" diff --git a/Cargo.toml b/Cargo.toml index 9875754..10a88d8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,4 +23,5 @@ futures = "0.3.25" walkdir = "2.3.2" [dev-dependencies] -proptest = "1.0.0" \ No newline at end of file +proptest = "1.0.0" +serial_test = "0.9.0" \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 3d11323..a988f83 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -20,10 +20,11 @@ pub struct IpfsViaDaemon { } impl IpfsViaDaemon { pub fn new() -> Result { - println!("{}", "Configuring ipfs...".green()); - IpfsViaDaemon::configure()?; println!("{}", "Starting ipfs...".green()); + let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); let proccess = Command::new(IPFS_EXE) + .arg("--api") + .arg(&api_addr) .arg("daemon") .spawn()?; println!("{}", ("⚠️ Warning: Ipfs Proccess Started. Please do NOT force close this app⚠️".yellow())); @@ -34,31 +35,6 @@ impl IpfsViaDaemon { connected_peers: vec![] }) } - fn configure() -> Result<()>{ - //This sets the API's address - //let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); - let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); - let http_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_HTTP_PORT); - //let http_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_HTTP_PORT); - IpfsViaDaemon::config_option("Addresses.API", &api_addr)?; - IpfsViaDaemon::config_option("Addresses.Gateway", &http_addr)?; - anyhow::Ok(()) - } - fn config_option(option:&str, value:&str)-> Result<()>{ - let cmd_str = format!("ipfs {} Addresses.API {}", option, value); - println!("running cmd \"{}\"", cmd_str.blue()); - let is_addr_set = Command::new(IPFS_EXE) - .arg("config") - .arg(option) - .arg(value) - .spawn()? - .wait()? - .success(); - if !is_addr_set { - bail!("Attempted to set the api address, but failed!"); - } - anyhow::Ok(()) - } async fn send_request(&mut self, options:&HttpRequest) -> Result>{ self.await_ready().await?; let result = self.http.try_send_request(options, Some(|response_data:Vec| { @@ -243,12 +219,6 @@ impl Ipfs for IpfsViaDaemon { } impl Drop for IpfsViaDaemon { fn drop(&mut self) { - // for peer in self.connected_peers.clone(){ - // match block_on(self.disconect_from(&peer)){ - // Ok(_) => (), - // Err(e) => println!("{}\n{}", "Ipfs was unable to properly disconect from peers before closing".red(), e) - // }; - // } self.ipfs_process.kill().unwrap(); println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) } @@ -261,6 +231,7 @@ mod tests { // use anyhow::Result; // use proptest::prelude::*; use super::*; + use serial_test::serial; //TODO: Setup pizza const PEER_ADDRS:&'static [&'static str] = &[ @@ -305,8 +276,9 @@ mod tests { // } // } #[test] + #[serial] fn can_add_directory(){ - let test_dir = "./test-dir"; + let test_dir = "./test-dir/more-tests"; let mut ipfs = connect_to_peers(); let res = block_on(ipfs.add_directory(test_dir)).unwrap(); println!("Server responded with:\n {}", res.green()); @@ -333,12 +305,13 @@ mod tests { assert!(res.contains(&fixed_path)); }); } - // #[test] - // fn can_add_file(){ - // let test_file = "./test-dir/more/fission_logo.png"; - // let mut ipfs = connect_to_peers(); - // let res = block_on(ipfs.add_file(test_file)).unwrap(); - // println!("Server responded with:\n {}", res.green()); - // assert!(true); - // } + #[test] + #[serial] + fn can_add_file(){ + let test_file = "./test-dir/test.txt"; + let mut ipfs = connect_to_peers(); + let res = block_on(ipfs.add_file(test_file)).unwrap(); + println!("Server responded with:\n {}", res.green()); + assert!(true); + } } \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index e902041..c7b8943 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -1,8 +1,7 @@ -pub const IPFS_API_PORT:u16 = 4867; -pub const IPFS_HTTP_PORT:u16 = 5742; +pub const IPFS_API_PORT:u16 = 4869; pub const IPFS_RETRY_ATTEMPTS:u16 = 7; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const HTTP_BOUNDARY:&str = "------------------------I_am_a_boundary_123A123"; -pub const BOOT_TIME_OUT:u16 = 120;//In seconds +pub const BOOT_TIME_OUT:u16 = 45;//In seconds pub const SLEEP_LENGTH:u8 = 1;//In seconds \ No newline at end of file diff --git a/test-dir/more/also-test.txt b/test-dir/more-tests/also-test.txt similarity index 100% rename from test-dir/more/also-test.txt rename to test-dir/more-tests/also-test.txt diff --git a/test-dir/more-tests/even more/noper.nope b/test-dir/more-tests/even more/noper.nope new file mode 100644 index 0000000..06e94c7 --- /dev/null +++ b/test-dir/more-tests/even more/noper.nope @@ -0,0 +1 @@ +Nope Nope \ No newline at end of file diff --git a/test-dir/more/fission_logo.png b/test-dir/more-tests/fission_logo.png similarity index 100% rename from test-dir/more/fission_logo.png rename to test-dir/more-tests/fission_logo.png From a00f9d9a9f6016d11d0abfd3230bef98a5d772c0 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 29 Nov 2022 13:21:20 -0600 Subject: [PATCH 29/63] finnishing add file --- src/ipfs.rs | 4 +-- src/ipfs/daemon.rs | 85 +++++++++++++++++++++++++++++++--------------- 2 files changed, 60 insertions(+), 29 deletions(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index 3c3d78e..773d742 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -11,8 +11,8 @@ pub mod options; #[async_trait] pub trait Ipfs { - async fn add_file(&mut self, path:&str) -> Result; - async fn add_directory(&mut self, path:&str) -> Result; + async fn add_file(&mut self, path:&str) -> Result>; + async fn add_directory(&mut self, path:&str) -> Result>; async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; async fn connect_to(&mut self, peer_id:&str) -> Result>; async fn disconect_from(&mut self, peer_id:&str)-> Result>; diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index a988f83..9340323 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -105,10 +105,38 @@ impl IpfsViaDaemon { return anyhow::Ok(peer_list); } + fn response_to_hashes(response:&str) -> Result> { + let mut res = response.to_string(); + let mut ret = HashMap::new(); + return loop { + //get location to take segment to + let json_seg_end = match res.find("}") { + Some(seg_loc) => seg_loc, + None => break anyhow::Ok(ret) + }; + //get segment to convert to json and remove the segment from res + let res_vec = res.chars().collect::>(); + let json_seg = res_vec[..(json_seg_end+1)].iter().collect::(); + res = res_vec[(json_seg_end+1)..].iter().collect(); + //convert that segment to json and value + // println!("{}", res.yellow()); + // println!("{}", json_seg.blue()); + let json:Value = serde_json::from_str(&json_seg)?; + let path = match json.get("Name"){ + Some(val) => val.to_string(), + None => bail!("Could not find Name property in ipfs's response to an add") + }; + let hash = match json.get("Hash"){ + Some(val) => val.to_string(), + None => bail!("Could not find Hash property in ipfs's response to an add") + }; + ret.insert(path, hash); + }; + } } #[async_trait] impl Ipfs for IpfsViaDaemon { - async fn add_file(&mut self, path:&str) -> Result { + async fn add_file(&mut self, path:&str) -> Result> { let cmd = HttpRequest::get_ipfs_addr()+ "/add"; let args = HashMap::from([ ("quieter", "true"), @@ -124,11 +152,12 @@ impl Ipfs for IpfsViaDaemon { let contents = std::fs::read(path)?; cmd_options.add_body(&headers, contents.as_slice()); let result_data = self.send_request(&cmd_options).await?; - let result = std::str::from_utf8(result_data.as_slice())?.to_string(); - return anyhow::Ok(result); + let response = std::str::from_utf8(result_data.as_slice())?.to_string(); + let hashes = Self::response_to_hashes(&response)?; + anyhow::Ok(hashes) } - async fn add_directory(&mut self, path:&str) -> Result { + async fn add_directory(&mut self, path:&str) -> Result> { let cmd = HttpRequest::get_ipfs_addr()+ "/add"; let args = HashMap::from([ ("quieter", "true"), @@ -159,11 +188,11 @@ impl Ipfs for IpfsViaDaemon { ]); request.add_body(&headers, data.as_slice()); println!("{}", file_path.blue()); - } let response_data = self.send_request(&request).await?; let response = std::str::from_utf8(response_data.as_slice())?.to_string(); - anyhow::Ok(response) + let hashes = Self::response_to_hashes(&response)?; + anyhow::Ok(hashes) } async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { @@ -175,7 +204,7 @@ impl Ipfs for IpfsViaDaemon { self.connected_peers.push(peer_id.to_string()); // print!("Connected Peers: "); // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); - anyhow::Ok(response) + anyhow::Ok(self.connected_peers.clone()) } async fn disconect_from(&mut self, peer_id:&str)-> Result> { @@ -190,7 +219,7 @@ impl Ipfs for IpfsViaDaemon { }).collect(); print!("Connected Peers: "); self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); - anyhow::Ok(response) + anyhow::Ok(self.connected_peers.clone()) } async fn config(&mut self, options:HashMap) -> Result<()> { @@ -226,6 +255,8 @@ impl Drop for IpfsViaDaemon { #[cfg(test)] mod tests { + use std::hash; + use futures::executor::block_on; use crate::utils::file_management; // use anyhow::Result; @@ -280,8 +311,11 @@ mod tests { fn can_add_directory(){ let test_dir = "./test-dir/more-tests"; let mut ipfs = connect_to_peers(); - let res = block_on(ipfs.add_directory(test_dir)).unwrap(); - println!("Server responded with:\n {}", res.green()); + let hashes = block_on(ipfs.add_directory(test_dir)).unwrap(); + println!("{}","Finnished Hashes:".green()); + for (path, hash) in &hashes { + println!("{}: {}", path.green(), hash.blue()) + } let files = file_management::get_files_in(test_dir).unwrap(); let folders = file_management::get_dirs_in(test_dir).unwrap(); @@ -289,29 +323,26 @@ mod tests { files.iter() .map(|(path, _)| path) .chain(folders.iter()) - .for_each(|path| { - //This removes the "./" at the begginning of paths as the ipfs server responds without them - let fixed_path:String = path - .split("/") - .enumerate() - .filter_map(|(i, seg)| { - match i { - 0 => None, - 1 => Some(seg.to_string()), - _ => Some("/".to_string() + seg) - } - }).collect(); - println!("checking if response contains path {}", fixed_path); - assert!(res.contains(&fixed_path)); + .for_each(|path_to_match| { + assert!(hashes.iter().any(|(path, _)|path_to_match ==path)) }); + + } #[test] #[serial] fn can_add_file(){ let test_file = "./test-dir/test.txt"; let mut ipfs = connect_to_peers(); - let res = block_on(ipfs.add_file(test_file)).unwrap(); - println!("Server responded with:\n {}", res.green()); - assert!(true); + let hashes = block_on(ipfs.add_file(test_file)).unwrap(); + println!("{}","Finnished Hashes:\n".green()); + for (path, hash) in &hashes { + println!("{}: {}", path.green(), hash.blue()) + } + assert!(hashes.iter().any(|(path, _)|test_file ==path)); + } + #[test] + fn can_config(){ + } } \ No newline at end of file From 40c76ee6f10fe093971c8506fa10cc1d9cf8a988 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 29 Nov 2022 16:57:48 -0600 Subject: [PATCH 30/63] quick fix for file adding --- src/ipfs/daemon.rs | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 9340323..d870115 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -119,15 +119,13 @@ impl IpfsViaDaemon { let json_seg = res_vec[..(json_seg_end+1)].iter().collect::(); res = res_vec[(json_seg_end+1)..].iter().collect(); //convert that segment to json and value - // println!("{}", res.yellow()); - // println!("{}", json_seg.blue()); let json:Value = serde_json::from_str(&json_seg)?; let path = match json.get("Name"){ - Some(val) => val.to_string(), + Some(val) => "/".to_string() + &val.to_string().split("\"").collect::(), None => bail!("Could not find Name property in ipfs's response to an add") }; let hash = match json.get("Hash"){ - Some(val) => val.to_string(), + Some(val) => "/".to_string() + &val.to_string().split("\"").collect::(), None => bail!("Could not find Hash property in ipfs's response to an add") }; ret.insert(path, hash); @@ -200,7 +198,7 @@ impl Ipfs for IpfsViaDaemon { } async fn connect_to(&mut self, peer_id:&str) -> Result> { - let response = self.swarm_or_bootstrap_cmd("/swarm/connect", peer_id).await?; + self.swarm_or_bootstrap_cmd("/swarm/connect", peer_id).await?; self.connected_peers.push(peer_id.to_string()); // print!("Connected Peers: "); // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); @@ -208,7 +206,7 @@ impl Ipfs for IpfsViaDaemon { } async fn disconect_from(&mut self, peer_id:&str)-> Result> { - let response = self.swarm_or_bootstrap_cmd("/swarm/disconnect", peer_id).await?; + self.swarm_or_bootstrap_cmd("/swarm/disconnect", peer_id).await?; self.connected_peers = self.connected_peers.iter() .filter_map(|peer_id_to_check| { let checkable = peer_id_to_check.to_string(); @@ -324,7 +322,12 @@ mod tests { .map(|(path, _)| path) .chain(folders.iter()) .for_each(|path_to_match| { - assert!(hashes.iter().any(|(path, _)|path_to_match ==path)) + let fixed_path_to_match:String = path_to_match + .split("/") + .filter(|seg| seg != &"." && !seg.is_empty()) + .map(|seg| "/".to_string() + seg) + .collect(); + assert!(hashes.iter().any(|(path, _)|fixed_path_to_match == path.to_owned())) }); @@ -339,7 +342,13 @@ mod tests { for (path, hash) in &hashes { println!("{}: {}", path.green(), hash.blue()) } - assert!(hashes.iter().any(|(path, _)|test_file ==path)); + let matchable_path:String = test_file + .split("/") + .filter(|seg| seg != &"." && !seg.is_empty()) + .map(|seg| "/".to_string() + seg) + .collect(); + println!("{}", matchable_path.red()); + assert!(hashes.iter().any(|(path, _)|matchable_path == path.to_owned())); } #[test] fn can_config(){ From 69e43c6e29f1c6ae4a25a2827bcc7f9445bb9d24 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 29 Nov 2022 17:03:04 -0600 Subject: [PATCH 31/63] remove warnings --- src/ipfs/daemon.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index d870115..a762251 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -125,7 +125,7 @@ impl IpfsViaDaemon { None => bail!("Could not find Name property in ipfs's response to an add") }; let hash = match json.get("Hash"){ - Some(val) => "/".to_string() + &val.to_string().split("\"").collect::(), + Some(val) => val.to_string().split("\"").collect::(), None => bail!("Could not find Hash property in ipfs's response to an add") }; ret.insert(path, hash); @@ -253,8 +253,6 @@ impl Drop for IpfsViaDaemon { #[cfg(test)] mod tests { - use std::hash; - use futures::executor::block_on; use crate::utils::file_management; // use anyhow::Result; From d13c31be929cd42b3b67dbf0183f9190c9b9b97d Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 30 Nov 2022 21:18:20 -0600 Subject: [PATCH 32/63] fixing config --- src/ipfs.rs | 2 +- src/ipfs/daemon.rs | 88 +++++++++++++++++++++++++++------------------ src/ipfs/options.rs | 2 +- src/utils/json.rs | 36 ++++++++++++++++--- 4 files changed, 86 insertions(+), 42 deletions(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index 773d742..e8f2bc8 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -16,5 +16,5 @@ pub trait Ipfs { async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; async fn connect_to(&mut self, peer_id:&str) -> Result>; async fn disconect_from(&mut self, peer_id:&str)-> Result>; - async fn config(&mut self, options:HashMap) -> Result<()>; + async fn config(&mut self, options:&HashMap<&str, &str>) -> Result<()>; } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index a762251..684d64b 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -220,28 +220,50 @@ impl Ipfs for IpfsViaDaemon { anyhow::Ok(self.connected_peers.clone()) } - async fn config(&mut self, options:HashMap) -> Result<()> { + async fn config(&mut self, options:&HashMap<&str, &str>) -> Result<()> { + let get_profile = HttpRequest::new(&(HttpRequest::get_ipfs_addr()+"/config/show"), &(HashMap::new()), false); + let profile_vec = self.send_request(&get_profile).await?; + let profile_str = std::str::from_utf8(profile_vec.as_slice())?; + let mut profile:Value = serde_json::from_str(profile_str)?; for (setting, value) in options { - let cleaned_value = value.to_lowercase(); - let is_bool = match cleaned_value.trim() == "true" || cleaned_value.trim() == "false" { - true => "true", - false => "false" - }; - let is_json = match serde_json::from_str::(&value).is_ok() { - true => "true", - false => "false" + let number_value = value.to_string().parse::(); + let bool_value = value.to_string().parse::(); + let json_value = serde_json::from_str::(value); + let value_parsed = match number_value { + Ok(v) => Value::Number(serde_json::Number::from_f64(v).unwrap()), + Err(_) => { + match bool_value { + Ok(v) => Value::Bool(v), + Err(_) => { + match json_value { + Ok(v) => v, + Err(_) => Value::String(value.to_string()) + } + } + } + } }; - let args = HashMap::from([ - ("bool", is_bool), - ("json", is_json), - ("arg", &setting), - ("arg", &value) - ]); - let addr = HttpRequest::get_ipfs_addr()+"config"; - let cmd_options = HttpRequest::new(&addr, &args, false); - self.send_request(&cmd_options).await?; + let location = setting.split(".").map(|s| s.to_string()); + profile = json::change_json_part(&profile, location, &value_parsed)?; + } + let json_str = profile.to_string(); + + let args = HashMap::new(); + let headers = HashMap::from([ + ("Content-Disposition"," form-data; name=\"files\"; filename=\"config\""), + ("Content-Type", "application/octet-stream") + ]); + + let addr = HttpRequest::get_ipfs_addr()+"/config/replace"; + let mut request = HttpRequest::new(&addr, &args, true); + request.add_body(&headers, json_str.as_bytes()); + let response = self.send_request(&request).await?; + let res_str = std::str::from_utf8(response.as_slice())?; + if res_str.trim().is_empty(){ + return anyhow::Ok(()) + }else{ + bail!("There was error changing the settings in ipfs. The failure was: {}", res_str.red()); } - anyhow::Ok(()) } } impl Drop for IpfsViaDaemon { @@ -255,6 +277,7 @@ impl Drop for IpfsViaDaemon { mod tests { use futures::executor::block_on; use crate::utils::file_management; + use std::collections::HashMap; // use anyhow::Result; // use proptest::prelude::*; use super::*; @@ -288,20 +311,6 @@ mod tests { return ipfs; } - // #[test] - // fn can_connect(){ - // connect_to_peers(); - // assert!(true); - // } - // proptest! { - // #[test] - // #[serial] - // fn can_add_file(s: &str){ - // let mut ipfs = connect_to_peers(); - // ipf.add_file() - // assert!(true); - // } - // } #[test] #[serial] fn can_add_directory(){ @@ -345,11 +354,20 @@ mod tests { .filter(|seg| seg != &"." && !seg.is_empty()) .map(|seg| "/".to_string() + seg) .collect(); - println!("{}", matchable_path.red()); assert!(hashes.iter().any(|(path, _)|matchable_path == path.to_owned())); } #[test] + #[serial] fn can_config(){ - + let mut ipfs = IpfsViaDaemon::new().unwrap(); + block_on(ipfs.config(&HashMap::from([ + ("Datastore.StorageMax", "11GB"), + ("Datastore.GCPeriod", "2h") + ]))).unwrap(); + block_on(ipfs.config(&HashMap::from([ + ("Datastore.StorageMax", "10GB"), + ("Datastore.GCPeriod", "1h") + ]))).unwrap(); + assert!(true) } } \ No newline at end of file diff --git a/src/ipfs/options.rs b/src/ipfs/options.rs index c7b8943..3fe7629 100644 --- a/src/ipfs/options.rs +++ b/src/ipfs/options.rs @@ -1,5 +1,5 @@ pub const IPFS_API_PORT:u16 = 4869; -pub const IPFS_RETRY_ATTEMPTS:u16 = 7; +pub const IPFS_RETRY_ATTEMPTS:u16 = 4; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const HTTP_BOUNDARY:&str = "------------------------I_am_a_boundary_123A123"; diff --git a/src/utils/json.rs b/src/utils/json.rs index c2f94f8..967bfb6 100644 --- a/src/utils/json.rs +++ b/src/utils/json.rs @@ -1,12 +1,11 @@ +use serde_json::{Map, Value}; +use anyhow::{Result, bail}; + /* Ipfs often returns json with a single property with the value being an array. This function simply takes the array in that property and turns it into a vector that can be used in rust. It will return an error result if the json is not formatted in this way. */ - -use serde_json::Value; -use anyhow::{Result, bail}; - pub fn value_to_vec(json:&Value, index:&str) -> Result> where A:Clone + for<'de> serde::Deserialize<'de>{ anyhow::Ok( match json.get(index) { @@ -27,4 +26,31 @@ pub fn value_to_vec(json:&Value, index:&str) -> Result> }, None => bail!("Improperly formatted Json: Cant locate index {}", index) }) -} \ No newline at end of file +} + +pub fn change_json_part(root:&Value, loc:I, to:&Value) -> Result + where I: Iterator + Clone{ + if loc.clone().count() == 0 { + // println!("{}", "found it!".red()); + return Ok(to.clone()); + }else if !root.is_object(){ + return Ok(root.clone()); + }else{ + let root_iter = match root.as_object() { + Some(o) => o.iter(), + None => return Ok(Value::Object(serde_json::Map::new())) + }; + let mut new_root:Map = Map::new(); + for (prop, val) in root_iter { + let mut new_loc = loc.clone(); + let prop_to_match = new_loc.next().unwrap().to_string() ; + // println!("{} <=> {} = {}", prop, prop_to_match, prop.to_owned() == prop_to_match); + let new_val = match prop.to_owned() == prop_to_match{ + true => change_json_part(val, new_loc, to)?, + false => change_json_part(val, loc.clone(), to)? + }; + new_root.insert(prop.to_owned(), new_val); + } + return Ok(Value::Object(new_root)); + } +} From 9c38cf3a8297b977a671b0be748237a909a14d6b Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Thu, 1 Dec 2022 19:30:25 -0600 Subject: [PATCH 33/63] rebase fix --- src/lib.rs | 1 - src/utils.rs | 54 +----------------------------------------------- src/utils/log.rs | 53 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 54 deletions(-) create mode 100644 src/utils/log.rs diff --git a/src/lib.rs b/src/lib.rs index 4f46bb6..b3822e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ pub mod cmd; pub mod legacy; -pub mod utils; pub mod ipfs; pub mod utils; diff --git a/src/utils.rs b/src/utils.rs index d66ed79..3f5f565 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,57 +1,5 @@ pub mod file_management; pub mod json; pub mod math; +pub mod log; -use anyhow::{anyhow, Result}; -use std::io::{self, Write}; -use std::process::Output; - -pub struct OutputOptions { - verbose: bool, - quiet: bool, - error: bool, -} - -impl OutputOptions { - fn verbose() -> OutputOptions { - OutputOptions { - verbose: true, - quiet: false, - error: false, - } - } - - fn default() -> OutputOptions { - OutputOptions { - verbose: false, - quiet: false, - error: false, - } - } - - fn quiet() -> OutputOptions { - OutputOptions { - verbose: false, - quiet: true, - error: false, - } - } -} - -pub fn write_output(output: &Output) -> Result<()> { - let mut options = OutputOptions::verbose(); - - if output.stdout != [] { - print_output(std::str::from_utf8(&output.stdout)?, &options)?; - } - if output.stderr != [] { - options.error = true; - print_output(std::str::from_utf8(&output.stdout)?, &options)?; - } - Ok(()) -} - -pub fn print_output(output: &str, options: &OutputOptions) -> Result<()> { - println!("{}", output); - Ok(()) -} diff --git a/src/utils/log.rs b/src/utils/log.rs new file mode 100644 index 0000000..a2a7243 --- /dev/null +++ b/src/utils/log.rs @@ -0,0 +1,53 @@ +use anyhow::{anyhow, Result}; +use std::io::{self, Write}; +use std::process::Output; + +pub struct OutputOptions { + verbose: bool, + quiet: bool, + error: bool, +} + +impl OutputOptions { + fn verbose() -> OutputOptions { + OutputOptions { + verbose: true, + quiet: false, + error: false, + } + } + + fn default() -> OutputOptions { + OutputOptions { + verbose: false, + quiet: false, + error: false, + } + } + + fn quiet() -> OutputOptions { + OutputOptions { + verbose: false, + quiet: true, + error: false, + } + } +} + +// pub fn write_output(output: &Output) -> Result<()> { +// let mut options = OutputOptions::verbose(); + +// if output.stdout != (Vec::new() as Vec) { +// print_output(std::str::from_utf8(&output.stdout)?, &options)?; +// } +// if output.stderr != (Vec::new() as Vec) { +// options.error = true; +// print_output(std::str::from_utf8(&output.stdout)?, &options)?; +// } +// Ok(()) +// } + +pub fn print_output(output: &str, options: &OutputOptions) -> Result<()> { + println!("{}", output); + Ok(()) +} \ No newline at end of file From 0a06fc76049043234b62e3092d0d5be06ee793f3 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Thu, 1 Dec 2022 19:46:47 -0600 Subject: [PATCH 34/63] fix duplicate --- src/utils.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils.rs b/src/utils.rs index 2073b69..3274b85 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,4 +2,3 @@ pub mod file_management; pub mod json; pub mod math; pub mod log; -pub mod math; From 5356210da19096abc1a10544229ded720a1bec12 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 5 Dec 2022 11:07:35 -0800 Subject: [PATCH 35/63] started on cofig --- src/ipfs.rs | 1 + src/ipfs/config.rs | 238 +++++++++++++++++++++++++++++++++++++++++++++ src/ipfs/daemon.rs | 2 +- 3 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 src/ipfs/config.rs diff --git a/src/ipfs.rs b/src/ipfs.rs index e8f2bc8..b65596d 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -8,6 +8,7 @@ use anyhow::Result; pub mod daemon; pub mod http; pub mod options; +pub mod config; #[async_trait] pub trait Ipfs { diff --git a/src/ipfs/config.rs b/src/ipfs/config.rs new file mode 100644 index 0000000..5375120 --- /dev/null +++ b/src/ipfs/config.rs @@ -0,0 +1,238 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Config{ + #[serde(alias = "API")] + api:API, + #[serde(alias = "Addresses")] + addresses:Addresses, + #[serde(alias = "AutoNAT")] + auto_nat:AutoNAT, + #[serde(alias = "Bootstrap")] + bootstrap:Vec +} +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct API{ + #[serde(alias = "HTTPHeaders")] + http_headers:HttpHeaders, +} +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct HttpHeaders{ + +} +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Addresses{ + #[serde(alias = "API")] + api:String, + #[serde(alias = "Announce")] + announce:Vec, + #[serde(alias = "AppendAnnounce")] + append_announce:Vec, + #[serde(alias = "Gateway")] + gateway:String, + #[serde(alias = "NoAnounce")] + no_anounce:Vec, + #[serde(alias = "Swarm")] + swarm:Vec +} +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct AutoNAT{ + +} +/* +{ + "API":{ + "HTTPHeaders":{ + + } + }, + "Addresses":{ + "API":"/ip4/127.0.0.1/tcp/4867", + "Announce":[ + + ], + "AppendAnnounce":[ + + ], + "Gateway":"/ip4/127.0.0.1/tcp/5742", + "NoAnnounce":[ + + ], + "Swarm":[ + "/ip4/0.0.0.0/tcp/4001", + "/ip6/::/tcp/4001", + "/ip4/0.0.0.0/udp/4001/quic", + "/ip6/::/udp/4001/quic" + ] + }, + "AutoNAT":{ + + }, + "Bootstrap":[ + "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", + "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", + "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", + "/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ" + ], + "DNS":{ + "Resolvers":{ + + } + }, + "Datastore":{ + "BloomFilterSize":0, + "GCPeriod":"1h", + "HashOnRead":false, + "Spec":{ + "mounts":[ + { + "child":{ + "path":"blocks", + "shardFunc":"/repo/flatfs/shard/v1/next-to-last/2", + "sync":true, + "type":"flatfs" + }, + "mountpoint":"/blocks", + "prefix":"flatfs.datastore", + "type":"measure" + }, + { + "child":{ + "compression":"none", + "path":"datastore", + "type":"levelds" + }, + "mountpoint":"/", + "prefix":"leveldb.datastore", + "type":"measure" + } + ], + "type":"mount" + }, + "StorageGCWatermark":90, + "StorageMax":"10GB" + }, + "Discovery":{ + "MDNS":{ + "Enabled":true + } + }, + "Experimental":{ + "AcceleratedDHTClient":false, + "FilestoreEnabled":false, + "GraphsyncEnabled":false, + "Libp2pStreamMounting":false, + "P2pHttpProxy":false, + "StrategicProviding":false, + "UrlstoreEnabled":false + }, + "Gateway":{ + "APICommands":[ + + ], + "HTTPHeaders":{ + "Access-Control-Allow-Headers":[ + "X-Requested-With", + "Range", + "User-Agent" + ], + "Access-Control-Allow-Methods":[ + "GET" + ], + "Access-Control-Allow-Origin":[ + "*" + ] + }, + "NoDNSLink":false, + "NoFetch":false, + "PathPrefixes":[ + + ], + "PublicGateways":null, + "RootRedirect":"", + "Writable":false + }, + "Identity":{ + "PeerID":"12D3KooWGbZNXNRr7ZJkAecA445LyjZCkz1uTXne8zJCCpnDgicX" + }, + "Internal":{ + + }, + "Ipns":{ + "RecordLifetime":"", + "RepublishPeriod":"", + "ResolveCacheSize":128 + }, + "Migration":{ + "DownloadSources":[ + + ], + "Keep":"" + }, + "Mounts":{ + "FuseAllowOther":false, + "IPFS":"/ipfs", + "IPNS":"/ipns" + }, + "Peering":{ + "Peers":null + }, + "Pinning":{ + "RemoteServices":{ + + } + }, + "Plugins":{ + "Plugins":null + }, + "Provider":{ + "Strategy":"" + }, + "Pubsub":{ + "DisableSigning":false, + "Router":"" + }, + "Reprovider":{ + "Interval":"12h", + "Strategy":"all" + }, + "Routing":{ + "Methods":null, + "Routers":null, + "Type":"dht" + }, + "Swarm":{ + "AddrFilters":null, + "ConnMgr":{ + "GracePeriod":"20s", + "HighWater":900, + "LowWater":600, + "Type":"basic" + }, + "DisableBandwidthMetrics":false, + "DisableNatPortMap":false, + "RelayClient":{ + + }, + "RelayService":{ + + }, + "ResourceMgr":{ + + }, + "Transports":{ + "Multiplexers":{ + + }, + "Network":{ + + }, + "Security":{ + + } + } + } +} +*/ \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 684d64b..cb0faa8 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -247,7 +247,7 @@ impl Ipfs for IpfsViaDaemon { profile = json::change_json_part(&profile, location, &value_parsed)?; } let json_str = profile.to_string(); - + println!("{}", json_str.red()); let args = HashMap::new(); let headers = HashMap::from([ ("Content-Disposition"," form-data; name=\"files\"; filename=\"config\""), From ddf6387fd3da4bb5538a1a24c609ee9bcacee5ef Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Mon, 5 Dec 2022 11:49:39 -0800 Subject: [PATCH 36/63] Add error and formatting --- src/ipfs/daemon.rs | 265 +++++++++++++++++++++++++-------------------- 1 file changed, 147 insertions(+), 118 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index cb0faa8..02ce688 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,22 +1,22 @@ -use crate::ipfs::Ipfs; -use crate::utils::*; -use anyhow::{Result, bail}; use super::http::HttpRequest; use super::options::*; -use serde_json::Value; -use std::collections::HashMap; +use crate::ipfs::http::HttpHandler; +use crate::ipfs::Ipfs; +use crate::utils::*; +use anyhow::{bail, Result}; use async_trait::async_trait; -use std::process::{Command, Child}; use colored::Colorize; -use crate::ipfs::http::HttpHandler; -use std::time::{Duration, SystemTime}; +use serde_json::Value; +use std::collections::HashMap; +use std::process::{Child, Command}; use std::thread::sleep; +use std::time::{Duration, SystemTime}; pub struct IpfsViaDaemon { - http:HttpHandler, - ipfs_process:Child, - is_ipfs_ready:bool, - connected_peers:Vec + http: HttpHandler, + ipfs_process: Child, + is_ipfs_ready: bool, + connected_peers: Vec, } impl IpfsViaDaemon { pub fn new() -> Result { @@ -26,30 +26,43 @@ impl IpfsViaDaemon { .arg("--api") .arg(&api_addr) .arg("daemon") - .spawn()?; - println!("{}", ("⚠️ Warning: Ipfs Proccess Started. Please do NOT force close this app⚠️".yellow())); - anyhow::Ok(IpfsViaDaemon{ - ipfs_process: proccess, - http: HttpHandler::new(), + .spawn() + .unwrap_or_else(|e| panic!("Failed to start IPFS daemon: {}\n This error may be because the Kubo binary is not on your PATH.", e)); + + println!( + "{}", + ("⚠️ Warning: Ipfs Proccess Started. Please do NOT force close this app⚠️".yellow()) + ); + anyhow::Ok(IpfsViaDaemon { + ipfs_process: proccess, + http: HttpHandler::new(), is_ipfs_ready: false, - connected_peers: vec![] + connected_peers: vec![], }) } - async fn send_request(&mut self, options:&HttpRequest) -> Result>{ + async fn send_request(&mut self, options: &HttpRequest) -> Result> { self.await_ready().await?; - let result = self.http.try_send_request(options, Some(|response_data:Vec| { - let response_str = std::str::from_utf8(response_data.as_slice())?; - //TODO: do a better job of checking here - anyhow::Ok(!(response_str.contains("\"Type\":\"error\""))) - })).await?; - anyhow::Ok(result)//it always return Some if a handler is given + let result = self + .http + .try_send_request( + options, + Some(|response_data: Vec| { + let response_str = std::str::from_utf8(response_data.as_slice())?; + //TODO: do a better job of checking here + anyhow::Ok(!(response_str.contains("\"Type\":\"error\""))) + }), + ) + .await?; + anyhow::Ok(result) //it always return Some if a handler is given } - async fn await_ready(&mut self) -> Result<()>{ - if self.is_ipfs_ready == true { return anyhow::Ok(());} + async fn await_ready(&mut self) -> Result<()> { + if self.is_ipfs_ready == true { + return anyhow::Ok(()); + } let start_time = SystemTime::now(); loop { println!("{}", "checking if ipfs is ready...".green()); - + if self.poll_ipfs_ready().await { println!("{}", "IPFS is ready!!".green()); self.is_ipfs_ready = true; @@ -60,33 +73,34 @@ impl IpfsViaDaemon { let now = SystemTime::now(); if now.duration_since(start_time)? > Duration::new(BOOT_TIME_OUT as u64, 0) { - bail!("{}","Failed to start ipfs because the timeout reached!!".red()) + bail!( + "{}", + "Failed to start ipfs because the timeout reached!!".red() + ) } } anyhow::Ok(()) } - async fn poll_ipfs_ready(&mut self) -> bool{ + async fn poll_ipfs_ready(&mut self) -> bool { let args = HashMap::new(); - let addr = HttpRequest::get_ipfs_addr() + "/config/show"; + let addr = HttpRequest::get_ipfs_addr() + "/config/show"; let cmd = HttpRequest::new(&addr, &args, false); let response = self.http.send_request(&cmd).await; return match response { Ok(_) => true, Err(e) => { - eprint!("{}", e); + eprint!("{}", e); false } }; } //TODO: Better name? - async fn swarm_or_bootstrap_cmd(&mut self, cmd:&str, peer_id:&str) -> Result>{ - let args = HashMap::from([ - ("arg", peer_id) - ]); - let addr = HttpRequest::get_ipfs_addr()+cmd; + async fn swarm_or_bootstrap_cmd(&mut self, cmd: &str, peer_id: &str) -> Result> { + let args = HashMap::from([("arg", peer_id)]); + let addr = HttpRequest::get_ipfs_addr() + cmd; let cmd_options = HttpRequest::new(&addr, &args, false); let result_data = self.send_request(&cmd_options).await?; - let result_str =std::str::from_utf8(result_data.as_slice())?; + let result_str = std::str::from_utf8(result_data.as_slice())?; let result_json:Value = match serde_json::from_str(result_str){ Ok(x) => x, Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) @@ -105,28 +119,28 @@ impl IpfsViaDaemon { return anyhow::Ok(peer_list); } - fn response_to_hashes(response:&str) -> Result> { + fn response_to_hashes(response: &str) -> Result> { let mut res = response.to_string(); let mut ret = HashMap::new(); return loop { //get location to take segment to let json_seg_end = match res.find("}") { Some(seg_loc) => seg_loc, - None => break anyhow::Ok(ret) + None => break anyhow::Ok(ret), }; //get segment to convert to json and remove the segment from res let res_vec = res.chars().collect::>(); - let json_seg = res_vec[..(json_seg_end+1)].iter().collect::(); - res = res_vec[(json_seg_end+1)..].iter().collect(); + let json_seg = res_vec[..(json_seg_end + 1)].iter().collect::(); + res = res_vec[(json_seg_end + 1)..].iter().collect(); //convert that segment to json and value - let json:Value = serde_json::from_str(&json_seg)?; - let path = match json.get("Name"){ + let json: Value = serde_json::from_str(&json_seg)?; + let path = match json.get("Name") { Some(val) => "/".to_string() + &val.to_string().split("\"").collect::(), - None => bail!("Could not find Name property in ipfs's response to an add") + None => bail!("Could not find Name property in ipfs's response to an add"), }; - let hash = match json.get("Hash"){ + let hash = match json.get("Hash") { Some(val) => val.to_string().split("\"").collect::(), - None => bail!("Could not find Hash property in ipfs's response to an add") + None => bail!("Could not find Hash property in ipfs's response to an add"), }; ret.insert(path, hash); }; @@ -134,17 +148,13 @@ impl IpfsViaDaemon { } #[async_trait] impl Ipfs for IpfsViaDaemon { - async fn add_file(&mut self, path:&str) -> Result> { - let cmd = HttpRequest::get_ipfs_addr()+ "/add"; - let args = HashMap::from([ - ("quieter", "true"), - ("cid-version", "1"), - ("path", &path) - ]); + async fn add_file(&mut self, path: &str) -> Result> { + let cmd = HttpRequest::get_ipfs_addr() + "/add"; + let args = HashMap::from([("quieter", "true"), ("cid-version", "1"), ("path", &path)]); let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &path); let headers = HashMap::from([ ("Content-Disposition", &disposition as &str), - ("Content-Type", "application/octet-stream") + ("Content-Type", "application/octet-stream"), ]); let mut cmd_options = HttpRequest::new(&cmd, &args, true); let contents = std::fs::read(path)?; @@ -155,21 +165,18 @@ impl Ipfs for IpfsViaDaemon { anyhow::Ok(hashes) } - async fn add_directory(&mut self, path:&str) -> Result> { - let cmd = HttpRequest::get_ipfs_addr()+ "/add"; - let args = HashMap::from([ - ("quieter", "true"), - ("cid-version", "1") - ]); + async fn add_directory(&mut self, path: &str) -> Result> { + let cmd = HttpRequest::get_ipfs_addr() + "/add"; + let args = HashMap::from([("quieter", "true"), ("cid-version", "1")]); let mut request = HttpRequest::new(&cmd, &args, true); println!("{}", "Adding the following directories..".blue()); - + let dirs = file_management::get_dirs_in(path)?; - for dir in dirs{ + for dir in dirs { let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &dir); let headers = HashMap::from([ ("Content-Disposition", &disposition as &str), - ("Content-Type", "application/x-directory") + ("Content-Type", "application/x-directory"), ]); request.add_body(&headers, &[]); println!("{}", dir.blue()); @@ -182,7 +189,7 @@ impl Ipfs for IpfsViaDaemon { let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &file_path); let headers = HashMap::from([ ("Content-Disposition", &disposition as &str), - ("Content-Type", "application/octet-stream") + ("Content-Type", "application/octet-stream"), ]); request.add_body(&headers, data.as_slice()); println!("{}", file_path.blue()); @@ -193,55 +200,62 @@ impl Ipfs for IpfsViaDaemon { anyhow::Ok(hashes) } - async fn add_bootstrap(&mut self, peer_id:&str) -> Result> { + async fn add_bootstrap(&mut self, peer_id: &str) -> Result> { self.swarm_or_bootstrap_cmd("/bootstrap/add", peer_id).await } - async fn connect_to(&mut self, peer_id:&str) -> Result> { - self.swarm_or_bootstrap_cmd("/swarm/connect", peer_id).await?; + async fn connect_to(&mut self, peer_id: &str) -> Result> { + self.swarm_or_bootstrap_cmd("/swarm/connect", peer_id) + .await?; self.connected_peers.push(peer_id.to_string()); // print!("Connected Peers: "); // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); anyhow::Ok(self.connected_peers.clone()) } - async fn disconect_from(&mut self, peer_id:&str)-> Result> { - self.swarm_or_bootstrap_cmd("/swarm/disconnect", peer_id).await?; - self.connected_peers = self.connected_peers.iter() + async fn disconect_from(&mut self, peer_id: &str) -> Result> { + self.swarm_or_bootstrap_cmd("/swarm/disconnect", peer_id) + .await?; + self.connected_peers = self + .connected_peers + .iter() .filter_map(|peer_id_to_check| { let checkable = peer_id_to_check.to_string(); - match peer_id != checkable{ + match peer_id != checkable { true => Some(checkable), - false => None + false => None, } - }).collect(); + }) + .collect(); print!("Connected Peers: "); - self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); + self.connected_peers + .iter() + .for_each(|peer| print!("{}, ", peer)); anyhow::Ok(self.connected_peers.clone()) } - async fn config(&mut self, options:&HashMap<&str, &str>) -> Result<()> { - let get_profile = HttpRequest::new(&(HttpRequest::get_ipfs_addr()+"/config/show"), &(HashMap::new()), false); + async fn config(&mut self, options: &HashMap<&str, &str>) -> Result<()> { + let get_profile = HttpRequest::new( + &(HttpRequest::get_ipfs_addr() + "/config/show"), + &(HashMap::new()), + false, + ); let profile_vec = self.send_request(&get_profile).await?; let profile_str = std::str::from_utf8(profile_vec.as_slice())?; - let mut profile:Value = serde_json::from_str(profile_str)?; + let mut profile: Value = serde_json::from_str(profile_str)?; for (setting, value) in options { let number_value = value.to_string().parse::(); let bool_value = value.to_string().parse::(); let json_value = serde_json::from_str::(value); let value_parsed = match number_value { Ok(v) => Value::Number(serde_json::Number::from_f64(v).unwrap()), - Err(_) => { - match bool_value { - Ok(v) => Value::Bool(v), - Err(_) => { - match json_value { - Ok(v) => v, - Err(_) => Value::String(value.to_string()) - } - } - } - } + Err(_) => match bool_value { + Ok(v) => Value::Bool(v), + Err(_) => match json_value { + Ok(v) => v, + Err(_) => Value::String(value.to_string()), + }, + }, }; let location = setting.split(".").map(|s| s.to_string()); profile = json::change_json_part(&profile, location, &value_parsed)?; @@ -250,40 +264,50 @@ impl Ipfs for IpfsViaDaemon { println!("{}", json_str.red()); let args = HashMap::new(); let headers = HashMap::from([ - ("Content-Disposition"," form-data; name=\"files\"; filename=\"config\""), - ("Content-Type", "application/octet-stream") + ( + "Content-Disposition", + " form-data; name=\"files\"; filename=\"config\"", + ), + ("Content-Type", "application/octet-stream"), ]); - let addr = HttpRequest::get_ipfs_addr()+"/config/replace"; + let addr = HttpRequest::get_ipfs_addr() + "/config/replace"; let mut request = HttpRequest::new(&addr, &args, true); request.add_body(&headers, json_str.as_bytes()); let response = self.send_request(&request).await?; let res_str = std::str::from_utf8(response.as_slice())?; - if res_str.trim().is_empty(){ - return anyhow::Ok(()) - }else{ - bail!("There was error changing the settings in ipfs. The failure was: {}", res_str.red()); + if res_str.trim().is_empty() { + return anyhow::Ok(()); + } else { + bail!( + "There was error changing the settings in ipfs. The failure was: {}", + res_str.red() + ); } } } impl Drop for IpfsViaDaemon { fn drop(&mut self) { self.ipfs_process.kill().unwrap(); - println!("{}", ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅".bright_green())) + println!( + "{}", + ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅" + .bright_green()) + ) } } #[cfg(test)] mod tests { - use futures::executor::block_on; use crate::utils::file_management; + use futures::executor::block_on; use std::collections::HashMap; // use anyhow::Result; // use proptest::prelude::*; use super::*; use serial_test::serial; - //TODO: Setup pizza + //TODO: Setup pizza const PEER_ADDRS:&'static [&'static str] = &[ "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", @@ -300,10 +324,10 @@ mod tests { "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", ]; - fn connect_to_peers() -> IpfsViaDaemon{ + fn connect_to_peers() -> IpfsViaDaemon { let mut ipfs = IpfsViaDaemon::new().unwrap(); for peer in PEER_ADDRS { - let result_peers = block_on(ipfs.connect_to(peer)).unwrap() ; + let result_peers = block_on(ipfs.connect_to(peer)).unwrap(); for result_peer in result_peers { println!("Connected to peer! {}", result_peer); } @@ -313,11 +337,11 @@ mod tests { #[test] #[serial] - fn can_add_directory(){ + fn can_add_directory() { let test_dir = "./test-dir/more-tests"; let mut ipfs = connect_to_peers(); let hashes = block_on(ipfs.add_directory(test_dir)).unwrap(); - println!("{}","Finnished Hashes:".green()); + println!("{}", "Finnished Hashes:".green()); for (path, hash) in &hashes { println!("{}: {}", path.green(), hash.blue()) } @@ -325,49 +349,54 @@ mod tests { let files = file_management::get_files_in(test_dir).unwrap(); let folders = file_management::get_dirs_in(test_dir).unwrap(); - files.iter() + files + .iter() .map(|(path, _)| path) .chain(folders.iter()) .for_each(|path_to_match| { - let fixed_path_to_match:String = path_to_match + let fixed_path_to_match: String = path_to_match .split("/") .filter(|seg| seg != &"." && !seg.is_empty()) .map(|seg| "/".to_string() + seg) .collect(); - assert!(hashes.iter().any(|(path, _)|fixed_path_to_match == path.to_owned())) + assert!(hashes + .iter() + .any(|(path, _)| fixed_path_to_match == path.to_owned())) }); - - } #[test] #[serial] - fn can_add_file(){ + fn can_add_file() { let test_file = "./test-dir/test.txt"; let mut ipfs = connect_to_peers(); let hashes = block_on(ipfs.add_file(test_file)).unwrap(); - println!("{}","Finnished Hashes:\n".green()); + println!("{}", "Finnished Hashes:\n".green()); for (path, hash) in &hashes { println!("{}: {}", path.green(), hash.blue()) } - let matchable_path:String = test_file + let matchable_path: String = test_file .split("/") .filter(|seg| seg != &"." && !seg.is_empty()) .map(|seg| "/".to_string() + seg) .collect(); - assert!(hashes.iter().any(|(path, _)|matchable_path == path.to_owned())); + assert!(hashes + .iter() + .any(|(path, _)| matchable_path == path.to_owned())); } #[test] #[serial] - fn can_config(){ + fn can_config() { let mut ipfs = IpfsViaDaemon::new().unwrap(); block_on(ipfs.config(&HashMap::from([ ("Datastore.StorageMax", "11GB"), - ("Datastore.GCPeriod", "2h") - ]))).unwrap(); + ("Datastore.GCPeriod", "2h"), + ]))) + .unwrap(); block_on(ipfs.config(&HashMap::from([ ("Datastore.StorageMax", "10GB"), - ("Datastore.GCPeriod", "1h") - ]))).unwrap(); + ("Datastore.GCPeriod", "1h"), + ]))) + .unwrap(); assert!(true) } -} \ No newline at end of file +} From 1cd9f55ed6f180dc92444c67350d79072e60469c Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 5 Dec 2022 11:57:49 -0800 Subject: [PATCH 37/63] re adding the disconnect from on drop --- src/ipfs/daemon.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 02ce688..d7491bd 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -6,6 +6,7 @@ use crate::utils::*; use anyhow::{bail, Result}; use async_trait::async_trait; use colored::Colorize; +use futures::executor::block_on; use serde_json::Value; use std::collections::HashMap; use std::process::{Child, Command}; @@ -288,6 +289,9 @@ impl Ipfs for IpfsViaDaemon { } impl Drop for IpfsViaDaemon { fn drop(&mut self) { + for peer in self.connected_peers.clone().iter() { + block_on(self.disconect_from(peer)).unwrap(); + } self.ipfs_process.kill().unwrap(); println!( "{}", From e3b0423b037a5320781d8396baf5acc3b7e762c7 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 5 Dec 2022 13:03:05 -0800 Subject: [PATCH 38/63] remove add bootstrap --- src/ipfs.rs | 1 - src/ipfs/daemon.rs | 10 +++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index b65596d..14b7aa6 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -14,7 +14,6 @@ pub mod config; pub trait Ipfs { async fn add_file(&mut self, path:&str) -> Result>; async fn add_directory(&mut self, path:&str) -> Result>; - async fn add_bootstrap(&mut self, peer_id:&str) -> Result>; async fn connect_to(&mut self, peer_id:&str) -> Result>; async fn disconect_from(&mut self, peer_id:&str)-> Result>; async fn config(&mut self, options:&HashMap<&str, &str>) -> Result<()>; diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index d7491bd..c645017 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -96,7 +96,7 @@ impl IpfsViaDaemon { }; } //TODO: Better name? - async fn swarm_or_bootstrap_cmd(&mut self, cmd: &str, peer_id: &str) -> Result> { + async fn swarm_cmd(&mut self, cmd: &str, peer_id: &str) -> Result> { let args = HashMap::from([("arg", peer_id)]); let addr = HttpRequest::get_ipfs_addr() + cmd; let cmd_options = HttpRequest::new(&addr, &args, false); @@ -201,12 +201,8 @@ impl Ipfs for IpfsViaDaemon { anyhow::Ok(hashes) } - async fn add_bootstrap(&mut self, peer_id: &str) -> Result> { - self.swarm_or_bootstrap_cmd("/bootstrap/add", peer_id).await - } - async fn connect_to(&mut self, peer_id: &str) -> Result> { - self.swarm_or_bootstrap_cmd("/swarm/connect", peer_id) + self.swarm_cmd("/swarm/connect", peer_id) .await?; self.connected_peers.push(peer_id.to_string()); // print!("Connected Peers: "); @@ -215,7 +211,7 @@ impl Ipfs for IpfsViaDaemon { } async fn disconect_from(&mut self, peer_id: &str) -> Result> { - self.swarm_or_bootstrap_cmd("/swarm/disconnect", peer_id) + self.swarm_cmd("/swarm/disconnect", peer_id) .await?; self.connected_peers = self .connected_peers From 0deb42cd11b6143f56d128bf4d3d54248e121ff9 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Mon, 5 Dec 2022 22:49:01 -0800 Subject: [PATCH 39/63] Config templating --- src/ipfs/config.rs | 88 ++++++++++++++++++++++----------- src/ipfs/config/API.rs | 11 +++++ src/ipfs/config/Addresses.rs | 17 +++++++ src/ipfs/config/AutoNAT.rs | 0 src/ipfs/config/DNS.rs | 0 src/ipfs/config/Datastore.rs | 0 src/ipfs/config/Discovery.rs | 0 src/ipfs/config/Experimental.rs | 0 src/ipfs/config/Gateway.rs | 0 src/ipfs/config/Identity.rs | 0 src/ipfs/config/Ipns.rs | 0 src/ipfs/config/Migration.rs | 0 src/ipfs/config/Mounts.rs | 0 src/ipfs/config/Peering.rs | 0 src/ipfs/config/Pinning.rs | 0 src/ipfs/config/Plugins.rs | 0 src/ipfs/config/Provider.rs | 0 src/ipfs/config/Pubsub.rs | 0 src/ipfs/config/Reprovider.rs | 0 src/ipfs/config/Routing.rs | 0 src/ipfs/config/Swarm.rs | 0 21 files changed, 87 insertions(+), 29 deletions(-) create mode 100644 src/ipfs/config/API.rs create mode 100644 src/ipfs/config/Addresses.rs create mode 100644 src/ipfs/config/AutoNAT.rs create mode 100644 src/ipfs/config/DNS.rs create mode 100644 src/ipfs/config/Datastore.rs create mode 100644 src/ipfs/config/Discovery.rs create mode 100644 src/ipfs/config/Experimental.rs create mode 100644 src/ipfs/config/Gateway.rs create mode 100644 src/ipfs/config/Identity.rs create mode 100644 src/ipfs/config/Ipns.rs create mode 100644 src/ipfs/config/Migration.rs create mode 100644 src/ipfs/config/Mounts.rs create mode 100644 src/ipfs/config/Peering.rs create mode 100644 src/ipfs/config/Pinning.rs create mode 100644 src/ipfs/config/Plugins.rs create mode 100644 src/ipfs/config/Provider.rs create mode 100644 src/ipfs/config/Pubsub.rs create mode 100644 src/ipfs/config/Reprovider.rs create mode 100644 src/ipfs/config/Routing.rs create mode 100644 src/ipfs/config/Swarm.rs diff --git a/src/ipfs/config.rs b/src/ipfs/config.rs index 5375120..4910b33 100644 --- a/src/ipfs/config.rs +++ b/src/ipfs/config.rs @@ -1,44 +1,74 @@ +pub mod Identity; +pub mod Datastore; +pub mod Mounts; +pub mod Discovery; +pub mod Routing; +pub mod Ipns; +pub mod Gateway; +pub mod Swarm; +pub mod Pubsub; +pub mod Peering; +pub mod DNS; +pub mod Migration; +pub mod Provider; +pub mod Reprovider; +pub mod Experimental; +pub mod Plugins; +pub mod Pinning; +pub mod API; +pub mod Addresses; +pub mod AutoNAT; + use serde::{Serialize, Deserialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Config{ + #[serde(alias = "Identity")] + identity:Identity::Identity, + #[serde(alias = "Datastore")] + datastore:Datastore::Datastore, + #[serde(alias = "Mounts")] + mounts:Mounts::Mounts, + #[serde(alias = "Discovery")] + discovery:Discovery::Discovery, + #[serde(alias = "Routing")] + routing:Routing::Routing, + #[serde(alias = "Ipns")] + ipns:Ipns::Ipns, + #[serde(alias = "Gateway")] + gateway:Gateway::Gateway, + #[serde(alias = "Swarm")] + swarm:Swarm::Swarm, + #[serde(alias = "Pubsub")] + pubsub:Pubsub::Pubsub, + #[serde(alias = "Peering")] + peering:Peering::Peering, + #[serde(alias = "DNS")] + dns:DNS::DNS, + #[serde(alias = "Migration")] + migration:Migration::Migration, + #[serde(alias = "Provider")] + provider:Provider::Provider, + #[serde(alias = "Reprovider")] + reprovider:Reprovider::Reprovider, + #[serde(alias = "Experimental")] + experimental:Experimental::Experimental, + #[serde(alias = "Plugins")] + plugins:Plugins::Plugins, + #[serde(alias = "Pinning")] + pinning:Pinning::Pinning, #[serde(alias = "API")] - api:API, + api:API::API, #[serde(alias = "Addresses")] - addresses:Addresses, + addresses:Addresses::Addresses, #[serde(alias = "AutoNAT")] - auto_nat:AutoNAT, + auto_nat:AutoNAT::AutoNAT, #[serde(alias = "Bootstrap")] bootstrap:Vec } -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct API{ - #[serde(alias = "HTTPHeaders")] - http_headers:HttpHeaders, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct HttpHeaders{ -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Addresses{ - #[serde(alias = "API")] - api:String, - #[serde(alias = "Announce")] - announce:Vec, - #[serde(alias = "AppendAnnounce")] - append_announce:Vec, - #[serde(alias = "Gateway")] - gateway:String, - #[serde(alias = "NoAnounce")] - no_anounce:Vec, - #[serde(alias = "Swarm")] - swarm:Vec -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct AutoNAT{ -} + /* { "API":{ diff --git a/src/ipfs/config/API.rs b/src/ipfs/config/API.rs new file mode 100644 index 0000000..9c4c0da --- /dev/null +++ b/src/ipfs/config/API.rs @@ -0,0 +1,11 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct API{ + #[serde(alias = "HTTPHeaders")] + http_headers:HttpHeaders, +} +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct HttpHeaders{ + +} \ No newline at end of file diff --git a/src/ipfs/config/Addresses.rs b/src/ipfs/config/Addresses.rs new file mode 100644 index 0000000..384bd10 --- /dev/null +++ b/src/ipfs/config/Addresses.rs @@ -0,0 +1,17 @@ +use serde::{Serialize, Deserialize}; + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Addresses{ + #[serde(alias = "API")] + api:String, + #[serde(alias = "Announce")] + announce:Vec, + #[serde(alias = "AppendAnnounce")] + append_announce:Vec, + #[serde(alias = "Gateway")] + gateway:String, + #[serde(alias = "NoAnounce")] + no_anounce:Vec, + #[serde(alias = "Swarm")] + swarm:Vec +} \ No newline at end of file diff --git a/src/ipfs/config/AutoNAT.rs b/src/ipfs/config/AutoNAT.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/DNS.rs b/src/ipfs/config/DNS.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Datastore.rs b/src/ipfs/config/Datastore.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Discovery.rs b/src/ipfs/config/Discovery.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Experimental.rs b/src/ipfs/config/Experimental.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Gateway.rs b/src/ipfs/config/Gateway.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Identity.rs b/src/ipfs/config/Identity.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Ipns.rs b/src/ipfs/config/Ipns.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Migration.rs b/src/ipfs/config/Migration.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Mounts.rs b/src/ipfs/config/Mounts.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Peering.rs b/src/ipfs/config/Peering.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Pinning.rs b/src/ipfs/config/Pinning.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Plugins.rs b/src/ipfs/config/Plugins.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Provider.rs b/src/ipfs/config/Provider.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Pubsub.rs b/src/ipfs/config/Pubsub.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Reprovider.rs b/src/ipfs/config/Reprovider.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Routing.rs b/src/ipfs/config/Routing.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/ipfs/config/Swarm.rs b/src/ipfs/config/Swarm.rs new file mode 100644 index 0000000..e69de29 From b604f5c48b6be1d2ca3fbe092ca58c21ffac9482 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 6 Dec 2022 10:54:58 -0800 Subject: [PATCH 40/63] ready for refactor --- src/ipfs.rs | 8 +- src/ipfs/config.rs | 103 +++++++++++------- .../config/{Addresses.rs => addresses.rs} | 6 + src/ipfs/config/{API.rs => api.rs} | 7 +- src/ipfs/config/{AutoNAT.rs => auto_nat.rs} | 0 src/ipfs/config/{DNS.rs => datastore.rs} | 0 .../config/{Datastore.rs => discovery.rs} | 0 src/ipfs/config/{Discovery.rs => dns.rs} | 0 .../{Experimental.rs => experimental.rs} | 0 src/ipfs/config/{Gateway.rs => gateway.rs} | 0 src/ipfs/config/{Identity.rs => identity.rs} | 0 src/ipfs/config/{Ipns.rs => ipns.rs} | 0 .../config/{Migration.rs => migration.rs} | 0 src/ipfs/config/{Mounts.rs => mounts.rs} | 0 src/ipfs/config/{Peering.rs => peering.rs} | 0 src/ipfs/config/{Pinning.rs => pinning.rs} | 0 src/ipfs/config/{Plugins.rs => plugins.rs} | 0 src/ipfs/config/{Provider.rs => provider.rs} | 0 src/ipfs/config/{Pubsub.rs => pubsub.rs} | 0 .../config/{Reprovider.rs => reprovider.rs} | 0 src/ipfs/config/{Routing.rs => routing.rs} | 0 src/ipfs/config/{Swarm.rs => swarm.rs} | 0 src/ipfs/daemon.rs | 96 ++++------------ 23 files changed, 99 insertions(+), 121 deletions(-) rename src/ipfs/config/{Addresses.rs => addresses.rs} (77%) rename src/ipfs/config/{API.rs => api.rs} (54%) rename src/ipfs/config/{AutoNAT.rs => auto_nat.rs} (100%) rename src/ipfs/config/{DNS.rs => datastore.rs} (100%) rename src/ipfs/config/{Datastore.rs => discovery.rs} (100%) rename src/ipfs/config/{Discovery.rs => dns.rs} (100%) rename src/ipfs/config/{Experimental.rs => experimental.rs} (100%) rename src/ipfs/config/{Gateway.rs => gateway.rs} (100%) rename src/ipfs/config/{Identity.rs => identity.rs} (100%) rename src/ipfs/config/{Ipns.rs => ipns.rs} (100%) rename src/ipfs/config/{Migration.rs => migration.rs} (100%) rename src/ipfs/config/{Mounts.rs => mounts.rs} (100%) rename src/ipfs/config/{Peering.rs => peering.rs} (100%) rename src/ipfs/config/{Pinning.rs => pinning.rs} (100%) rename src/ipfs/config/{Plugins.rs => plugins.rs} (100%) rename src/ipfs/config/{Provider.rs => provider.rs} (100%) rename src/ipfs/config/{Pubsub.rs => pubsub.rs} (100%) rename src/ipfs/config/{Reprovider.rs => reprovider.rs} (100%) rename src/ipfs/config/{Routing.rs => routing.rs} (100%) rename src/ipfs/config/{Swarm.rs => swarm.rs} (100%) diff --git a/src/ipfs.rs b/src/ipfs.rs index 14b7aa6..17601cb 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -5,6 +5,8 @@ use std::collections::HashMap; use anyhow::Result; +use self::config::Config; + pub mod daemon; pub mod http; pub mod options; @@ -14,7 +16,7 @@ pub mod config; pub trait Ipfs { async fn add_file(&mut self, path:&str) -> Result>; async fn add_directory(&mut self, path:&str) -> Result>; - async fn connect_to(&mut self, peer_id:&str) -> Result>; - async fn disconect_from(&mut self, peer_id:&str)-> Result>; - async fn config(&mut self, options:&HashMap<&str, &str>) -> Result<()>; + async fn connect_to(&mut self, peer_id:&str) -> Result<()>; + async fn set_config(&mut self, options:&Config) -> Result<()>; + async fn get_config(&mut self) -> Result; } \ No newline at end of file diff --git a/src/ipfs/config.rs b/src/ipfs/config.rs index 4910b33..0d16175 100644 --- a/src/ipfs/config.rs +++ b/src/ipfs/config.rs @@ -1,70 +1,91 @@ -pub mod Identity; -pub mod Datastore; -pub mod Mounts; -pub mod Discovery; -pub mod Routing; -pub mod Ipns; -pub mod Gateway; -pub mod Swarm; -pub mod Pubsub; -pub mod Peering; -pub mod DNS; -pub mod Migration; -pub mod Provider; -pub mod Reprovider; -pub mod Experimental; -pub mod Plugins; -pub mod Pinning; -pub mod API; -pub mod Addresses; -pub mod AutoNAT; +pub mod identity; +pub mod datastore; +pub mod mounts; +pub mod discovery; +pub mod routing; +pub mod ipns; +pub mod gateway; +pub mod swarm; +pub mod pubsub; +pub mod peering; +pub mod dns; +pub mod migration; +pub mod provider; +pub mod reprovider; +pub mod experimental; +pub mod plugins; +pub mod pinning; +pub mod api; +pub mod addresses; +pub mod auto_nat; use serde::{Serialize, Deserialize}; +use serde_json::Value; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Config{ + #[serde(default)] #[serde(alias = "Identity")] - identity:Identity::Identity, + pub identity:Value, + #[serde(default)] #[serde(alias = "Datastore")] - datastore:Datastore::Datastore, + pub datastore:Value, + #[serde(default)] #[serde(alias = "Mounts")] - mounts:Mounts::Mounts, + pub mounts:Value, + #[serde(default)] #[serde(alias = "Discovery")] - discovery:Discovery::Discovery, + pub discovery:Value, + #[serde(default)] #[serde(alias = "Routing")] - routing:Routing::Routing, + pub routing:Value, + #[serde(default)] #[serde(alias = "Ipns")] - ipns:Ipns::Ipns, + pub ipns:Value, + #[serde(default)] #[serde(alias = "Gateway")] - gateway:Gateway::Gateway, + pub gateway:Value, + #[serde(default)] #[serde(alias = "Swarm")] - swarm:Swarm::Swarm, + pub swarm:Value, + #[serde(default)] #[serde(alias = "Pubsub")] - pubsub:Pubsub::Pubsub, + pub pubsub:Value, + #[serde(default)] #[serde(alias = "Peering")] - peering:Peering::Peering, + pub peering:Value, + #[serde(default)] #[serde(alias = "DNS")] - dns:DNS::DNS, + pub dns:Value, + #[serde(default)] #[serde(alias = "Migration")] - migration:Migration::Migration, + pub migration:Value, + #[serde(default)] #[serde(alias = "Provider")] - provider:Provider::Provider, + pub provider:Value, + #[serde(default)] #[serde(alias = "Reprovider")] - reprovider:Reprovider::Reprovider, + pub reprovider:Value, + #[serde(default)] #[serde(alias = "Experimental")] - experimental:Experimental::Experimental, + pub experimental:Value, + #[serde(default)] #[serde(alias = "Plugins")] - plugins:Plugins::Plugins, + pub plugins:Value, + #[serde(default)] #[serde(alias = "Pinning")] - pinning:Pinning::Pinning, + pub pinning:Value, + #[serde(default)] #[serde(alias = "API")] - api:API::API, + pub api:Value, #[serde(alias = "Addresses")] - addresses:Addresses::Addresses, + pub addresses:addresses::Addresses, + #[serde(default)] #[serde(alias = "AutoNAT")] - auto_nat:AutoNAT::AutoNAT, + pub auto_nat:Value, + #[serde(default)] #[serde(alias = "Bootstrap")] - bootstrap:Vec + pub bootstrap:Vec } diff --git a/src/ipfs/config/Addresses.rs b/src/ipfs/config/addresses.rs similarity index 77% rename from src/ipfs/config/Addresses.rs rename to src/ipfs/config/addresses.rs index 384bd10..69483bb 100644 --- a/src/ipfs/config/Addresses.rs +++ b/src/ipfs/config/addresses.rs @@ -2,16 +2,22 @@ use serde::{Serialize, Deserialize}; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Addresses{ + #[serde(default)] #[serde(alias = "API")] api:String, + #[serde(default)] #[serde(alias = "Announce")] announce:Vec, + #[serde(default)] #[serde(alias = "AppendAnnounce")] append_announce:Vec, + #[serde(default)] #[serde(alias = "Gateway")] gateway:String, + #[serde(default)] #[serde(alias = "NoAnounce")] no_anounce:Vec, + #[serde(default)] #[serde(alias = "Swarm")] swarm:Vec } \ No newline at end of file diff --git a/src/ipfs/config/API.rs b/src/ipfs/config/api.rs similarity index 54% rename from src/ipfs/config/API.rs rename to src/ipfs/config/api.rs index 9c4c0da..8889014 100644 --- a/src/ipfs/config/API.rs +++ b/src/ipfs/config/api.rs @@ -1,11 +1,8 @@ use serde::{Serialize, Deserialize}; +use serde_json::Value; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct API{ #[serde(alias = "HTTPHeaders")] - http_headers:HttpHeaders, -} -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct HttpHeaders{ - + http_headers:Value,//Note this a dynamic Value because the http header could be anything } \ No newline at end of file diff --git a/src/ipfs/config/AutoNAT.rs b/src/ipfs/config/auto_nat.rs similarity index 100% rename from src/ipfs/config/AutoNAT.rs rename to src/ipfs/config/auto_nat.rs diff --git a/src/ipfs/config/DNS.rs b/src/ipfs/config/datastore.rs similarity index 100% rename from src/ipfs/config/DNS.rs rename to src/ipfs/config/datastore.rs diff --git a/src/ipfs/config/Datastore.rs b/src/ipfs/config/discovery.rs similarity index 100% rename from src/ipfs/config/Datastore.rs rename to src/ipfs/config/discovery.rs diff --git a/src/ipfs/config/Discovery.rs b/src/ipfs/config/dns.rs similarity index 100% rename from src/ipfs/config/Discovery.rs rename to src/ipfs/config/dns.rs diff --git a/src/ipfs/config/Experimental.rs b/src/ipfs/config/experimental.rs similarity index 100% rename from src/ipfs/config/Experimental.rs rename to src/ipfs/config/experimental.rs diff --git a/src/ipfs/config/Gateway.rs b/src/ipfs/config/gateway.rs similarity index 100% rename from src/ipfs/config/Gateway.rs rename to src/ipfs/config/gateway.rs diff --git a/src/ipfs/config/Identity.rs b/src/ipfs/config/identity.rs similarity index 100% rename from src/ipfs/config/Identity.rs rename to src/ipfs/config/identity.rs diff --git a/src/ipfs/config/Ipns.rs b/src/ipfs/config/ipns.rs similarity index 100% rename from src/ipfs/config/Ipns.rs rename to src/ipfs/config/ipns.rs diff --git a/src/ipfs/config/Migration.rs b/src/ipfs/config/migration.rs similarity index 100% rename from src/ipfs/config/Migration.rs rename to src/ipfs/config/migration.rs diff --git a/src/ipfs/config/Mounts.rs b/src/ipfs/config/mounts.rs similarity index 100% rename from src/ipfs/config/Mounts.rs rename to src/ipfs/config/mounts.rs diff --git a/src/ipfs/config/Peering.rs b/src/ipfs/config/peering.rs similarity index 100% rename from src/ipfs/config/Peering.rs rename to src/ipfs/config/peering.rs diff --git a/src/ipfs/config/Pinning.rs b/src/ipfs/config/pinning.rs similarity index 100% rename from src/ipfs/config/Pinning.rs rename to src/ipfs/config/pinning.rs diff --git a/src/ipfs/config/Plugins.rs b/src/ipfs/config/plugins.rs similarity index 100% rename from src/ipfs/config/Plugins.rs rename to src/ipfs/config/plugins.rs diff --git a/src/ipfs/config/Provider.rs b/src/ipfs/config/provider.rs similarity index 100% rename from src/ipfs/config/Provider.rs rename to src/ipfs/config/provider.rs diff --git a/src/ipfs/config/Pubsub.rs b/src/ipfs/config/pubsub.rs similarity index 100% rename from src/ipfs/config/Pubsub.rs rename to src/ipfs/config/pubsub.rs diff --git a/src/ipfs/config/Reprovider.rs b/src/ipfs/config/reprovider.rs similarity index 100% rename from src/ipfs/config/Reprovider.rs rename to src/ipfs/config/reprovider.rs diff --git a/src/ipfs/config/Routing.rs b/src/ipfs/config/routing.rs similarity index 100% rename from src/ipfs/config/Routing.rs rename to src/ipfs/config/routing.rs diff --git a/src/ipfs/config/Swarm.rs b/src/ipfs/config/swarm.rs similarity index 100% rename from src/ipfs/config/Swarm.rs rename to src/ipfs/config/swarm.rs diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index c645017..57e5bab 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,12 +1,12 @@ use super::http::HttpRequest; use super::options::*; +use crate::ipfs::config::Config; use crate::ipfs::http::HttpHandler; use crate::ipfs::Ipfs; use crate::utils::*; use anyhow::{bail, Result}; use async_trait::async_trait; use colored::Colorize; -use futures::executor::block_on; use serde_json::Value; use std::collections::HashMap; use std::process::{Child, Command}; @@ -16,8 +16,7 @@ use std::time::{Duration, SystemTime}; pub struct IpfsViaDaemon { http: HttpHandler, ipfs_process: Child, - is_ipfs_ready: bool, - connected_peers: Vec, + is_ipfs_ready: bool } impl IpfsViaDaemon { pub fn new() -> Result { @@ -37,8 +36,7 @@ impl IpfsViaDaemon { anyhow::Ok(IpfsViaDaemon { ipfs_process: proccess, http: HttpHandler::new(), - is_ipfs_ready: false, - connected_peers: vec![], + is_ipfs_ready: false }) } async fn send_request(&mut self, options: &HttpRequest) -> Result> { @@ -201,37 +199,14 @@ impl Ipfs for IpfsViaDaemon { anyhow::Ok(hashes) } - async fn connect_to(&mut self, peer_id: &str) -> Result> { + async fn connect_to(&mut self, peer_id: &str) -> Result<()> { self.swarm_cmd("/swarm/connect", peer_id) .await?; - self.connected_peers.push(peer_id.to_string()); // print!("Connected Peers: "); // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); - anyhow::Ok(self.connected_peers.clone()) - } - - async fn disconect_from(&mut self, peer_id: &str) -> Result> { - self.swarm_cmd("/swarm/disconnect", peer_id) - .await?; - self.connected_peers = self - .connected_peers - .iter() - .filter_map(|peer_id_to_check| { - let checkable = peer_id_to_check.to_string(); - match peer_id != checkable { - true => Some(checkable), - false => None, - } - }) - .collect(); - print!("Connected Peers: "); - self.connected_peers - .iter() - .for_each(|peer| print!("{}, ", peer)); - anyhow::Ok(self.connected_peers.clone()) + anyhow::Ok(()) } - - async fn config(&mut self, options: &HashMap<&str, &str>) -> Result<()> { + async fn get_config(&mut self) -> Result{ let get_profile = HttpRequest::new( &(HttpRequest::get_ipfs_addr() + "/config/show"), &(HashMap::new()), @@ -239,27 +214,12 @@ impl Ipfs for IpfsViaDaemon { ); let profile_vec = self.send_request(&get_profile).await?; let profile_str = std::str::from_utf8(profile_vec.as_slice())?; - let mut profile: Value = serde_json::from_str(profile_str)?; - for (setting, value) in options { - let number_value = value.to_string().parse::(); - let bool_value = value.to_string().parse::(); - let json_value = serde_json::from_str::(value); - let value_parsed = match number_value { - Ok(v) => Value::Number(serde_json::Number::from_f64(v).unwrap()), - Err(_) => match bool_value { - Ok(v) => Value::Bool(v), - Err(_) => match json_value { - Ok(v) => v, - Err(_) => Value::String(value.to_string()), - }, - }, - }; - let location = setting.split(".").map(|s| s.to_string()); - profile = json::change_json_part(&profile, location, &value_parsed)?; - } - let json_str = profile.to_string(); - println!("{}", json_str.red()); + return Ok(serde_json::from_str(profile_str)?); + } + async fn set_config(&mut self, options: &Config) -> Result<()> { let args = HashMap::new(); + let addr = HttpRequest::get_ipfs_addr() + "/config/replace"; + let mut request = HttpRequest::new(&addr, &args, true); let headers = HashMap::from([ ( "Content-Disposition", @@ -267,10 +227,8 @@ impl Ipfs for IpfsViaDaemon { ), ("Content-Type", "application/octet-stream"), ]); - - let addr = HttpRequest::get_ipfs_addr() + "/config/replace"; - let mut request = HttpRequest::new(&addr, &args, true); - request.add_body(&headers, json_str.as_bytes()); + let body = serde_json::to_string(options)?; + request.add_body(&headers, body.as_bytes()); let response = self.send_request(&request).await?; let res_str = std::str::from_utf8(response.as_slice())?; if res_str.trim().is_empty() { @@ -285,9 +243,6 @@ impl Ipfs for IpfsViaDaemon { } impl Drop for IpfsViaDaemon { fn drop(&mut self) { - for peer in self.connected_peers.clone().iter() { - block_on(self.disconect_from(peer)).unwrap(); - } self.ipfs_process.kill().unwrap(); println!( "{}", @@ -300,6 +255,7 @@ impl Drop for IpfsViaDaemon { #[cfg(test)] mod tests { use crate::utils::file_management; + use crate::ipfs::{Config, config}; use futures::executor::block_on; use std::collections::HashMap; // use anyhow::Result; @@ -307,6 +263,7 @@ mod tests { use super::*; use serial_test::serial; + //TODO: Setup pizza const PEER_ADDRS:&'static [&'static str] = &[ "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", @@ -327,10 +284,8 @@ mod tests { fn connect_to_peers() -> IpfsViaDaemon { let mut ipfs = IpfsViaDaemon::new().unwrap(); for peer in PEER_ADDRS { - let result_peers = block_on(ipfs.connect_to(peer)).unwrap(); - for result_peer in result_peers { - println!("Connected to peer! {}", result_peer); - } + block_on(ipfs.connect_to(peer)).unwrap(); + println!("Connected to peer! {}", peer); } return ipfs; } @@ -387,16 +342,13 @@ mod tests { #[serial] fn can_config() { let mut ipfs = IpfsViaDaemon::new().unwrap(); - block_on(ipfs.config(&HashMap::from([ - ("Datastore.StorageMax", "11GB"), - ("Datastore.GCPeriod", "2h"), - ]))) - .unwrap(); - block_on(ipfs.config(&HashMap::from([ - ("Datastore.StorageMax", "10GB"), - ("Datastore.GCPeriod", "1h"), - ]))) - .unwrap(); + let mut config = block_on(ipfs.get_config()).unwrap(); + config.datastore.as_object_mut().unwrap().insert("StorageMax".to_string(), Value::String("11GB".to_string())); + config.datastore.as_object_mut().unwrap().insert("GCPeriod".to_string(), Value::String("2h".to_string())); + block_on(ipfs.set_config(&config)).unwrap(); + config.datastore.as_object_mut().unwrap().insert("StorageMax".to_string(), Value::String("10GB".to_string())); + config.datastore.as_object_mut().unwrap().insert("GCPeriod".to_string(), Value::String("1h".to_string())); + block_on(ipfs.set_config(&config)).unwrap(); assert!(true) } } From c95cf61351971bde4a06a3127f5b34bf80d710d9 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Tue, 6 Dec 2022 11:26:37 -0800 Subject: [PATCH 41/63] Update import formatting --- src/ipfs.rs | 5 +--- src/ipfs/config.rs | 2 ++ src/ipfs/config/api.rs | 2 +- src/ipfs/daemon.rs | 33 ++++++++++++++---------- src/ipfs/http.rs | 8 +++--- src/utils.rs | 1 + src/{ipfs/options.rs => utils/config.rs} | 0 src/utils/file_management.rs | 4 +-- src/utils/json.rs | 2 +- src/utils/math.rs | 4 +-- 10 files changed, 34 insertions(+), 27 deletions(-) rename src/{ipfs/options.rs => utils/config.rs} (100%) diff --git a/src/ipfs.rs b/src/ipfs.rs index 17601cb..11a95de 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -1,15 +1,12 @@ -//use std::collections::{HashMap, btree_map::OccupiedError}; - -use async_trait::async_trait; use std::collections::HashMap; use anyhow::Result; +use async_trait::async_trait; use self::config::Config; pub mod daemon; pub mod http; -pub mod options; pub mod config; #[async_trait] diff --git a/src/ipfs/config.rs b/src/ipfs/config.rs index 0d16175..ed2fa87 100644 --- a/src/ipfs/config.rs +++ b/src/ipfs/config.rs @@ -91,6 +91,8 @@ pub struct Config{ /* +Example IPFS Config + { "API":{ "HTTPHeaders":{ diff --git a/src/ipfs/config/api.rs b/src/ipfs/config/api.rs index 8889014..1a1aaf8 100644 --- a/src/ipfs/config/api.rs +++ b/src/ipfs/config/api.rs @@ -4,5 +4,5 @@ use serde_json::Value; #[derive(Clone, Debug, Serialize, Deserialize)] pub struct API{ #[serde(alias = "HTTPHeaders")] - http_headers:Value,//Note this a dynamic Value because the http header could be anything + http_headers:Value, // Note this a dynamic Value because the http header could be anything } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 57e5bab..fa7f70b 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,17 +1,22 @@ -use super::http::HttpRequest; -use super::options::*; -use crate::ipfs::config::Config; -use crate::ipfs::http::HttpHandler; -use crate::ipfs::Ipfs; -use crate::utils::*; +use std::{ + collections::HashMap, + process::{Child, Command}, + thread::sleep, + time::{Duration, SystemTime} +}; + use anyhow::{bail, Result}; use async_trait::async_trait; use colored::Colorize; use serde_json::Value; -use std::collections::HashMap; -use std::process::{Child, Command}; -use std::thread::sleep; -use std::time::{Duration, SystemTime}; + +use crate::ipfs::{ + config::Config, + http::{HttpHandler, HttpRequest}, + Ipfs +}; +use crate::utils::*; + pub struct IpfsViaDaemon { http: HttpHandler, @@ -21,8 +26,8 @@ pub struct IpfsViaDaemon { impl IpfsViaDaemon { pub fn new() -> Result { println!("{}", "Starting ipfs...".green()); - let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); - let proccess = Command::new(IPFS_EXE) + let api_addr = format!("/ip4/{}/tcp/{}", config::IPFS_ADDR, config::IPFS_API_PORT); + let proccess = Command::new(config::IPFS_EXE) .arg("--api") .arg(&api_addr) .arg("daemon") @@ -68,10 +73,10 @@ impl IpfsViaDaemon { break; } - sleep(Duration::new(SLEEP_LENGTH as u64, 0)); + sleep(Duration::new(config::SLEEP_LENGTH as u64, 0)); let now = SystemTime::now(); - if now.duration_since(start_time)? > Duration::new(BOOT_TIME_OUT as u64, 0) { + if now.duration_since(start_time)? > Duration::new(config::BOOT_TIME_OUT as u64, 0) { bail!( "{}", "Failed to start ipfs because the timeout reached!!".red() diff --git a/src/ipfs/http.rs b/src/ipfs/http.rs index bf42a43..334057b 100644 --- a/src/ipfs/http.rs +++ b/src/ipfs/http.rs @@ -13,9 +13,11 @@ use hyper::{ client::HttpConnector, body::HttpBody }; -use crate::utils::math; -use super::options::*; +use crate::utils::{ + config::*, + math +}; pub struct PostOptions { @@ -135,7 +137,7 @@ impl HttpHandler { 'attempt_loop: loop { attempt += 1; if attempt != 1 { - std::thread::sleep(Duration::new(math::get_fibinaci(attempt), 0)) + std::thread::sleep(Duration::new(math::get_fibonacci(attempt), 0)) } println!("attempting to send post request: attempt {} of {}", attempt, IPFS_RETRY_ATTEMPTS); let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS as u32; diff --git a/src/utils.rs b/src/utils.rs index 3274b85..4d65f18 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,4 @@ +pub mod config; pub mod file_management; pub mod json; pub mod math; diff --git a/src/ipfs/options.rs b/src/utils/config.rs similarity index 100% rename from src/ipfs/options.rs rename to src/utils/config.rs diff --git a/src/utils/file_management.rs b/src/utils/file_management.rs index d8aad66..d791085 100644 --- a/src/utils/file_management.rs +++ b/src/utils/file_management.rs @@ -1,8 +1,8 @@ - -use walkdir::WalkDir; use std::collections::HashMap; + use anyhow::{Result, bail}; use colored::Colorize; +use walkdir::WalkDir; //TODO: This needs to move to utils pub fn get_files_in(dir:&str) -> Result>> { diff --git a/src/utils/json.rs b/src/utils/json.rs index 967bfb6..25925e9 100644 --- a/src/utils/json.rs +++ b/src/utils/json.rs @@ -1,5 +1,5 @@ -use serde_json::{Map, Value}; use anyhow::{Result, bail}; +use serde_json::{Map, Value}; /* Ipfs often returns json with a single property with the value being an array. diff --git a/src/utils/math.rs b/src/utils/math.rs index 2f3f8e0..ded5b71 100644 --- a/src/utils/math.rs +++ b/src/utils/math.rs @@ -1,6 +1,6 @@ -pub fn get_fibinaci(n:u32) -> u64{ +pub fn get_fibonacci(n:u32) -> u64{ if n <= 1 { return n as u64; } - return get_fibinaci(n - 1) + get_fibinaci(n - 2); + return get_fibonacci(n - 1) + get_fibonacci(n - 2); } \ No newline at end of file From 1ec8e4fd2fed2ef129149708669139376b3a0930 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Tue, 6 Dec 2022 11:38:14 -0800 Subject: [PATCH 42/63] Rename IPFS Daemon --- src/ipfs/daemon.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index fa7f70b..3400487 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -18,13 +18,13 @@ use crate::ipfs::{ use crate::utils::*; -pub struct IpfsViaDaemon { +pub struct IpfsDaemon { http: HttpHandler, ipfs_process: Child, is_ipfs_ready: bool } -impl IpfsViaDaemon { - pub fn new() -> Result { +impl IpfsDaemon { + pub fn new() -> Result { println!("{}", "Starting ipfs...".green()); let api_addr = format!("/ip4/{}/tcp/{}", config::IPFS_ADDR, config::IPFS_API_PORT); let proccess = Command::new(config::IPFS_EXE) @@ -38,7 +38,7 @@ impl IpfsViaDaemon { "{}", ("⚠️ Warning: Ipfs Proccess Started. Please do NOT force close this app⚠️".yellow()) ); - anyhow::Ok(IpfsViaDaemon { + anyhow::Ok(IpfsDaemon { ipfs_process: proccess, http: HttpHandler::new(), is_ipfs_ready: false @@ -151,7 +151,7 @@ impl IpfsViaDaemon { } } #[async_trait] -impl Ipfs for IpfsViaDaemon { +impl Ipfs for IpfsDaemon { async fn add_file(&mut self, path: &str) -> Result> { let cmd = HttpRequest::get_ipfs_addr() + "/add"; let args = HashMap::from([("quieter", "true"), ("cid-version", "1"), ("path", &path)]); @@ -246,7 +246,7 @@ impl Ipfs for IpfsViaDaemon { } } } -impl Drop for IpfsViaDaemon { +impl Drop for IpfsDaemon { fn drop(&mut self) { self.ipfs_process.kill().unwrap(); println!( @@ -286,8 +286,8 @@ mod tests { "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", ]; - fn connect_to_peers() -> IpfsViaDaemon { - let mut ipfs = IpfsViaDaemon::new().unwrap(); + fn connect_to_peers() -> IpfsDaemon { + let mut ipfs = IpfsDaemon::new().unwrap(); for peer in PEER_ADDRS { block_on(ipfs.connect_to(peer)).unwrap(); println!("Connected to peer! {}", peer); @@ -346,7 +346,7 @@ mod tests { #[test] #[serial] fn can_config() { - let mut ipfs = IpfsViaDaemon::new().unwrap(); + let mut ipfs = IpfsDaemon::new().unwrap(); let mut config = block_on(ipfs.get_config()).unwrap(); config.datastore.as_object_mut().unwrap().insert("StorageMax".to_string(), Value::String("11GB".to_string())); config.datastore.as_object_mut().unwrap().insert("GCPeriod".to_string(), Value::String("2h".to_string())); From d16023b97a8e4271f44decbfa11dca8bd09c6a54 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 6 Dec 2022 13:20:53 -0800 Subject: [PATCH 43/63] Handle null values in config --- src/ipfs/config/addresses.rs | 4 ++-- src/ipfs/daemon.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ipfs/config/addresses.rs b/src/ipfs/config/addresses.rs index 69483bb..947b9d1 100644 --- a/src/ipfs/config/addresses.rs +++ b/src/ipfs/config/addresses.rs @@ -10,13 +10,13 @@ pub struct Addresses{ announce:Vec, #[serde(default)] #[serde(alias = "AppendAnnounce")] - append_announce:Vec, + append_announce:Option>, #[serde(default)] #[serde(alias = "Gateway")] gateway:String, #[serde(default)] #[serde(alias = "NoAnounce")] - no_anounce:Vec, + no_anounce:Option>, #[serde(default)] #[serde(alias = "Swarm")] swarm:Vec diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 3400487..e1fcdd6 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -219,6 +219,7 @@ impl Ipfs for IpfsDaemon { ); let profile_vec = self.send_request(&get_profile).await?; let profile_str = std::str::from_utf8(profile_vec.as_slice())?; + // println!("{}", profile_str.red()); return Ok(serde_json::from_str(profile_str)?); } async fn set_config(&mut self, options: &Config) -> Result<()> { From 1c963b5922e4c6d5109237dceaecfd77c3dbc940 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Tue, 6 Dec 2022 13:36:00 -0800 Subject: [PATCH 44/63] Separate out daemon tests into a module --- src/ipfs.rs | 3 ++ src/ipfs/daemon.rs | 103 +---------------------------------------- src/ipfs/tests.rs | 113 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 117 insertions(+), 102 deletions(-) create mode 100644 src/ipfs/tests.rs diff --git a/src/ipfs.rs b/src/ipfs.rs index 11a95de..e6bd2b6 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -9,6 +9,9 @@ pub mod daemon; pub mod http; pub mod config; +#[cfg(test)] +pub mod tests; + #[async_trait] pub trait Ipfs { async fn add_file(&mut self, path:&str) -> Result>; diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index e1fcdd6..752cbe9 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -256,105 +256,4 @@ impl Drop for IpfsDaemon { .bright_green()) ) } -} - -#[cfg(test)] -mod tests { - use crate::utils::file_management; - use crate::ipfs::{Config, config}; - use futures::executor::block_on; - use std::collections::HashMap; - // use anyhow::Result; - // use proptest::prelude::*; - use super::*; - use serial_test::serial; - - - //TODO: Setup pizza - const PEER_ADDRS:&'static [&'static str] = &[ - "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", - "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", - "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4001/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", - "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/ip4/54.235.17.70/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/ip4/54.235.17.70/udp/4001/quic/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4001/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", - "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4001/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", - "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4001/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", - "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", - "/ip4/54.235.17.70/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", - ]; - - fn connect_to_peers() -> IpfsDaemon { - let mut ipfs = IpfsDaemon::new().unwrap(); - for peer in PEER_ADDRS { - block_on(ipfs.connect_to(peer)).unwrap(); - println!("Connected to peer! {}", peer); - } - return ipfs; - } - - #[test] - #[serial] - fn can_add_directory() { - let test_dir = "./test-dir/more-tests"; - let mut ipfs = connect_to_peers(); - let hashes = block_on(ipfs.add_directory(test_dir)).unwrap(); - println!("{}", "Finnished Hashes:".green()); - for (path, hash) in &hashes { - println!("{}: {}", path.green(), hash.blue()) - } - - let files = file_management::get_files_in(test_dir).unwrap(); - let folders = file_management::get_dirs_in(test_dir).unwrap(); - - files - .iter() - .map(|(path, _)| path) - .chain(folders.iter()) - .for_each(|path_to_match| { - let fixed_path_to_match: String = path_to_match - .split("/") - .filter(|seg| seg != &"." && !seg.is_empty()) - .map(|seg| "/".to_string() + seg) - .collect(); - assert!(hashes - .iter() - .any(|(path, _)| fixed_path_to_match == path.to_owned())) - }); - } - #[test] - #[serial] - fn can_add_file() { - let test_file = "./test-dir/test.txt"; - let mut ipfs = connect_to_peers(); - let hashes = block_on(ipfs.add_file(test_file)).unwrap(); - println!("{}", "Finnished Hashes:\n".green()); - for (path, hash) in &hashes { - println!("{}: {}", path.green(), hash.blue()) - } - let matchable_path: String = test_file - .split("/") - .filter(|seg| seg != &"." && !seg.is_empty()) - .map(|seg| "/".to_string() + seg) - .collect(); - assert!(hashes - .iter() - .any(|(path, _)| matchable_path == path.to_owned())); - } - #[test] - #[serial] - fn can_config() { - let mut ipfs = IpfsDaemon::new().unwrap(); - let mut config = block_on(ipfs.get_config()).unwrap(); - config.datastore.as_object_mut().unwrap().insert("StorageMax".to_string(), Value::String("11GB".to_string())); - config.datastore.as_object_mut().unwrap().insert("GCPeriod".to_string(), Value::String("2h".to_string())); - block_on(ipfs.set_config(&config)).unwrap(); - config.datastore.as_object_mut().unwrap().insert("StorageMax".to_string(), Value::String("10GB".to_string())); - config.datastore.as_object_mut().unwrap().insert("GCPeriod".to_string(), Value::String("1h".to_string())); - block_on(ipfs.set_config(&config)).unwrap(); - assert!(true) - } -} +} \ No newline at end of file diff --git a/src/ipfs/tests.rs b/src/ipfs/tests.rs new file mode 100644 index 0000000..2d8a5a7 --- /dev/null +++ b/src/ipfs/tests.rs @@ -0,0 +1,113 @@ +use colored::Colorize; +use futures::executor::block_on; +use serde_json::Value; +use serial_test::serial; + +use self::daemon::IpfsDaemon; +use super::*; +use crate::ipfs::Ipfs; +use crate::utils::file_management; + +//TODO: Setup pizza +const PEER_ADDRS:&'static [&'static str] = &[ + "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", + "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", + "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4001/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", + "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/ip4/54.235.17.70/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/ip4/54.235.17.70/udp/4001/quic/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4001/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", + "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4001/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", + "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4001/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", + "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", + "/ip4/54.235.17.70/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", + "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", + ]; + +fn connect_to_peers() -> IpfsDaemon { + let mut ipfs = IpfsDaemon::new().unwrap(); + for peer in PEER_ADDRS { + block_on(ipfs.connect_to(peer)).unwrap(); + println!("Connected to peer! {}", peer); + } + return ipfs; +} + +#[test] +#[serial] +fn can_add_directory() { + let test_dir = "./test-dir/more-tests"; + let mut ipfs = connect_to_peers(); + let hashes = block_on(ipfs.add_directory(test_dir)).unwrap(); + println!("{}", "Finnished Hashes:".green()); + for (path, hash) in &hashes { + println!("{}: {}", path.green(), hash.blue()) + } + + let files = file_management::get_files_in(test_dir).unwrap(); + let folders = file_management::get_dirs_in(test_dir).unwrap(); + + files + .iter() + .map(|(path, _)| path) + .chain(folders.iter()) + .for_each(|path_to_match| { + let fixed_path_to_match: String = path_to_match + .split("/") + .filter(|seg| seg != &"." && !seg.is_empty()) + .map(|seg| "/".to_string() + seg) + .collect(); + assert!(hashes + .iter() + .any(|(path, _)| fixed_path_to_match == path.to_owned())) + }); +} +#[test] +#[serial] +fn can_add_file() { + let test_file = "./test-dir/test.txt"; + let mut ipfs = connect_to_peers(); + let hashes = block_on(ipfs.add_file(test_file)).unwrap(); + println!("{}", "Finnished Hashes:\n".green()); + for (path, hash) in &hashes { + println!("{}: {}", path.green(), hash.blue()) + } + let matchable_path: String = test_file + .split("/") + .filter(|seg| seg != &"." && !seg.is_empty()) + .map(|seg| "/".to_string() + seg) + .collect(); + assert!(hashes + .iter() + .any(|(path, _)| matchable_path == path.to_owned())); +} +#[test] +#[serial] +fn can_config() { + let mut ipfs = IpfsDaemon::new().unwrap(); + let mut config = block_on(ipfs.get_config()).unwrap(); + config + .datastore + .as_object_mut() + .unwrap() + .insert("StorageMax".to_string(), Value::String("11GB".to_string())); + config + .datastore + .as_object_mut() + .unwrap() + .insert("GCPeriod".to_string(), Value::String("2h".to_string())); + block_on(ipfs.set_config(&config)).unwrap(); + config + .datastore + .as_object_mut() + .unwrap() + .insert("StorageMax".to_string(), Value::String("10GB".to_string())); + config + .datastore + .as_object_mut() + .unwrap() + .insert("GCPeriod".to_string(), Value::String("1h".to_string())); + block_on(ipfs.set_config(&config)).unwrap(); + assert!(true) +} From 719f91ded68194fc41d9d46c2d145c12dac1094e Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Tue, 6 Dec 2022 13:55:17 -0800 Subject: [PATCH 45/63] Move http module to utils --- src/ipfs.rs | 1 - src/ipfs/daemon.rs | 33 +++++++++++++++++++++------------ src/utils.rs | 3 ++- src/utils/config.rs | 4 ++-- src/{ipfs => utils}/http.rs | 3 --- 5 files changed, 25 insertions(+), 19 deletions(-) rename src/{ipfs => utils}/http.rs (98%) diff --git a/src/ipfs.rs b/src/ipfs.rs index e6bd2b6..fdb3df3 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -6,7 +6,6 @@ use async_trait::async_trait; use self::config::Config; pub mod daemon; -pub mod http; pub mod config; #[cfg(test)] diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 752cbe9..e2f978a 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -12,10 +12,15 @@ use serde_json::Value; use crate::ipfs::{ config::Config, - http::{HttpHandler, HttpRequest}, Ipfs }; -use crate::utils::*; + +use crate::utils::{ + config::{IPFS_BOOT_TIME_OUT, IPFS_ADDR, IPFS_API_PORT, IPFS_EXE, IPFS_SLEEP_LENGTH}, + file_management, + http::{HttpHandler, HttpRequest}, + json +}; pub struct IpfsDaemon { @@ -26,8 +31,8 @@ pub struct IpfsDaemon { impl IpfsDaemon { pub fn new() -> Result { println!("{}", "Starting ipfs...".green()); - let api_addr = format!("/ip4/{}/tcp/{}", config::IPFS_ADDR, config::IPFS_API_PORT); - let proccess = Command::new(config::IPFS_EXE) + let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); + let proccess = Command::new(IPFS_EXE) .arg("--api") .arg(&api_addr) .arg("daemon") @@ -73,10 +78,10 @@ impl IpfsDaemon { break; } - sleep(Duration::new(config::SLEEP_LENGTH as u64, 0)); + sleep(Duration::new(IPFS_SLEEP_LENGTH as u64, 0)); let now = SystemTime::now(); - if now.duration_since(start_time)? > Duration::new(config::BOOT_TIME_OUT as u64, 0) { + if now.duration_since(start_time)? > Duration::new(IPFS_BOOT_TIME_OUT as u64, 0) { bail!( "{}", "Failed to start ipfs because the timeout reached!!".red() @@ -87,7 +92,7 @@ impl IpfsDaemon { } async fn poll_ipfs_ready(&mut self) -> bool { let args = HashMap::new(); - let addr = HttpRequest::get_ipfs_addr() + "/config/show"; + let addr = Self::get_ipfs_addr() + "/config/show"; let cmd = HttpRequest::new(&addr, &args, false); let response = self.http.send_request(&cmd).await; return match response { @@ -101,7 +106,7 @@ impl IpfsDaemon { //TODO: Better name? async fn swarm_cmd(&mut self, cmd: &str, peer_id: &str) -> Result> { let args = HashMap::from([("arg", peer_id)]); - let addr = HttpRequest::get_ipfs_addr() + cmd; + let addr = Self::get_ipfs_addr() + cmd; let cmd_options = HttpRequest::new(&addr, &args, false); let result_data = self.send_request(&cmd_options).await?; let result_str = std::str::from_utf8(result_data.as_slice())?; @@ -149,11 +154,15 @@ impl IpfsDaemon { ret.insert(path, hash); }; } + + fn get_ipfs_addr() -> String { + format!("http://{}:{}/api/v0", IPFS_ADDR, IPFS_API_PORT) + } } #[async_trait] impl Ipfs for IpfsDaemon { async fn add_file(&mut self, path: &str) -> Result> { - let cmd = HttpRequest::get_ipfs_addr() + "/add"; + let cmd = Self::get_ipfs_addr() + "/add"; let args = HashMap::from([("quieter", "true"), ("cid-version", "1"), ("path", &path)]); let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &path); let headers = HashMap::from([ @@ -170,7 +179,7 @@ impl Ipfs for IpfsDaemon { } async fn add_directory(&mut self, path: &str) -> Result> { - let cmd = HttpRequest::get_ipfs_addr() + "/add"; + let cmd = Self::get_ipfs_addr() + "/add"; let args = HashMap::from([("quieter", "true"), ("cid-version", "1")]); let mut request = HttpRequest::new(&cmd, &args, true); println!("{}", "Adding the following directories..".blue()); @@ -213,7 +222,7 @@ impl Ipfs for IpfsDaemon { } async fn get_config(&mut self) -> Result{ let get_profile = HttpRequest::new( - &(HttpRequest::get_ipfs_addr() + "/config/show"), + &(Self::get_ipfs_addr() + "/config/show"), &(HashMap::new()), false, ); @@ -224,7 +233,7 @@ impl Ipfs for IpfsDaemon { } async fn set_config(&mut self, options: &Config) -> Result<()> { let args = HashMap::new(); - let addr = HttpRequest::get_ipfs_addr() + "/config/replace"; + let addr = Self::get_ipfs_addr() + "/config/replace"; let mut request = HttpRequest::new(&addr, &args, true); let headers = HashMap::from([ ( diff --git a/src/utils.rs b/src/utils.rs index 4d65f18..2dfea19 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,6 @@ pub mod config; pub mod file_management; +pub mod http; pub mod json; -pub mod math; pub mod log; +pub mod math; diff --git a/src/utils/config.rs b/src/utils/config.rs index 3fe7629..37f3a95 100644 --- a/src/utils/config.rs +++ b/src/utils/config.rs @@ -3,5 +3,5 @@ pub const IPFS_RETRY_ATTEMPTS:u16 = 4; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const HTTP_BOUNDARY:&str = "------------------------I_am_a_boundary_123A123"; -pub const BOOT_TIME_OUT:u16 = 45;//In seconds -pub const SLEEP_LENGTH:u8 = 1;//In seconds \ No newline at end of file +pub const IPFS_BOOT_TIME_OUT:u16 = 45;//In seconds +pub const IPFS_SLEEP_LENGTH:u8 = 1;//In seconds \ No newline at end of file diff --git a/src/ipfs/http.rs b/src/utils/http.rs similarity index 98% rename from src/ipfs/http.rs rename to src/utils/http.rs index 334057b..e6abb94 100644 --- a/src/ipfs/http.rs +++ b/src/utils/http.rs @@ -55,9 +55,6 @@ impl HttpRequest { false => format!("{}?{}", self.addr, arg_str) } } - pub fn get_ipfs_addr() -> String { - format!("http://{}:{}/api/v0", IPFS_ADDR, IPFS_API_PORT) - } } pub struct HttpHandler{ From c746cc0bf4555769ac7f1c5a2a814acdba20d386 Mon Sep 17 00:00:00 2001 From: Brian Ginsburg Date: Tue, 6 Dec 2022 13:58:38 -0800 Subject: [PATCH 46/63] Add whitespace --- src/ipfs/daemon.rs | 10 ++++++++++ src/utils/http.rs | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index e2f978a..8a7e2b4 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -28,6 +28,7 @@ pub struct IpfsDaemon { ipfs_process: Child, is_ipfs_ready: bool } + impl IpfsDaemon { pub fn new() -> Result { println!("{}", "Starting ipfs...".green()); @@ -49,6 +50,7 @@ impl IpfsDaemon { is_ipfs_ready: false }) } + async fn send_request(&mut self, options: &HttpRequest) -> Result> { self.await_ready().await?; let result = self @@ -64,6 +66,7 @@ impl IpfsDaemon { .await?; anyhow::Ok(result) //it always return Some if a handler is given } + async fn await_ready(&mut self) -> Result<()> { if self.is_ipfs_ready == true { return anyhow::Ok(()); @@ -90,6 +93,7 @@ impl IpfsDaemon { } anyhow::Ok(()) } + async fn poll_ipfs_ready(&mut self) -> bool { let args = HashMap::new(); let addr = Self::get_ipfs_addr() + "/config/show"; @@ -103,6 +107,7 @@ impl IpfsDaemon { } }; } + //TODO: Better name? async fn swarm_cmd(&mut self, cmd: &str, peer_id: &str) -> Result> { let args = HashMap::from([("arg", peer_id)]); @@ -128,6 +133,7 @@ impl IpfsDaemon { return anyhow::Ok(peer_list); } + fn response_to_hashes(response: &str) -> Result> { let mut res = response.to_string(); let mut ret = HashMap::new(); @@ -159,6 +165,7 @@ impl IpfsDaemon { format!("http://{}:{}/api/v0", IPFS_ADDR, IPFS_API_PORT) } } + #[async_trait] impl Ipfs for IpfsDaemon { async fn add_file(&mut self, path: &str) -> Result> { @@ -220,6 +227,7 @@ impl Ipfs for IpfsDaemon { // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); anyhow::Ok(()) } + async fn get_config(&mut self) -> Result{ let get_profile = HttpRequest::new( &(Self::get_ipfs_addr() + "/config/show"), @@ -231,6 +239,7 @@ impl Ipfs for IpfsDaemon { // println!("{}", profile_str.red()); return Ok(serde_json::from_str(profile_str)?); } + async fn set_config(&mut self, options: &Config) -> Result<()> { let args = HashMap::new(); let addr = Self::get_ipfs_addr() + "/config/replace"; @@ -256,6 +265,7 @@ impl Ipfs for IpfsDaemon { } } } + impl Drop for IpfsDaemon { fn drop(&mut self) { self.ipfs_process.kill().unwrap(); diff --git a/src/utils/http.rs b/src/utils/http.rs index e6abb94..ed61e6a 100644 --- a/src/utils/http.rs +++ b/src/utils/http.rs @@ -24,12 +24,14 @@ pub struct PostOptions { pub headers:HashMap, pub body: Vec } + pub struct HttpRequest { pub addr: String, pub args: HashMap, pub is_multipart:bool, post_options: Vec//TODO: Better name? } + impl HttpRequest { pub fn new(addr: &str, args: &HashMap<&str, &str>, is_multipart:bool) -> Self{ let owned_args:HashMap = args.iter() @@ -61,6 +63,7 @@ pub struct HttpHandler{ http_client:Client, tokio:Runtime } + impl HttpHandler { pub fn new() -> HttpHandler{ let client = Client::new(); @@ -128,6 +131,7 @@ impl HttpHandler { anyhow::Ok(response_data) } + pub async fn try_send_request(&mut self, options:&HttpRequest, handler_option:Option) -> Result> where F: Fn(Vec) -> Result{ let mut attempt:u32 = 0; From 97f91df83d3503f1351ea2593e19c301621af8cd Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Thu, 15 Dec 2022 13:38:33 -0600 Subject: [PATCH 47/63] Starting to move to ipfs-api llib saving work.. --- Cargo.lock | 362 +++++++++++++++++++++++++++++++- Cargo.toml | 1 + src/ipfs.rs | 15 +- src/ipfs/config.rs | 291 ------------------------- src/ipfs/config/addresses.rs | 23 -- src/ipfs/config/api.rs | 8 - src/ipfs/config/auto_nat.rs | 0 src/ipfs/config/datastore.rs | 0 src/ipfs/config/discovery.rs | 0 src/ipfs/config/dns.rs | 0 src/ipfs/config/experimental.rs | 0 src/ipfs/config/gateway.rs | 0 src/ipfs/config/identity.rs | 0 src/ipfs/config/ipns.rs | 0 src/ipfs/config/migration.rs | 0 src/ipfs/config/mounts.rs | 0 src/ipfs/config/peering.rs | 0 src/ipfs/config/pinning.rs | 0 src/ipfs/config/plugins.rs | 0 src/ipfs/config/provider.rs | 0 src/ipfs/config/pubsub.rs | 0 src/ipfs/config/reprovider.rs | 0 src/ipfs/config/routing.rs | 0 src/ipfs/config/swarm.rs | 0 src/ipfs/daemon.rs | 323 ++++++++-------------------- src/ipfs/tests.rs | 175 ++++++++------- src/utils.rs | 1 - src/utils/file_management.rs | 19 -- src/utils/http.rs | 33 --- src/utils/json.rs | 9 +- src/utils/log.rs | 53 ----- 31 files changed, 566 insertions(+), 747 deletions(-) delete mode 100644 src/ipfs/config.rs delete mode 100644 src/ipfs/config/addresses.rs delete mode 100644 src/ipfs/config/api.rs delete mode 100644 src/ipfs/config/auto_nat.rs delete mode 100644 src/ipfs/config/datastore.rs delete mode 100644 src/ipfs/config/discovery.rs delete mode 100644 src/ipfs/config/dns.rs delete mode 100644 src/ipfs/config/experimental.rs delete mode 100644 src/ipfs/config/gateway.rs delete mode 100644 src/ipfs/config/identity.rs delete mode 100644 src/ipfs/config/ipns.rs delete mode 100644 src/ipfs/config/migration.rs delete mode 100644 src/ipfs/config/mounts.rs delete mode 100644 src/ipfs/config/peering.rs delete mode 100644 src/ipfs/config/pinning.rs delete mode 100644 src/ipfs/config/plugins.rs delete mode 100644 src/ipfs/config/provider.rs delete mode 100644 src/ipfs/config/pubsub.rs delete mode 100644 src/ipfs/config/reprovider.rs delete mode 100644 src/ipfs/config/routing.rs delete mode 100644 src/ipfs/config/swarm.rs delete mode 100644 src/utils/log.rs diff --git a/Cargo.lock b/Cargo.lock index ad497c1..1d24de9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,6 +75,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" +[[package]] +name = "base-x" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" + [[package]] name = "base64" version = "0.12.3" @@ -255,6 +261,22 @@ dependencies = [ "winapi", ] +[[package]] +name = "common-multipart-rfc7578" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baee326bc603965b0f26583e1ecd7c111c41b49bd92a344897476a352798869" +dependencies = [ + "bytes", + "futures-core", + "futures-util", + "http", + "mime", + "mime_guess", + "rand 0.8.5", + "thiserror", +] + [[package]] name = "const-oid" version = "0.6.2" @@ -358,6 +380,32 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb" + +[[package]] +name = "data-encoding-macro" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86927b7cd2fe88fa698b87404b287ab98d1a0063a34071d92e575b72d3029aca" +dependencies = [ + "data-encoding", + "data-encoding-macro-internal", +] + +[[package]] +name = "data-encoding-macro-internal" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5bbed42daaa95e780b60a50546aa345b8413a1e46f9a40a12907d3598f038db" +dependencies = [ + "data-encoding", + "syn", +] + [[package]] name = "der" version = "0.4.5" @@ -409,6 +457,26 @@ dependencies = [ "generic-array", ] +[[package]] +name = "dirs" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + [[package]] name = "ecdsa" version = "0.12.4" @@ -515,6 +583,7 @@ dependencies = [ "did-key", "futures", "hyper", + "ipfs-api-backend-hyper", "proptest", "serde", "serde_json", @@ -706,7 +775,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.7.4", "tracing", ] @@ -852,6 +921,29 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-multipart-rfc7578" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0eb2cf73e96e9925f4bed948e763aa2901c2f1a3a5f713ee41917433ced6671" +dependencies = [ + "bytes", + "common-multipart-rfc7578", + "futures-core", + "http", + "hyper", +] + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "indexmap" version = "1.9.1" @@ -871,6 +963,47 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "ipfs-api-backend-hyper" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "114341e043a87eff0e43ec192f0a495988323dc14c468448e62b20aaf96bd1e6" +dependencies = [ + "async-trait", + "bytes", + "futures", + "http", + "hyper", + "hyper-multipart-rfc7578", + "ipfs-api-prelude", + "thiserror", +] + +[[package]] +name = "ipfs-api-prelude" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf47fa129710ae041d5844a15b1365bdad8551673aee237449ba9dec6bcadc" +dependencies = [ + "async-trait", + "bytes", + "cfg-if", + "common-multipart-rfc7578", + "dirs", + "futures", + "http", + "multibase", + "parity-multiaddr", + "serde", + "serde_json", + "serde_urlencoded", + "thiserror", + "tokio", + "tokio-util 0.6.10", + "tracing", + "walkdir", +] + [[package]] name = "itoa" version = "1.0.4" @@ -971,6 +1104,22 @@ version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "mime" +version = "0.3.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" + +[[package]] +name = "mime_guess" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" +dependencies = [ + "mime", + "unicase", +] + [[package]] name = "mio" version = "0.8.5" @@ -983,6 +1132,42 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "multibase" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b3539ec3c1f04ac9748a260728e855f261b4977f5c3406612c884564f329404" +dependencies = [ + "base-x", + "data-encoding", + "data-encoding-macro", +] + +[[package]] +name = "multihash" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab" +dependencies = [ + "generic-array", + "multihash-derive", + "unsigned-varint 0.5.1", +] + +[[package]] +name = "multihash-derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99" +dependencies = [ + "proc-macro-crate", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", + "synstructure", +] + [[package]] name = "nb" version = "0.1.3" @@ -1064,6 +1249,24 @@ dependencies = [ "group 0.11.0", ] +[[package]] +name = "parity-multiaddr" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58341485071825827b7f03cf7efd1cb21e6a709bea778fb50227fd45d2f361b4" +dependencies = [ + "arrayref", + "bs58", + "byteorder", + "data-encoding", + "multihash", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint 0.7.1", + "url", +] + [[package]] name = "parking_lot" version = "0.12.1" @@ -1121,6 +1324,17 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +[[package]] +name = "proc-macro-crate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +dependencies = [ + "once_cell", + "thiserror", + "toml", +] + [[package]] name = "proc-macro-error" version = "1.0.4" @@ -1290,6 +1504,17 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom 0.2.8", + "redox_syscall", + "thiserror", +] + [[package]] name = "regex" version = "1.6.0" @@ -1449,6 +1674,18 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + [[package]] name = "serial_test" version = "0.9.0" @@ -1575,6 +1812,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "strsim" version = "0.10.0" @@ -1645,6 +1888,41 @@ version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +[[package]] +name = "thiserror" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "tokio" version = "1.21.2" @@ -1676,6 +1954,20 @@ dependencies = [ "syn", ] +[[package]] +name = "tokio-util" +version = "0.6.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.4" @@ -1690,6 +1982,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f" +dependencies = [ + "serde", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -1704,9 +2005,21 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ "cfg-if", "pin-project-lite", + "tracing-attributes", "tracing-core", ] +[[package]] +name = "tracing-attributes" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "tracing-core" version = "0.1.30" @@ -1728,18 +2041,65 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" + [[package]] name = "unicode-ident" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +[[package]] +name = "unsigned-varint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fdeedbf205afadfe39ae559b75c3240f24e257d0ca27e85f85cb82aa19ac35" + +[[package]] +name = "unsigned-varint" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86a8dc7f45e4c1b0d30e43038c38f274e77af056aa5f74b93c2cf9eb3c1c836" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + [[package]] name = "vcell" version = "0.1.3" diff --git a/Cargo.toml b/Cargo.toml index 10a88d8..33b7904 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ bytes = "1.2.1" tokio = { version = "1", features = ["full"] } async-trait = "0.1.58" futures = "0.3.25" +ipfs-api-backend-hyper = "0.5" walkdir = "2.3.2" [dev-dependencies] diff --git a/src/ipfs.rs b/src/ipfs.rs index fdb3df3..8a5f337 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -1,21 +1,18 @@ -use std::collections::HashMap; +use std::{collections::HashMap, path::Path}; use anyhow::Result; use async_trait::async_trait; -use self::config::Config; - pub mod daemon; -pub mod config; #[cfg(test)] pub mod tests; #[async_trait] pub trait Ipfs { - async fn add_file(&mut self, path:&str) -> Result>; - async fn add_directory(&mut self, path:&str) -> Result>; - async fn connect_to(&mut self, peer_id:&str) -> Result<()>; - async fn set_config(&mut self, options:&Config) -> Result<()>; - async fn get_config(&mut self) -> Result; + // async fn add_file(&self, path:&str) -> Result>; + async fn add(&self, path:&Path) -> Result>; + async fn connect_to(&self, peer_id:&str) -> Result<()>; + // async fn set_config(&self, options:&Config) -> Result<()>; + // async fn get_config(&self) -> Result; } \ No newline at end of file diff --git a/src/ipfs/config.rs b/src/ipfs/config.rs deleted file mode 100644 index ed2fa87..0000000 --- a/src/ipfs/config.rs +++ /dev/null @@ -1,291 +0,0 @@ -pub mod identity; -pub mod datastore; -pub mod mounts; -pub mod discovery; -pub mod routing; -pub mod ipns; -pub mod gateway; -pub mod swarm; -pub mod pubsub; -pub mod peering; -pub mod dns; -pub mod migration; -pub mod provider; -pub mod reprovider; -pub mod experimental; -pub mod plugins; -pub mod pinning; -pub mod api; -pub mod addresses; -pub mod auto_nat; - -use serde::{Serialize, Deserialize}; -use serde_json::Value; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Config{ - #[serde(default)] - #[serde(alias = "Identity")] - pub identity:Value, - #[serde(default)] - #[serde(alias = "Datastore")] - pub datastore:Value, - #[serde(default)] - #[serde(alias = "Mounts")] - pub mounts:Value, - #[serde(default)] - #[serde(alias = "Discovery")] - pub discovery:Value, - #[serde(default)] - #[serde(alias = "Routing")] - pub routing:Value, - #[serde(default)] - #[serde(alias = "Ipns")] - pub ipns:Value, - #[serde(default)] - #[serde(alias = "Gateway")] - pub gateway:Value, - #[serde(default)] - #[serde(alias = "Swarm")] - pub swarm:Value, - #[serde(default)] - #[serde(alias = "Pubsub")] - pub pubsub:Value, - #[serde(default)] - #[serde(alias = "Peering")] - pub peering:Value, - #[serde(default)] - #[serde(alias = "DNS")] - pub dns:Value, - #[serde(default)] - #[serde(alias = "Migration")] - pub migration:Value, - #[serde(default)] - #[serde(alias = "Provider")] - pub provider:Value, - #[serde(default)] - #[serde(alias = "Reprovider")] - pub reprovider:Value, - #[serde(default)] - #[serde(alias = "Experimental")] - pub experimental:Value, - #[serde(default)] - #[serde(alias = "Plugins")] - pub plugins:Value, - #[serde(default)] - #[serde(alias = "Pinning")] - pub pinning:Value, - #[serde(default)] - #[serde(alias = "API")] - pub api:Value, - #[serde(alias = "Addresses")] - pub addresses:addresses::Addresses, - #[serde(default)] - #[serde(alias = "AutoNAT")] - pub auto_nat:Value, - #[serde(default)] - #[serde(alias = "Bootstrap")] - pub bootstrap:Vec -} - - - -/* -Example IPFS Config - -{ - "API":{ - "HTTPHeaders":{ - - } - }, - "Addresses":{ - "API":"/ip4/127.0.0.1/tcp/4867", - "Announce":[ - - ], - "AppendAnnounce":[ - - ], - "Gateway":"/ip4/127.0.0.1/tcp/5742", - "NoAnnounce":[ - - ], - "Swarm":[ - "/ip4/0.0.0.0/tcp/4001", - "/ip6/::/tcp/4001", - "/ip4/0.0.0.0/udp/4001/quic", - "/ip6/::/udp/4001/quic" - ] - }, - "AutoNAT":{ - - }, - "Bootstrap":[ - "/dnsaddr/bootstrap.libp2p.io/p2p/QmNnooDu7bfjPFoTZYxMNLWUQJyrVwtbZg5gBMjTezGAJN", - "/dnsaddr/bootstrap.libp2p.io/p2p/QmQCU2EcMqAqQPR2i9bChDtGNJchTbq5TbXJJ16u19uLTa", - "/dnsaddr/bootstrap.libp2p.io/p2p/QmbLHAnMoJPWSCR5Zhtx6BHJX9KiKNN6tpvbUcqanj75Nb", - "/dnsaddr/bootstrap.libp2p.io/p2p/QmcZf59bWwK5XFi76CZX8cbJ4BhTzzA3gU1ZjYZcYW3dwt", - "/ip4/104.131.131.82/tcp/4001/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ", - "/ip4/104.131.131.82/udp/4001/quic/p2p/QmaCpDMGvV2BGHeYERUEnRQAwe3N8SzbUtfsmvsqQLuvuJ" - ], - "DNS":{ - "Resolvers":{ - - } - }, - "Datastore":{ - "BloomFilterSize":0, - "GCPeriod":"1h", - "HashOnRead":false, - "Spec":{ - "mounts":[ - { - "child":{ - "path":"blocks", - "shardFunc":"/repo/flatfs/shard/v1/next-to-last/2", - "sync":true, - "type":"flatfs" - }, - "mountpoint":"/blocks", - "prefix":"flatfs.datastore", - "type":"measure" - }, - { - "child":{ - "compression":"none", - "path":"datastore", - "type":"levelds" - }, - "mountpoint":"/", - "prefix":"leveldb.datastore", - "type":"measure" - } - ], - "type":"mount" - }, - "StorageGCWatermark":90, - "StorageMax":"10GB" - }, - "Discovery":{ - "MDNS":{ - "Enabled":true - } - }, - "Experimental":{ - "AcceleratedDHTClient":false, - "FilestoreEnabled":false, - "GraphsyncEnabled":false, - "Libp2pStreamMounting":false, - "P2pHttpProxy":false, - "StrategicProviding":false, - "UrlstoreEnabled":false - }, - "Gateway":{ - "APICommands":[ - - ], - "HTTPHeaders":{ - "Access-Control-Allow-Headers":[ - "X-Requested-With", - "Range", - "User-Agent" - ], - "Access-Control-Allow-Methods":[ - "GET" - ], - "Access-Control-Allow-Origin":[ - "*" - ] - }, - "NoDNSLink":false, - "NoFetch":false, - "PathPrefixes":[ - - ], - "PublicGateways":null, - "RootRedirect":"", - "Writable":false - }, - "Identity":{ - "PeerID":"12D3KooWGbZNXNRr7ZJkAecA445LyjZCkz1uTXne8zJCCpnDgicX" - }, - "Internal":{ - - }, - "Ipns":{ - "RecordLifetime":"", - "RepublishPeriod":"", - "ResolveCacheSize":128 - }, - "Migration":{ - "DownloadSources":[ - - ], - "Keep":"" - }, - "Mounts":{ - "FuseAllowOther":false, - "IPFS":"/ipfs", - "IPNS":"/ipns" - }, - "Peering":{ - "Peers":null - }, - "Pinning":{ - "RemoteServices":{ - - } - }, - "Plugins":{ - "Plugins":null - }, - "Provider":{ - "Strategy":"" - }, - "Pubsub":{ - "DisableSigning":false, - "Router":"" - }, - "Reprovider":{ - "Interval":"12h", - "Strategy":"all" - }, - "Routing":{ - "Methods":null, - "Routers":null, - "Type":"dht" - }, - "Swarm":{ - "AddrFilters":null, - "ConnMgr":{ - "GracePeriod":"20s", - "HighWater":900, - "LowWater":600, - "Type":"basic" - }, - "DisableBandwidthMetrics":false, - "DisableNatPortMap":false, - "RelayClient":{ - - }, - "RelayService":{ - - }, - "ResourceMgr":{ - - }, - "Transports":{ - "Multiplexers":{ - - }, - "Network":{ - - }, - "Security":{ - - } - } - } -} -*/ \ No newline at end of file diff --git a/src/ipfs/config/addresses.rs b/src/ipfs/config/addresses.rs deleted file mode 100644 index 947b9d1..0000000 --- a/src/ipfs/config/addresses.rs +++ /dev/null @@ -1,23 +0,0 @@ -use serde::{Serialize, Deserialize}; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct Addresses{ - #[serde(default)] - #[serde(alias = "API")] - api:String, - #[serde(default)] - #[serde(alias = "Announce")] - announce:Vec, - #[serde(default)] - #[serde(alias = "AppendAnnounce")] - append_announce:Option>, - #[serde(default)] - #[serde(alias = "Gateway")] - gateway:String, - #[serde(default)] - #[serde(alias = "NoAnounce")] - no_anounce:Option>, - #[serde(default)] - #[serde(alias = "Swarm")] - swarm:Vec -} \ No newline at end of file diff --git a/src/ipfs/config/api.rs b/src/ipfs/config/api.rs deleted file mode 100644 index 1a1aaf8..0000000 --- a/src/ipfs/config/api.rs +++ /dev/null @@ -1,8 +0,0 @@ -use serde::{Serialize, Deserialize}; -use serde_json::Value; - -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct API{ - #[serde(alias = "HTTPHeaders")] - http_headers:Value, // Note this a dynamic Value because the http header could be anything -} \ No newline at end of file diff --git a/src/ipfs/config/auto_nat.rs b/src/ipfs/config/auto_nat.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/datastore.rs b/src/ipfs/config/datastore.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/discovery.rs b/src/ipfs/config/discovery.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/dns.rs b/src/ipfs/config/dns.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/experimental.rs b/src/ipfs/config/experimental.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/gateway.rs b/src/ipfs/config/gateway.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/identity.rs b/src/ipfs/config/identity.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/ipns.rs b/src/ipfs/config/ipns.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/migration.rs b/src/ipfs/config/migration.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/mounts.rs b/src/ipfs/config/mounts.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/peering.rs b/src/ipfs/config/peering.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/pinning.rs b/src/ipfs/config/pinning.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/plugins.rs b/src/ipfs/config/plugins.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/provider.rs b/src/ipfs/config/provider.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/pubsub.rs b/src/ipfs/config/pubsub.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/reprovider.rs b/src/ipfs/config/reprovider.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/routing.rs b/src/ipfs/config/routing.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/config/swarm.rs b/src/ipfs/config/swarm.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 8a7e2b4..4b35b77 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,83 +1,88 @@ -use std::{ - collections::HashMap, - process::{Child, Command}, - thread::sleep, - time::{Duration, SystemTime} -}; - +use std::process::{Child, Command}; +use std::collections::HashMap; +use std::thread::{self, sleep}; +use std::time::{SystemTime, Duration}; + +use futures::executor::block_on; +use tokio::runtime::Runtime; +use ipfs_api_backend_hyper::{TryFromUri, IpfsClient, IpfsApi, LoggingLevel, Logger}; use anyhow::{bail, Result}; use async_trait::async_trait; use colored::Colorize; -use serde_json::Value; - -use crate::ipfs::{ - config::Config, - Ipfs -}; +use std::path::Path; -use crate::utils::{ - config::{IPFS_BOOT_TIME_OUT, IPFS_ADDR, IPFS_API_PORT, IPFS_EXE, IPFS_SLEEP_LENGTH}, - file_management, - http::{HttpHandler, HttpRequest}, - json -}; +use crate::ipfs::Ipfs; +use crate::utils::config::{IPFS_ADDR, IPFS_API_PORT, IPFS_EXE, IPFS_SLEEP_LENGTH, IPFS_BOOT_TIME_OUT}; pub struct IpfsDaemon { - http: HttpHandler, - ipfs_process: Child, - is_ipfs_ready: bool + proccess: Option, + client: IpfsClient, + tokio:Runtime } impl IpfsDaemon { - pub fn new() -> Result { - println!("{}", "Starting ipfs...".green()); + pub fn new() -> Result { + let client = IpfsClient::from_host_and_port("http".parse()?, IPFS_ADDR, IPFS_API_PORT)?; + + let runtime = tokio::runtime::Runtime::new().unwrap(); + Ok(Self{ + proccess: None, + client, + tokio: runtime + }) + } + pub fn has_launched(&self) -> bool{ + self.proccess.is_some() + } + pub async fn launch(&mut self) -> Result<()>{ let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); + println!("Launhing IPFS..."); let proccess = Command::new(IPFS_EXE) - .arg("--api") - .arg(&api_addr) - .arg("daemon") - .spawn() - .unwrap_or_else(|e| panic!("Failed to start IPFS daemon: {}\n This error may be because the Kubo binary is not on your PATH.", e)); - - println!( - "{}", - ("⚠️ Warning: Ipfs Proccess Started. Please do NOT force close this app⚠️".yellow()) - ); - anyhow::Ok(IpfsDaemon { - ipfs_process: proccess, - http: HttpHandler::new(), - is_ipfs_ready: false - }) - } - - async fn send_request(&mut self, options: &HttpRequest) -> Result> { + .arg("--api") + .arg(&api_addr) + .arg("daemon") + .spawn() + .unwrap_or_else(|e| panic!("Failed to start IPFS daemon: {}\n This error may be because the Kubo binary is not on your PATH.", e)); + self.proccess = Some(proccess); + println!("Waiting for IPFS to ready.."); self.await_ready().await?; - let result = self - .http - .try_send_request( - options, - Some(|response_data: Vec| { - let response_str = std::str::from_utf8(response_data.as_slice())?; - //TODO: do a better job of checking here - anyhow::Ok(!(response_str.contains("\"Type\":\"error\""))) - }), - ) - .await?; - anyhow::Ok(result) //it always return Some if a handler is given + self.tokio.block_on(async { + self.client.log_level(Logger::All, LoggingLevel::Error).await + })?; + Ok(()) } - - async fn await_ready(&mut self) -> Result<()> { - if self.is_ipfs_ready == true { - return anyhow::Ok(()); + pub fn shutdown(&mut self) -> Result<()>{ + Ok(match self.proccess.as_mut() { + Some(process) => { + self.tokio.block_on(async { + block_on(self.client.shutdown()) + })?; + process.wait()?; + self.proccess = None; + }, + None => () + }) + } + async fn is_ipfs_ready(&self) -> bool { + let res = self.tokio.block_on(async { + self.client.config_get_json("API").await + }); + if res.is_ok() { + println!("Config is {}", res.as_ref().unwrap().value); } + return match res { + Ok(_) => true, + Err(_) => false + }; + } + async fn await_ready(&self) -> Result<()> { let start_time = SystemTime::now(); loop { println!("{}", "checking if ipfs is ready...".green()); - if self.poll_ipfs_ready().await { + if self.is_ipfs_ready().await { println!("{}", "IPFS is ready!!".green()); - self.is_ipfs_ready = true; break; } @@ -93,186 +98,38 @@ impl IpfsDaemon { } anyhow::Ok(()) } - - async fn poll_ipfs_ready(&mut self) -> bool { - let args = HashMap::new(); - let addr = Self::get_ipfs_addr() + "/config/show"; - let cmd = HttpRequest::new(&addr, &args, false); - let response = self.http.send_request(&cmd).await; - return match response { - Ok(_) => true, - Err(e) => { - eprint!("{}", e); - false - } - }; - } - - //TODO: Better name? - async fn swarm_cmd(&mut self, cmd: &str, peer_id: &str) -> Result> { - let args = HashMap::from([("arg", peer_id)]); - let addr = Self::get_ipfs_addr() + cmd; - let cmd_options = HttpRequest::new(&addr, &args, false); - let result_data = self.send_request(&cmd_options).await?; - let result_str = std::str::from_utf8(result_data.as_slice())?; - let result_json:Value = match serde_json::from_str(result_str){ - Ok(x) => x, - Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) - }; - let peer_list = match json::value_to_vec::(&result_json, "Strings"){ - Ok(peers) => { - for peer in peers.iter() { - if !peer.contains("success"){ - bail!("The following peer did not successfully connect or disconnect: {}", peer) - } - } - peers - }, - Err(_) => bail!("The was error parsing the server's response! The server's response is as follows: \n {}", result_str) - }; - - return anyhow::Ok(peer_list); - } - - fn response_to_hashes(response: &str) -> Result> { - let mut res = response.to_string(); - let mut ret = HashMap::new(); - return loop { - //get location to take segment to - let json_seg_end = match res.find("}") { - Some(seg_loc) => seg_loc, - None => break anyhow::Ok(ret), - }; - //get segment to convert to json and remove the segment from res - let res_vec = res.chars().collect::>(); - let json_seg = res_vec[..(json_seg_end + 1)].iter().collect::(); - res = res_vec[(json_seg_end + 1)..].iter().collect(); - //convert that segment to json and value - let json: Value = serde_json::from_str(&json_seg)?; - let path = match json.get("Name") { - Some(val) => "/".to_string() + &val.to_string().split("\"").collect::(), - None => bail!("Could not find Name property in ipfs's response to an add"), - }; - let hash = match json.get("Hash") { - Some(val) => val.to_string().split("\"").collect::(), - None => bail!("Could not find Hash property in ipfs's response to an add"), - }; - ret.insert(path, hash); - }; - } - - fn get_ipfs_addr() -> String { - format!("http://{}:{}/api/v0", IPFS_ADDR, IPFS_API_PORT) - } } #[async_trait] impl Ipfs for IpfsDaemon { - async fn add_file(&mut self, path: &str) -> Result> { - let cmd = Self::get_ipfs_addr() + "/add"; - let args = HashMap::from([("quieter", "true"), ("cid-version", "1"), ("path", &path)]); - let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &path); - let headers = HashMap::from([ - ("Content-Disposition", &disposition as &str), - ("Content-Type", "application/octet-stream"), - ]); - let mut cmd_options = HttpRequest::new(&cmd, &args, true); - let contents = std::fs::read(path)?; - cmd_options.add_body(&headers, contents.as_slice()); - let result_data = self.send_request(&cmd_options).await?; - let response = std::str::from_utf8(result_data.as_slice())?.to_string(); - let hashes = Self::response_to_hashes(&response)?; - anyhow::Ok(hashes) - } - - async fn add_directory(&mut self, path: &str) -> Result> { - let cmd = Self::get_ipfs_addr() + "/add"; - let args = HashMap::from([("quieter", "true"), ("cid-version", "1")]); - let mut request = HttpRequest::new(&cmd, &args, true); - println!("{}", "Adding the following directories..".blue()); - - let dirs = file_management::get_dirs_in(path)?; - for dir in dirs { - let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &dir); - let headers = HashMap::from([ - ("Content-Disposition", &disposition as &str), - ("Content-Type", "application/x-directory"), - ]); - request.add_body(&headers, &[]); - println!("{}", dir.blue()); - } - - println!("{}", "Adding the following files..".blue()); - let files = file_management::get_files_in(path)?; - - for (file_path, data) in files { - let disposition = format!(" form-data; name=\"files\"; filename=\"{}\"", &file_path); - let headers = HashMap::from([ - ("Content-Disposition", &disposition as &str), - ("Content-Type", "application/octet-stream"), - ]); - request.add_body(&headers, data.as_slice()); - println!("{}", file_path.blue()); - } - let response_data = self.send_request(&request).await?; - let response = std::str::from_utf8(response_data.as_slice())?.to_string(); - let hashes = Self::response_to_hashes(&response)?; - anyhow::Ok(hashes) + // async fn add_file(&self, path: &str) -> Result> { + // todo!() + // } + + async fn add(&self, path: &Path) -> Result> { + // let mut form = Form::default(); + // for entry_result in WalkDir::new(path) { + // let entry = entry_result?; + // form = form.add_file(entry.file_name(), entry.path())?; + // } + let response_list = self.tokio.block_on(async { + self.client.add_path(path).await + })?; + //let response_list = self.client.add_path(path).await?; + return Ok(response_list.into_iter().map(|res| { + (res.name, res.hash) + }).collect()); } - async fn connect_to(&mut self, peer_id: &str) -> Result<()> { - self.swarm_cmd("/swarm/connect", peer_id) - .await?; - // print!("Connected Peers: "); - // self.connected_peers.iter().for_each(|peer| print!("{}, ", peer)); - anyhow::Ok(()) + async fn connect_to(&self, peer_id: &str) -> Result<()> { + todo!() } - async fn get_config(&mut self) -> Result{ - let get_profile = HttpRequest::new( - &(Self::get_ipfs_addr() + "/config/show"), - &(HashMap::new()), - false, - ); - let profile_vec = self.send_request(&get_profile).await?; - let profile_str = std::str::from_utf8(profile_vec.as_slice())?; - // println!("{}", profile_str.red()); - return Ok(serde_json::from_str(profile_str)?); - } + // async fn get_config(&self) -> Result{ + // todo!() + // } - async fn set_config(&mut self, options: &Config) -> Result<()> { - let args = HashMap::new(); - let addr = Self::get_ipfs_addr() + "/config/replace"; - let mut request = HttpRequest::new(&addr, &args, true); - let headers = HashMap::from([ - ( - "Content-Disposition", - " form-data; name=\"files\"; filename=\"config\"", - ), - ("Content-Type", "application/octet-stream"), - ]); - let body = serde_json::to_string(options)?; - request.add_body(&headers, body.as_bytes()); - let response = self.send_request(&request).await?; - let res_str = std::str::from_utf8(response.as_slice())?; - if res_str.trim().is_empty() { - return anyhow::Ok(()); - } else { - bail!( - "There was error changing the settings in ipfs. The failure was: {}", - res_str.red() - ); - } - } -} - -impl Drop for IpfsDaemon { - fn drop(&mut self) { - self.ipfs_process.kill().unwrap(); - println!( - "{}", - ("Ipfs proccess closed successfully. Feel free to close app whenever. ✅" - .bright_green()) - ) - } + // async fn set_config(&self, options: &Config) -> Result<()> { + // todo!() + // } } \ No newline at end of file diff --git a/src/ipfs/tests.rs b/src/ipfs/tests.rs index 2d8a5a7..99664eb 100644 --- a/src/ipfs/tests.rs +++ b/src/ipfs/tests.rs @@ -25,89 +25,122 @@ const PEER_ADDRS:&'static [&'static str] = &[ "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", ]; -fn connect_to_peers() -> IpfsDaemon { + +fn run_ipfs_test(test: T) -> () + where T: FnOnce(&IpfsDaemon) -> bool +{ let mut ipfs = IpfsDaemon::new().unwrap(); - for peer in PEER_ADDRS { - block_on(ipfs.connect_to(peer)).unwrap(); - println!("Connected to peer! {}", peer); + // for peer in PEER_ADDRS { + // block_on(ipfs.connect_to(peer)).unwrap(); + // println!("Connected to peer! {}", peer); + // } + block_on(ipfs.launch()).unwrap(); + let has_passed = test(&ipfs); + ipfs.shutdown().unwrap(); + assert!(has_passed) +} + +fn are_files_uploaded(uploaded_paths:Vec, os_paths:Vec) -> bool{ + let mut is_uploaded = true; + for os_path in os_paths{ + let mut fixed_path_os_path = String::new(); + let mut i = 0; + for seg in os_path.split("/") { + if seg != "." && !seg.is_empty() { + fixed_path_os_path += &(match i { + 0 => String::new(), + 1 => seg.to_string(), + _ => "/".to_string() + seg + }); + i += 1; + } + } + + let mut is_any_matching = false; + 'any: for uploaded_path in &uploaded_paths { + if &fixed_path_os_path == uploaded_path { + println!("{} == {}", fixed_path_os_path.green(), uploaded_path.green()); + is_any_matching = true; + break 'any; + }else{ + println!("{} == {}", fixed_path_os_path.red(), uploaded_path.red()); + } + }; + if !is_any_matching{ + println!("Failed to match {}", fixed_path_os_path.red()); + is_uploaded = false; + } } - return ipfs; + is_uploaded } #[test] #[serial] fn can_add_directory() { let test_dir = "./test-dir/more-tests"; - let mut ipfs = connect_to_peers(); - let hashes = block_on(ipfs.add_directory(test_dir)).unwrap(); - println!("{}", "Finnished Hashes:".green()); - for (path, hash) in &hashes { - println!("{}: {}", path.green(), hash.blue()) - } - - let files = file_management::get_files_in(test_dir).unwrap(); - let folders = file_management::get_dirs_in(test_dir).unwrap(); + run_ipfs_test(|ipfs| { + + let hashes = block_on(ipfs.add(Path::new(test_dir))).unwrap(); + println!("{}", "Finnished Hashes:".green()); + for (path, hash) in &hashes { + println!("{}: {}", path.green(), hash.blue()) + } - files - .iter() - .map(|(path, _)| path) - .chain(folders.iter()) - .for_each(|path_to_match| { - let fixed_path_to_match: String = path_to_match - .split("/") - .filter(|seg| seg != &"." && !seg.is_empty()) - .map(|seg| "/".to_string() + seg) - .collect(); - assert!(hashes - .iter() - .any(|(path, _)| fixed_path_to_match == path.to_owned())) - }); + let files = file_management::get_files_in(test_dir).unwrap(); + + let uploaded_paths = hashes.into_iter() + .map(|(path, _)| path) + .collect(); + let os_paths = files.into_iter() + .map(|(path, _)| path) + .collect(); + are_files_uploaded(uploaded_paths, os_paths) + }) } #[test] #[serial] fn can_add_file() { let test_file = "./test-dir/test.txt"; - let mut ipfs = connect_to_peers(); - let hashes = block_on(ipfs.add_file(test_file)).unwrap(); - println!("{}", "Finnished Hashes:\n".green()); - for (path, hash) in &hashes { - println!("{}: {}", path.green(), hash.blue()) - } - let matchable_path: String = test_file - .split("/") - .filter(|seg| seg != &"." && !seg.is_empty()) - .map(|seg| "/".to_string() + seg) - .collect(); - assert!(hashes - .iter() - .any(|(path, _)| matchable_path == path.to_owned())); -} -#[test] -#[serial] -fn can_config() { - let mut ipfs = IpfsDaemon::new().unwrap(); - let mut config = block_on(ipfs.get_config()).unwrap(); - config - .datastore - .as_object_mut() - .unwrap() - .insert("StorageMax".to_string(), Value::String("11GB".to_string())); - config - .datastore - .as_object_mut() - .unwrap() - .insert("GCPeriod".to_string(), Value::String("2h".to_string())); - block_on(ipfs.set_config(&config)).unwrap(); - config - .datastore - .as_object_mut() - .unwrap() - .insert("StorageMax".to_string(), Value::String("10GB".to_string())); - config - .datastore - .as_object_mut() - .unwrap() - .insert("GCPeriod".to_string(), Value::String("1h".to_string())); - block_on(ipfs.set_config(&config)).unwrap(); - assert!(true) + run_ipfs_test(|ipfs| { + let hashes = block_on(ipfs.add(Path::new(test_file))).unwrap(); + println!("{}", "Finnished Hashes:\n".green()); + for (path, hash) in &hashes { + println!("{}: {}", path.green(), hash.blue()) + } + let uploaded_paths = hashes.into_iter() + .map(|(path, _)| path) + .collect(); + let os_paths = vec![test_file.to_string()]; + are_files_uploaded(uploaded_paths, os_paths) + }) } + +// #[test] +// #[serial] +// fn can_config() { +// let mut ipfs = IpfsDaemon::new().unwrap(); +// let mut config = block_on(ipfs.get_config()).unwrap(); +// config +// .datastore +// .as_object_mut() +// .unwrap() +// .insert("StorageMax".to_string(), Value::String("11GB".to_string())); +// config +// .datastore +// .as_object_mut() +// .unwrap() +// .insert("GCPeriod".to_string(), Value::String("2h".to_string())); +// block_on(ipfs.set_config(&config)).unwrap(); +// config +// .datastore +// .as_object_mut() +// .unwrap() +// .insert("StorageMax".to_string(), Value::String("10GB".to_string())); +// config +// .datastore +// .as_object_mut() +// .unwrap() +// .insert("GCPeriod".to_string(), Value::String("1h".to_string())); +// block_on(ipfs.set_config(&config)).unwrap(); +// assert!(true) +// } diff --git a/src/utils.rs b/src/utils.rs index 2dfea19..9fb2645 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,5 +2,4 @@ pub mod config; pub mod file_management; pub mod http; pub mod json; -pub mod log; pub mod math; diff --git a/src/utils/file_management.rs b/src/utils/file_management.rs index d791085..b7b696e 100644 --- a/src/utils/file_management.rs +++ b/src/utils/file_management.rs @@ -4,7 +4,6 @@ use anyhow::{Result, bail}; use colored::Colorize; use walkdir::WalkDir; -//TODO: This needs to move to utils pub fn get_files_in(dir:&str) -> Result>> { let mut files = HashMap::new(); for entry_result in WalkDir::new(dir) { @@ -25,22 +24,4 @@ pub fn get_files_in(dir:&str) -> Result>> { } } return anyhow::Ok(files); -} - -pub fn get_dirs_in(root:&str) -> Result> { - let mut dirs = vec![]; - for entry_result in WalkDir::new(root) { - let entry = match entry_result { - Ok(x) => x, - Err(e) => bail!("{}\n{}", "failled to get item in directory, failed with error:".red(), e) - }; - if entry.path().is_dir() { - let path = match entry.path().to_str() { - Some(x) => x, - None => bail!("failed to get path as string a file") - }.to_string(); - dirs.push(path); - } - } - return anyhow::Ok(dirs); } \ No newline at end of file diff --git a/src/utils/http.rs b/src/utils/http.rs index ed61e6a..94a440d 100644 --- a/src/utils/http.rs +++ b/src/utils/http.rs @@ -131,37 +131,4 @@ impl HttpHandler { anyhow::Ok(response_data) } - - pub async fn try_send_request(&mut self, options:&HttpRequest, handler_option:Option) -> Result> - where F: Fn(Vec) -> Result{ - let mut attempt:u32 = 0; - 'attempt_loop: loop { - attempt += 1; - if attempt != 1 { - std::thread::sleep(Duration::new(math::get_fibonacci(attempt), 0)) - } - println!("attempting to send post request: attempt {} of {}", attempt, IPFS_RETRY_ATTEMPTS); - let is_final_attempt = attempt >= IPFS_RETRY_ATTEMPTS as u32; - let response_result = self.send_request(options).await; - let response = match is_final_attempt { - true => response_result?, - false => { match response_result { - Ok(x) => x, - Err(_) => continue 'attempt_loop - }} - }; - if is_final_attempt && handler_option.as_ref().is_some(){ - (handler_option.unwrap())(response.clone())?; - }else if handler_option.is_some(){ - let handler_result = (handler_option.as_ref().unwrap())(response.clone()); - if handler_result.is_err() { - continue 'attempt_loop; - }else if !(handler_result.unwrap()) { - continue 'attempt_loop; - } - } - return anyhow::Ok(response); - } - } - } diff --git a/src/utils/json.rs b/src/utils/json.rs index 25925e9..2db717b 100644 --- a/src/utils/json.rs +++ b/src/utils/json.rs @@ -1,11 +1,10 @@ use anyhow::{Result, bail}; use serde_json::{Map, Value}; -/* -Ipfs often returns json with a single property with the value being an array. -This function simply takes the array in that property and turns it into a vector that can be used in rust. -It will return an error result if the json is not formatted in this way. -*/ + +/// Ipfs often returns json with a single property with the value being an array. +/// This function simply takes the array in that property and turns it into a vector that can be used in rust. +/// It will return an error result if the json is not formatted in this way. pub fn value_to_vec(json:&Value, index:&str) -> Result> where A:Clone + for<'de> serde::Deserialize<'de>{ anyhow::Ok( match json.get(index) { diff --git a/src/utils/log.rs b/src/utils/log.rs deleted file mode 100644 index a2a7243..0000000 --- a/src/utils/log.rs +++ /dev/null @@ -1,53 +0,0 @@ -use anyhow::{anyhow, Result}; -use std::io::{self, Write}; -use std::process::Output; - -pub struct OutputOptions { - verbose: bool, - quiet: bool, - error: bool, -} - -impl OutputOptions { - fn verbose() -> OutputOptions { - OutputOptions { - verbose: true, - quiet: false, - error: false, - } - } - - fn default() -> OutputOptions { - OutputOptions { - verbose: false, - quiet: false, - error: false, - } - } - - fn quiet() -> OutputOptions { - OutputOptions { - verbose: false, - quiet: true, - error: false, - } - } -} - -// pub fn write_output(output: &Output) -> Result<()> { -// let mut options = OutputOptions::verbose(); - -// if output.stdout != (Vec::new() as Vec) { -// print_output(std::str::from_utf8(&output.stdout)?, &options)?; -// } -// if output.stderr != (Vec::new() as Vec) { -// options.error = true; -// print_output(std::str::from_utf8(&output.stdout)?, &options)?; -// } -// Ok(()) -// } - -pub fn print_output(output: &str, options: &OutputOptions) -> Result<()> { - println!("{}", output); - Ok(()) -} \ No newline at end of file From 098141d28c56f576911d81325ca47bdd1fa9aa0d Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Thu, 15 Dec 2022 14:56:39 -0600 Subject: [PATCH 48/63] config moved to lib --- src/ipfs.rs | 4 ++- src/ipfs/daemon.rs | 45 ++++++++++++++++------------ src/ipfs/tests.rs | 73 ++++++++++++++++++---------------------------- src/utils/http.rs | 4 +++ src/utils/json.rs | 4 +++ src/utils/math.rs | 4 +++ 6 files changed, 69 insertions(+), 65 deletions(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index 8a5f337..1961914 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -2,6 +2,7 @@ use std::{collections::HashMap, path::Path}; use anyhow::Result; use async_trait::async_trait; +use serde_json::Value; pub mod daemon; @@ -10,9 +11,10 @@ pub mod tests; #[async_trait] pub trait Ipfs { - // async fn add_file(&self, path:&str) -> Result>; async fn add(&self, path:&Path) -> Result>; async fn connect_to(&self, peer_id:&str) -> Result<()>; + async fn set_config(&self, property:&str, val:&Value) -> Result<()>; + async fn get_config(&self, property:&str) -> Result; // async fn set_config(&self, options:&Config) -> Result<()>; // async fn get_config(&self) -> Result; } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 4b35b77..495da6c 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,9 +1,10 @@ use std::process::{Child, Command}; use std::collections::HashMap; -use std::thread::{self, sleep}; +use std::thread::sleep; use std::time::{SystemTime, Duration}; use futures::executor::block_on; +use serde_json::Value; use tokio::runtime::Runtime; use ipfs_api_backend_hyper::{TryFromUri, IpfsClient, IpfsApi, LoggingLevel, Logger}; use anyhow::{bail, Result}; @@ -102,34 +103,40 @@ impl IpfsDaemon { #[async_trait] impl Ipfs for IpfsDaemon { - // async fn add_file(&self, path: &str) -> Result> { - // todo!() - // } - async fn add(&self, path: &Path) -> Result> { - // let mut form = Form::default(); - // for entry_result in WalkDir::new(path) { - // let entry = entry_result?; - // form = form.add_file(entry.file_name(), entry.path())?; - // } let response_list = self.tokio.block_on(async { self.client.add_path(path).await })?; - //let response_list = self.client.add_path(path).await?; return Ok(response_list.into_iter().map(|res| { (res.name, res.hash) }).collect()); } - async fn connect_to(&self, peer_id: &str) -> Result<()> { todo!() } + async fn get_config(&self, prop:&str) -> Result{ + let config = self.tokio.block_on(async { + self.client.config_get_json(prop).await + })?; + return Ok(config.value); + } + async fn set_config(&self, prop:&str, val:&Value) -> Result<()> { + if val.is_boolean() { + self.tokio.block_on(async { + self.client.config_set_bool(prop, val.as_bool().unwrap()).await + })?; + return Ok(()); + } + if val.is_string() { + self.tokio.block_on(async { + self.client.config_set_string(prop, val.as_str().unwrap()).await + })?; + return Ok(()); + } + self.tokio.block_on(async { + self.client.config_set_json(prop, &val.to_string()).await + })?; - // async fn get_config(&self) -> Result{ - // todo!() - // } - - // async fn set_config(&self, options: &Config) -> Result<()> { - // todo!() - // } + return Ok(()); + } } \ No newline at end of file diff --git a/src/ipfs/tests.rs b/src/ipfs/tests.rs index 99664eb..8f52137 100644 --- a/src/ipfs/tests.rs +++ b/src/ipfs/tests.rs @@ -1,6 +1,5 @@ use colored::Colorize; use futures::executor::block_on; -use serde_json::Value; use serial_test::serial; use self::daemon::IpfsDaemon; @@ -9,21 +8,21 @@ use crate::ipfs::Ipfs; use crate::utils::file_management; //TODO: Setup pizza -const PEER_ADDRS:&'static [&'static str] = &[ - "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", - "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", - "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4001/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", - "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/ip4/54.235.17.70/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/ip4/54.235.17.70/udp/4001/quic/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4001/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", - "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4001/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", - "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4001/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", - "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", - "/ip4/54.235.17.70/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", - "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", - ]; +// const PEER_ADDRS:&'static [&'static str] = &[ +// "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", +// "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", +// "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4001/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", +// "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", +// "/ip4/54.235.17.70/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", +// "/ip4/54.235.17.70/udp/4001/quic/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", +// "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", +// "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4001/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", +// "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4001/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", +// "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4001/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", +// "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", +// "/ip4/54.235.17.70/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", +// "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", +// ]; fn run_ipfs_test(test: T) -> () @@ -115,32 +114,16 @@ fn can_add_file() { }) } -// #[test] -// #[serial] -// fn can_config() { -// let mut ipfs = IpfsDaemon::new().unwrap(); -// let mut config = block_on(ipfs.get_config()).unwrap(); -// config -// .datastore -// .as_object_mut() -// .unwrap() -// .insert("StorageMax".to_string(), Value::String("11GB".to_string())); -// config -// .datastore -// .as_object_mut() -// .unwrap() -// .insert("GCPeriod".to_string(), Value::String("2h".to_string())); -// block_on(ipfs.set_config(&config)).unwrap(); -// config -// .datastore -// .as_object_mut() -// .unwrap() -// .insert("StorageMax".to_string(), Value::String("10GB".to_string())); -// config -// .datastore -// .as_object_mut() -// .unwrap() -// .insert("GCPeriod".to_string(), Value::String("1h".to_string())); -// block_on(ipfs.set_config(&config)).unwrap(); -// assert!(true) -// } +#[test] +#[serial] +fn can_config() { + let test_prop = "Datastore.StorageMax"; + let test_value = Value::String("11GB".to_string()); + run_ipfs_test(|ipfs| { + let old_config = block_on(ipfs.get_config(test_prop)).unwrap(); + block_on(ipfs.set_config(test_prop, &test_value)).unwrap(); + let new_config = block_on(ipfs.get_config(test_prop)).unwrap(); + block_on(ipfs.set_config(test_prop, &old_config)).unwrap(); + test_value == new_config + }); +} diff --git a/src/utils/http.rs b/src/utils/http.rs index 94a440d..872f877 100644 --- a/src/utils/http.rs +++ b/src/utils/http.rs @@ -1,3 +1,7 @@ +/* + This file is currently dead code. Please remove if it continue to be dead code. +*/ + use std::{ time::Duration, collections::HashMap, diff --git a/src/utils/json.rs b/src/utils/json.rs index 2db717b..ede5806 100644 --- a/src/utils/json.rs +++ b/src/utils/json.rs @@ -1,3 +1,7 @@ +/* + This file is currently dead code. Please remove if it continue to be dead code. +*/ + use anyhow::{Result, bail}; use serde_json::{Map, Value}; diff --git a/src/utils/math.rs b/src/utils/math.rs index ded5b71..9be4aa8 100644 --- a/src/utils/math.rs +++ b/src/utils/math.rs @@ -1,3 +1,7 @@ +/* + This file is currently dead code. Please remove if it continue to be dead code. +*/ + pub fn get_fibonacci(n:u32) -> u64{ if n <= 1 { return n as u64; From 1548f7c84402a1b1762ed5e8ab53501b54c17701 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Fri, 16 Dec 2022 13:38:50 -0600 Subject: [PATCH 49/63] Graceful Shutdown --- Cargo.lock | 673 +++++++++++++++++++++------------------------ Cargo.toml | 27 +- src/ipfs/daemon.rs | 70 +++-- src/ipfs/tests.rs | 2 +- 4 files changed, 371 insertions(+), 401 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1d24de9..8a39a28 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "0.7.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e" -dependencies = [ - "memchr", -] - [[package]] name = "anyhow" version = "1.0.66" @@ -25,9 +16,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.59" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" dependencies = [ "proc-macro2", "quote", @@ -36,9 +27,9 @@ dependencies = [ [[package]] name = "atomic-polyfill" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c041a8d9751a520ee19656232a18971f18946a7900f1520ee4400002244dd89" +checksum = "e3ff7eb3f316534d83a8a2c3d1674ace8a5a71198eba31e2e2b597833f699b28" dependencies = [ "critical-section", ] @@ -51,7 +42,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -61,37 +52,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] -name = "bare-metal" -version = "0.2.5" +name = "base-x" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" -dependencies = [ - "rustc_version 0.2.3", -] +checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" [[package]] -name = "bare-metal" -version = "1.0.0" +name = "base16ct" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" [[package]] -name = "base-x" -version = "0.2.11" +name = "base64" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.12.3" +version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +checksum = "0ea22880d78093b0cbe17c89f64a7d457941e65759157ec6cb31a31d652b05e5" [[package]] -name = "base64" -version = "0.13.0" +name = "base64ct" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" [[package]] name = "bit-set" @@ -109,16 +97,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] -name = "bit_field" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" - -[[package]] -name = "bitfield" -version = "0.13.2" +name = "bitflags" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" +checksum = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3" [[package]] name = "bitflags" @@ -128,9 +110,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitvec" -version = "0.22.3" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5237f00a8c86130a0cc317830e558b966dd7850d48a953d998c813f01a41b527" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" dependencies = [ "funty", "radium", @@ -148,33 +130,25 @@ dependencies = [ ] [[package]] -name = "bls12_381_plus" -version = "0.5.2" +name = "block-buffer" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14072e323786a34a18e1bf1ef8940fff0537cc45f1f35ad96d4921008c18a88a" +checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ - "digest", - "ff 0.10.1", - "group 0.10.0", - "heapless", - "pairing 0.20.0", - "rand_core 0.6.4", - "serde", - "subtle", - "zeroize", + "generic-array", ] [[package]] name = "bls12_381_plus" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9ca230350e9fa6d2bcbf2eec0dd805a8aa0996ee8884da282097ca7e50a29b" +checksum = "c7c681aa947677ec0c5ccfa6f14c0dd039ddbaa7b12952bf146bd5226a5f9880" dependencies = [ - "digest", - "ff 0.11.1", - "group 0.11.0", + "digest 0.9.0", + "ff", + "group", "heapless", - "pairing 0.21.0", + "pairing", "rand_core 0.6.4", "serde", "subtle", @@ -201,9 +175,15 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" +checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "cfg-if" @@ -213,12 +193,12 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "clap" -version = "3.2.12" +version = "3.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8b79fe3946ceb4a0b1c080b4018992b8d27e9ff363644c1c9b6387c854614d" +checksum = "71655c45cb9845d3270c9d6df84ebe72b4dad3c2ba3f7023ad47c144e4e473a5" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", "indexmap", @@ -230,9 +210,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "3.2.7" +version = "3.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759bf187376e1afa7b85b959e6a664a3e7a95203415dba952ad19139e798f902" +checksum = "ea0c8bce528c4be4da13ea6fead8965e95b6073585a2f05204bd8f4119f82a65" dependencies = [ "heck", "proc-macro-error", @@ -258,7 +238,7 @@ checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" dependencies = [ "atty", "lazy_static", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -279,21 +259,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b" - -[[package]] -name = "cortex-m" -version = "0.7.6" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70858629a458fdfd39f9675c4dc309411f2a3f83bede76988d81bf1a0ecee9e0" -dependencies = [ - "bare-metal 0.2.5", - "bitfield", - "embedded-hal", - "volatile-register", -] +checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" [[package]] name = "cpufeatures" @@ -306,15 +274,9 @@ dependencies = [ [[package]] name = "critical-section" -version = "0.2.7" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95da181745b56d4bd339530ec393508910c909c784e8962d15d722bacf0bcbcd" -dependencies = [ - "bare-metal 1.0.0", - "cfg-if", - "cortex-m", - "riscv", -] +checksum = "6548a0ad5d2549e111e1f6a11a6c2e2d00ce6a3dafe22948d67c2b443f775e52" [[package]] name = "crunchy" @@ -324,9 +286,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.2.11" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -334,6 +296,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -361,7 +333,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", - "digest", + "digest 0.9.0", "rand_core 0.5.1", "subtle", "zeroize", @@ -373,7 +345,7 @@ version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "hashbrown", "lock_api", "once_cell", @@ -408,34 +380,35 @@ dependencies = [ [[package]] name = "der" -version = "0.4.5" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79b71cca7d95d7681a4b3b9cdf63c8dbc3730d0584c2c74e31416d64a90493f4" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" dependencies = [ "const-oid", + "zeroize", ] [[package]] name = "did-key" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3722614aaa48b0b34489aa86a59d0dfa365d7b9448a24bc6d10ae361c7a2b49c" +checksum = "3ed21f9ed50f9d3f79b6ba84f2cf8a536399c3500bc99406c1bbc1e0c598524e" dependencies = [ "arrayref", - "base64 0.13.0", - "bls12_381_plus 0.6.0", + "base64 0.13.1", + "bls12_381_plus", "bs58", "curve25519-dalek", "did_url", "ed25519-dalek", "getrandom 0.2.8", - "hkdf", + "hkdf 0.11.0", + "json-patch", "libsecp256k1", "p256", "serde", "serde_json", - "sha2", - "signature_bls", + "sha2 0.9.9", "x25519-dalek", ] @@ -457,6 +430,17 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer 0.10.3", + "crypto-common", + "subtle", +] + [[package]] name = "dirs" version = "4.0.0" @@ -474,18 +458,18 @@ checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", - "winapi", + "winapi 0.3.9", ] [[package]] name = "ecdsa" -version = "0.12.4" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" dependencies = [ "der", "elliptic-curve", - "hmac 0.11.0", + "rfc6979", "signature", ] @@ -508,36 +492,31 @@ dependencies = [ "ed25519", "rand 0.7.3", "serde", - "sha2", + "sha2 0.9.9", "zeroize", ] [[package]] name = "elliptic-curve" -version = "0.10.6" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" dependencies = [ + "base16ct", "crypto-bigint", - "ff 0.10.1", + "der", + "digest 0.10.6", + "ff", "generic-array", - "group 0.10.0", + "group", + "hkdf 0.12.3", "pkcs8", "rand_core 0.6.4", + "sec1", "subtle", "zeroize", ] -[[package]] -name = "embedded-hal" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" -dependencies = [ - "nb 0.1.3", - "void", -] - [[package]] name = "fastrand" version = "1.8.0" @@ -549,20 +528,9 @@ dependencies = [ [[package]] name = "ff" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f" -dependencies = [ - "bitvec", - "rand_core 0.6.4", - "subtle", -] - -[[package]] -name = "ff" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131655483be284720a17d74ff97592b8e76576dc25563148601df2d7c9080924" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" dependencies = [ "bitvec", "rand_core 0.6.4", @@ -575,13 +543,14 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "base64 0.13.0", + "base64 0.20.0", "bs58", "bytes", "clap", "colored", "did-key", "futures", + "graceful", "hyper", "ipfs-api-backend-hyper", "proptest", @@ -609,9 +578,9 @@ dependencies = [ [[package]] name = "funty" -version = "1.2.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1847abb9cb65d566acd5942e94aea9c8f547ad02c98e1649326fc0e8910b8b1e" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" @@ -718,7 +687,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -729,7 +698,7 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", @@ -737,25 +706,22 @@ dependencies = [ ] [[package]] -name = "group" -version = "0.10.0" +name = "graceful" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912" +checksum = "1ca5313c7c751c3e64c789d0c0abfc8f6e782d4e93d88da070012d434a215ecc" dependencies = [ - "byteorder", - "ff 0.10.1", - "rand_core 0.6.4", - "subtle", + "kernel32-sys", + "nix", ] [[package]] name = "group" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5ac374b108929de78460075f3dc439fa66df9d8fc77e8f12caa5165fcf0c89" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "byteorder", - "ff 0.11.1", + "ff", "rand_core 0.6.4", "subtle", ] @@ -828,10 +794,19 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b" dependencies = [ - "digest", + "digest 0.9.0", "hmac 0.11.0", ] +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac 0.12.1", +] + [[package]] name = "hmac" version = "0.8.1" @@ -839,7 +814,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" dependencies = [ "crypto-mac 0.8.0", - "digest", + "digest 0.9.0", ] [[package]] @@ -849,7 +824,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ "crypto-mac 0.11.1", - "digest", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.6", ] [[package]] @@ -858,7 +842,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ - "digest", + "digest 0.9.0", "generic-array", "hmac 0.8.1", ] @@ -899,9 +883,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.22" +version = "0.14.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" +checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" dependencies = [ "bytes", "futures-channel", @@ -946,9 +930,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" +checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" dependencies = [ "autocfg", "hashbrown", @@ -960,7 +944,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -987,7 +971,7 @@ checksum = "fbaf47fa129710ae041d5844a15b1365bdad8551673aee237449ba9dec6bcadc" dependencies = [ "async-trait", "bytes", - "cfg-if", + "cfg-if 1.0.0", "common-multipart-rfc7578", "dirs", "futures", @@ -1019,6 +1003,27 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json-patch" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3fa5a61630976fc4c353c70297f2e93f1930e3ccee574d59d618ccbd5154ce" +dependencies = [ + "serde", + "serde_json", + "treediff", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -1027,54 +1032,54 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" [[package]] name = "libsecp256k1" -version = "0.5.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd1137239ab33b41aa9637a88a28249e5e70c40a42ccc92db7f12cc356c1fcd7" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64 0.12.3", - "digest", + "base64 0.13.1", + "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", - "rand 0.7.3", + "rand 0.8.5", "serde", - "sha2", + "sha2 0.9.9", "typenum", ] [[package]] name = "libsecp256k1-core" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" dependencies = [ "crunchy", - "digest", + "digest 0.9.0", "subtle", ] [[package]] name = "libsecp256k1-gen-ecmult" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" dependencies = [ "libsecp256k1-core", ] [[package]] name = "libsecp256k1-gen-genmult" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" dependencies = [ "libsecp256k1-core", ] @@ -1095,7 +1100,7 @@ version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", ] [[package]] @@ -1169,20 +1174,19 @@ dependencies = [ ] [[package]] -name = "nb" -version = "0.1.3" +name = "nix" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +checksum = "a0d95c5fa8b641c10ad0b8887454ebaafa3c92b5cd5350f8fc693adafd178e7b" dependencies = [ - "nb 1.0.0", + "bitflags 0.4.0", + "cfg-if 0.1.10", + "libc", + "rustc_version 0.1.7", + "semver 0.1.20", + "void", ] -[[package]] -name = "nb" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" - [[package]] name = "num-traits" version = "0.2.15" @@ -1216,37 +1220,28 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "os_str_bytes" -version = "6.1.0" +version = "6.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21326818e99cfe6ce1e524c2a805c189a99b5ae555a35d19f9a284b427d86afa" +checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" [[package]] name = "p256" -version = "0.9.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d053368e1bae4c8a672953397bd1bd7183dde1c72b0b7612a15719173148d186" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" dependencies = [ "ecdsa", "elliptic-curve", - "sha2", + "sha2 0.10.6", ] [[package]] name = "pairing" -version = "0.20.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7de9d09263c9966e8196fe0380c9dbbc7ea114b5cf371ba29004bc1f9c6db7f3" +checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b" dependencies = [ - "group 0.10.0", -] - -[[package]] -name = "pairing" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2e415e349a3006dd7d9482cdab1c980a845bed1377777d768cb693a44540b42" -dependencies = [ - "group 0.11.0", + "group", ] [[package]] @@ -1279,11 +1274,11 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "smallvec", @@ -1310,9 +1305,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs8" -version = "0.7.6" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3ef9b64d26bad0536099c816c6734379e45bbd5f14798def6809e5cc350447" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" dependencies = [ "der", "spki", @@ -1320,9 +1315,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" @@ -1361,9 +1356,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.40" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" dependencies = [ "unicode-ident", ] @@ -1375,7 +1370,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0d9cc07f18492d879586c92b485def06bc850da3118075cd45d50e9c95b0e5" dependencies = [ "bit-set", - "bitflags", + "bitflags 1.3.2", "byteorder", "lazy_static", "num-traits", @@ -1402,18 +1397,18 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quote" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" dependencies = [ "proc-macro2", ] [[package]] name = "radium" -version = "0.6.2" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643f8f41a8ebc4c5dc4515c82bb8abd397b527fc20fd681b7c011c2aee5d44fb" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" @@ -1501,7 +1496,7 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1515,22 +1510,11 @@ dependencies = [ "thiserror", ] -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - [[package]] name = "regex-syntax" -version = "0.6.27" +version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" [[package]] name = "remove_dir_all" @@ -1538,37 +1522,27 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] -name = "riscv" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6907ccdd7a31012b70faf2af85cd9e5ba97657cc3987c4f13f8e4d2c2a088aba" -dependencies = [ - "bare-metal 1.0.0", - "bit_field", - "riscv-target", -] - -[[package]] -name = "riscv-target" -version = "0.1.2" +name = "rfc6979" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88aa938cda42a0cf62a20cfe8d139ff1af20c2e681212b5b34adb5a58333f222" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" dependencies = [ - "lazy_static", - "regex", + "crypto-bigint", + "hmac 0.12.1", + "zeroize", ] [[package]] name = "rustc_version" -version = "0.2.3" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "c5f5376ea5e30ce23c03eb77cbe4962b988deead10910c372b226388b594c084" dependencies = [ - "semver 0.9.0", + "semver 0.1.20", ] [[package]] @@ -1614,49 +1588,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] -name = "semver" -version = "0.9.0" +name = "sec1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ - "semver-parser", + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", ] [[package]] name = "semver" -version = "1.0.14" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" [[package]] -name = "semver-parser" -version = "0.7.0" +name = "semver" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" [[package]] name = "serde" -version = "1.0.145" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b" +checksum = "97fed41fc1a24994d044e6db6935e69511a1153b52c15eb42493b26fa87feba0" dependencies = [ "serde_derive", ] -[[package]] -name = "serde-big-array" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd31f59f6fe2b0c055371bb2f16d7f0aa7d8881676c04a55b1596d1a17cd10a4" -dependencies = [ - "serde", -] - [[package]] name = "serde_derive" -version = "1.0.145" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c" +checksum = "255abe9a125a985c05190d687b320c12f9b1f0b99445e608c21ba0782c719ad8" dependencies = [ "proc-macro2", "quote", @@ -1665,9 +1635,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.87" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" +checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" dependencies = [ "itoa", "ryu", @@ -1718,49 +1688,41 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer", - "cfg-if", + "block-buffer 0.9.0", + "cfg-if 1.0.0", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] [[package]] -name = "signal-hook-registry" -version = "1.4.0" +name = "sha2" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" dependencies = [ - "libc", + "cfg-if 1.0.0", + "cpufeatures", + "digest 0.10.6", ] [[package]] -name = "signature" -version = "1.3.2" +name = "signal-hook-registry" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" dependencies = [ - "digest", - "rand_core 0.6.4", + "libc", ] [[package]] -name = "signature_bls" -version = "0.30.0" +name = "signature" +version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b7cca12d2cd1d6d2fffa0375cfc94485acc2a871fc82ac77393487132b5456" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" dependencies = [ - "bls12_381_plus 0.5.2", - "ff 0.10.1", - "group 0.10.0", - "hkdf", - "pairing 0.20.0", + "digest 0.10.6", "rand_core 0.6.4", - "serde", - "sha2", - "subtle", - "vsss-rs", - "zeroize", ] [[package]] @@ -1785,7 +1747,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" dependencies = [ "libc", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -1799,10 +1761,11 @@ dependencies = [ [[package]] name = "spki" -version = "0.4.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c01a0c15da1b0b0e1494112e7af814a678fec9bd157881b49beac661e9b6f32" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" dependencies = [ + "base64ct", "der", ] @@ -1832,9 +1795,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.98" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" dependencies = [ "proc-macro2", "quote", @@ -1865,12 +1828,12 @@ version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "fastrand", "libc", "redox_syscall", "remove_dir_all", - "winapi", + "winapi 0.3.9", ] [[package]] @@ -1884,9 +1847,9 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" @@ -1925,9 +1888,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.21.2" +version = "1.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099" +checksum = "eab6d665857cc6ca78d6e80303a02cea7a7851e85dfbd77cbdc09bd129f1ef46" dependencies = [ "autocfg", "bytes", @@ -1940,14 +1903,14 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "winapi", + "windows-sys", ] [[package]] name = "tokio-macros" -version = "1.8.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8" dependencies = [ "proc-macro2", "quote", @@ -2003,7 +1966,7 @@ version = "0.1.37" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "pin-project-lite", "tracing-attributes", "tracing-core", @@ -2029,6 +1992,15 @@ dependencies = [ "once_cell", ] +[[package]] +name = "treediff" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "761e8d5ad7ce14bb82b7e61ccc0ca961005a275a060b9644a2431aa11553c2ff" +dependencies = [ + "serde_json", +] + [[package]] name = "try-lock" version = "0.2.3" @@ -2037,9 +2009,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "unicase" @@ -2058,9 +2030,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.1" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" +checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" [[package]] name = "unicode-normalization" @@ -2100,12 +2072,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "vcell" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" - [[package]] name = "version_check" version = "0.9.4" @@ -2118,31 +2084,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" -[[package]] -name = "volatile-register" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee8f19f9d74293faf70901bc20ad067dc1ad390d2cbf1e3f75f721ffee908b6" -dependencies = [ - "vcell", -] - -[[package]] -name = "vsss-rs" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f509df857e50af93bea4921d55f66a719d2b5f1f6d066abe7f21800448d09ca" -dependencies = [ - "ff 0.10.1", - "group 0.10.0", - "rand_chacha 0.3.1", - "rand_core 0.6.4", - "serde", - "serde-big-array", - "sha2", - "zeroize", -] - [[package]] name = "wait-timeout" version = "0.2.0" @@ -2159,7 +2100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", - "winapi", + "winapi 0.3.9", "winapi-util", ] @@ -2191,7 +2132,7 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "wasm-bindgen-macro", ] @@ -2239,6 +2180,12 @@ version = "0.2.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + [[package]] name = "winapi" version = "0.3.9" @@ -2249,6 +2196,12 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -2261,7 +2214,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi", + "winapi 0.3.9", ] [[package]] @@ -2329,9 +2282,9 @@ checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" [[package]] name = "wyz" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "129e027ad65ce1453680623c3fb5163cbf7107bfe1aa32257e7d0e63f9ced188" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" dependencies = [ "tap", ] @@ -2349,18 +2302,18 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.4.3" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d68d9dcec5f9b43a30d38c49f91dfedfaac384cb8f085faca366c26207dd1619" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.3.2" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 33b7904..3aca15a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,22 +7,23 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -anyhow = "1.0.66" -bs58 = "0.4.0" -base64 = "0.13.0" -clap = { version = "3.2.12", features = ["derive"] } -did-key = "0.1.1" -colored = "2.0.0" +anyhow = "1.0" +bs58 = "0.4" +base64 = "0.20" +clap = { version = "3.2", features = ["derive"] } +did-key = "0.2" +colored = "2.0" serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0.87" +serde_json = "1.0" hyper = { version = "0.14", features = ["full"] } -bytes = "1.2.1" +bytes = "1.2" tokio = { version = "1", features = ["full"] } -async-trait = "0.1.58" -futures = "0.3.25" +async-trait = "0.1" +futures = "0.3" ipfs-api-backend-hyper = "0.5" -walkdir = "2.3.2" +walkdir = "2.3" +graceful = "0.1" [dev-dependencies] -proptest = "1.0.0" -serial_test = "0.9.0" \ No newline at end of file +proptest = "1.0" +serial_test = "0.9" \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 495da6c..ff23315 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,9 +1,10 @@ -use std::process::{Child, Command}; +use std::process::Command; use std::collections::HashMap; -use std::thread::sleep; +use std::thread::{spawn, sleep}; use std::time::{SystemTime, Duration}; use futures::executor::block_on; +use graceful::SignalGuard; use serde_json::Value; use tokio::runtime::Runtime; use ipfs_api_backend_hyper::{TryFromUri, IpfsClient, IpfsApi, LoggingLevel, Logger}; @@ -15,11 +16,9 @@ use std::path::Path; use crate::ipfs::Ipfs; use crate::utils::config::{IPFS_ADDR, IPFS_API_PORT, IPFS_EXE, IPFS_SLEEP_LENGTH, IPFS_BOOT_TIME_OUT}; - pub struct IpfsDaemon { - proccess: Option, client: IpfsClient, - tokio:Runtime + tokio: Runtime } impl IpfsDaemon { @@ -28,50 +27,61 @@ impl IpfsDaemon { let runtime = tokio::runtime::Runtime::new().unwrap(); Ok(Self{ - proccess: None, client, tokio: runtime }) } - pub fn has_launched(&self) -> bool{ - self.proccess.is_some() - } - pub async fn launch(&mut self) -> Result<()>{ + pub async fn launch(&self) -> Result<()>{ + //launch the daemon let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); println!("Launhing IPFS..."); - let proccess = Command::new(IPFS_EXE) + Command::new(IPFS_EXE) .arg("--api") .arg(&api_addr) .arg("daemon") .spawn() .unwrap_or_else(|e| panic!("Failed to start IPFS daemon: {}\n This error may be because the Kubo binary is not on your PATH.", e)); - self.proccess = Some(proccess); + + //Wait ipfs to ready println!("Waiting for IPFS to ready.."); self.await_ready().await?; + + //Reduce log level for IPFS self.tokio.block_on(async { self.client.log_level(Logger::All, LoggingLevel::Error).await })?; + + //setup gracefull shutdown + println!("Creating gracefull shutdown for IPFS..."); + let me = self.clone(); + spawn(move || { + let signal_guard = SignalGuard::new(); + + signal_guard.at_exit(move |sig| { + println!("Signal {} received. Attempting to stop IPFS...", sig); + match me.shutdown() { + Ok(_) => println!("{}", "IPFS has shutdown successfully.".green()), + Err(_) => println!("{}", "IPFS failed to shutdown succefully! You may need to stop the proccess yourself.".red()) + }; + }); + }); + + println!("{}", "IPFS has launched successfully!!".green()); Ok(()) } - pub fn shutdown(&mut self) -> Result<()>{ - Ok(match self.proccess.as_mut() { - Some(process) => { - self.tokio.block_on(async { - block_on(self.client.shutdown()) - })?; - process.wait()?; - self.proccess = None; - }, - None => () - }) + pub fn shutdown(&self) -> Result<()>{ + self.tokio.block_on(async { + block_on(self.client.shutdown()) + })?; + Ok(()) } async fn is_ipfs_ready(&self) -> bool { let res = self.tokio.block_on(async { - self.client.config_get_json("API").await + self.client.config_show().await }); - if res.is_ok() { - println!("Config is {}", res.as_ref().unwrap().value); - } + // if res.is_ok() { + // println!("Config is {}", res.as_ref().unwrap()); + // } return match res { Ok(_) => true, Err(_) => false @@ -101,6 +111,12 @@ impl IpfsDaemon { } } +impl Clone for IpfsDaemon { + fn clone(&self) -> Self { + return Self { client: self.client.clone(), tokio: Runtime::new().unwrap() } + } +} + #[async_trait] impl Ipfs for IpfsDaemon { async fn add(&self, path: &Path) -> Result> { diff --git a/src/ipfs/tests.rs b/src/ipfs/tests.rs index 8f52137..1727c78 100644 --- a/src/ipfs/tests.rs +++ b/src/ipfs/tests.rs @@ -28,7 +28,7 @@ use crate::utils::file_management; fn run_ipfs_test(test: T) -> () where T: FnOnce(&IpfsDaemon) -> bool { - let mut ipfs = IpfsDaemon::new().unwrap(); + let ipfs = IpfsDaemon::new().unwrap(); // for peer in PEER_ADDRS { // block_on(ipfs.connect_to(peer)).unwrap(); // println!("Connected to peer! {}", peer); From d48cc24df046bcc44285e7ac00b5bbd735f4a271 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Sat, 17 Dec 2022 11:44:39 -0600 Subject: [PATCH 50/63] add bootstap start --- src/ipfs.rs | 5 ++-- src/ipfs/daemon.rs | 22 ++++++++++---- src/ipfs/tests.rs | 72 ++++++++++++++++++++++++++++------------------ src/utils/http.rs | 6 +--- 4 files changed, 64 insertions(+), 41 deletions(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index 1961914..a562d87 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -12,9 +12,8 @@ pub mod tests; #[async_trait] pub trait Ipfs { async fn add(&self, path:&Path) -> Result>; - async fn connect_to(&self, peer_id:&str) -> Result<()>; + async fn add_bootstrap(&self, peer_id:&str) -> Result<()>; + async fn get_connected(&self) -> Result>; async fn set_config(&self, property:&str, val:&Value) -> Result<()>; async fn get_config(&self, property:&str) -> Result; - // async fn set_config(&self, options:&Config) -> Result<()>; - // async fn get_config(&self) -> Result; } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index ff23315..9c0bd7c 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,6 +1,6 @@ use std::process::Command; use std::collections::HashMap; -use std::thread::{spawn, sleep}; +use std::thread; use std::time::{SystemTime, Duration}; use futures::executor::block_on; @@ -54,7 +54,7 @@ impl IpfsDaemon { //setup gracefull shutdown println!("Creating gracefull shutdown for IPFS..."); let me = self.clone(); - spawn(move || { + thread::spawn(move || { let signal_guard = SignalGuard::new(); signal_guard.at_exit(move |sig| { @@ -97,7 +97,7 @@ impl IpfsDaemon { break; } - sleep(Duration::new(IPFS_SLEEP_LENGTH as u64, 0)); + thread::sleep(Duration::new(IPFS_SLEEP_LENGTH as u64, 0)); let now = SystemTime::now(); if now.duration_since(start_time)? > Duration::new(IPFS_BOOT_TIME_OUT as u64, 0) { @@ -127,8 +127,20 @@ impl Ipfs for IpfsDaemon { (res.name, res.hash) }).collect()); } - async fn connect_to(&self, peer_id: &str) -> Result<()> { - todo!() + async fn add_bootstrap(&self, peer_id: &str) -> Result<()> { + let mut old_peers = self.get_config("Bootstrap") + .await? + .as_array() + .unwrap() + .clone(); + old_peers.push(Value::String(peer_id.to_string())); + self.set_config("Bootstrap", &Value::Array(old_peers)).await + } + async fn get_connected(&self) -> Result> { + let peers = self.tokio.block_on(async { + self.client.swarm_peers().await + })?; + Ok(peers.peers.into_iter().map(|peer| peer.addr).collect()) } async fn get_config(&self, prop:&str) -> Result{ let config = self.tokio.block_on(async { diff --git a/src/ipfs/tests.rs b/src/ipfs/tests.rs index 1727c78..5b322b4 100644 --- a/src/ipfs/tests.rs +++ b/src/ipfs/tests.rs @@ -1,3 +1,6 @@ +use std::thread; +use std::time::Duration; + use colored::Colorize; use futures::executor::block_on; use serial_test::serial; @@ -7,23 +10,6 @@ use super::*; use crate::ipfs::Ipfs; use crate::utils::file_management; -//TODO: Setup pizza -// const PEER_ADDRS:&'static [&'static str] = &[ -// "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", -// "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", -// "/dns4/production-ipfs-cluster-eu-north-1-node1.runfission.com/tcp/4001/p2p/12D3KooWRwbRrSN2cPAKz4yt1vxBFdh53CpgWjSFK5hZPkzHHz5h", -// "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", -// "/ip4/54.235.17.70/tcp/4001/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", -// "/ip4/54.235.17.70/udp/4001/quic/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", -// "/dns4/production-ipfs-cluster-mega-us-east-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", -// "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4001/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ", -// "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4001/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", -// "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4001/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", -// "/dns4/production-ipfs-cluster-eu-north-1-node0.runfission.com/tcp/4003/wss/p2p/12D3KooWDTUTdVJfW7Rwb6kKhceEwevTatPXnavPwkfZp2A6r1Fn", -// "/ip4/54.235.17.70/tcp/4003/wss/p2p/12D3KooWJQHUo1snJrv5NWVesFspjwhkNkaMu5M9cMdF1oF7ucTz", -// "/dns4/production-ipfs-cluster-us-east-1-node1.runfission.com/tcp/4003/wss/p2p/12D3KooWNntMEXRUa2dNgkQsVgzao6zGSYxm1oAs83YtRy6uBuxv", -// ]; - fn run_ipfs_test(test: T) -> () where T: FnOnce(&IpfsDaemon) -> bool @@ -42,31 +28,29 @@ fn run_ipfs_test(test: T) -> () fn are_files_uploaded(uploaded_paths:Vec, os_paths:Vec) -> bool{ let mut is_uploaded = true; for os_path in os_paths{ - let mut fixed_path_os_path = String::new(); - let mut i = 0; - for seg in os_path.split("/") { + let mut fixed_os_path = String::new(); + for (i, seg) in os_path.split("/").enumerate() { if seg != "." && !seg.is_empty() { - fixed_path_os_path += &(match i { - 0 => String::new(), - 1 => seg.to_string(), + fixed_os_path += &(match i { + 1 => String::new(), + 2 => seg.to_string(), _ => "/".to_string() + seg }); - i += 1; } } let mut is_any_matching = false; 'any: for uploaded_path in &uploaded_paths { - if &fixed_path_os_path == uploaded_path { - println!("{} == {}", fixed_path_os_path.green(), uploaded_path.green()); + if &fixed_os_path == uploaded_path { + println!("{} == {}", fixed_os_path.green(), uploaded_path.green()); is_any_matching = true; break 'any; }else{ - println!("{} == {}", fixed_path_os_path.red(), uploaded_path.red()); + println!("{} == {}", fixed_os_path.red(), uploaded_path.red()); } }; if !is_any_matching{ - println!("Failed to match {}", fixed_path_os_path.red()); + println!("Failed to match {}", fixed_os_path.red()); is_uploaded = false; } } @@ -127,3 +111,35 @@ fn can_config() { test_value == new_config }); } +#[test] +#[serial] +fn can_add_bootstrap() { + //TODO: Setup pizza + let test_peer = "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ"; + run_ipfs_test(|ipfs| { + block_on(ipfs.add_bootstrap(test_peer)).unwrap(); + let is_config_changed = block_on(ipfs.get_config("Bootstrap")) + .unwrap() + .as_array() + .unwrap() + .contains(&Value::String(test_peer.to_string())); + if !is_config_changed { + println!("{}", "Config failed to be changed!".red()); + } + is_config_changed + }); + thread::sleep(Duration::new(3, 0));//This is to give IPFS enough time to shut down properly + run_ipfs_test(|ipfs| { + let peers = block_on(ipfs.get_connected()).unwrap(); + peers.iter().for_each(|peer| println!("{}", peer.blue())); + let is_config_changed = block_on(ipfs.get_config("Bootstrap")) + .unwrap() + .as_array() + .unwrap() + .contains(&Value::String(test_peer.to_string())); + if !is_config_changed { + println!("{}", "Config failed to be changed!".red()) + } + peers.contains(&test_peer.to_string()) + }); +} \ No newline at end of file diff --git a/src/utils/http.rs b/src/utils/http.rs index 872f877..018b627 100644 --- a/src/utils/http.rs +++ b/src/utils/http.rs @@ -3,7 +3,6 @@ */ use std::{ - time::Duration, collections::HashMap, io::Write }; @@ -18,10 +17,7 @@ use hyper::{ body::HttpBody }; -use crate::utils::{ - config::*, - math -}; +use crate::utils::config::*; pub struct PostOptions { From e3a8750bd5e5b02f24d68e9b768aa46f268d7647 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Sat, 17 Dec 2022 14:13:40 -0600 Subject: [PATCH 51/63] Adding Documentation --- src/ipfs.rs | 11 +++++++ src/ipfs/daemon.rs | 82 ++++++++++++++++++++++++++++++++++++---------- src/ipfs/tests.rs | 2 +- 3 files changed, 77 insertions(+), 18 deletions(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index a562d87..d9ab13e 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -11,9 +11,20 @@ pub mod tests; #[async_trait] pub trait Ipfs { + /// This method upload a given file or directory at a given path to the IPFS swarm you are + /// currently connected to. async fn add(&self, path:&Path) -> Result>; + /// This method adds a given address to the list bootstrap peers in the config. This + /// fuction will not take affect until after a restart of the daemon. async fn add_bootstrap(&self, peer_id:&str) -> Result<()>; + /// This method will return a list of all the addresses that are currently connected async fn get_connected(&self) -> Result>; + /// This method will change a the value of a given property in the IPFS config + /// + /// Ex. `ipfs.set_config("Datastore.StorageMax", "11GB")` async fn set_config(&self, property:&str, val:&Value) -> Result<()>; + /// This method will return the value a given property in the IPFS config + /// + /// Ex. `ipfs.get_config("Datastore.StorageMax")` async fn get_config(&self, property:&str) -> Result; } \ No newline at end of file diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 9c0bd7c..ac3876c 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,39 +1,43 @@ -use std::process::Command; + use std::collections::HashMap; +use std::process::Command; use std::thread; use std::time::{SystemTime, Duration}; +use std::path::Path; +use anyhow::{bail, Result}; +use async_trait::async_trait; +use colored::Colorize; use futures::executor::block_on; use graceful::SignalGuard; +use ipfs_api_backend_hyper::{TryFromUri, IpfsClient, IpfsApi, LoggingLevel, Logger}; use serde_json::Value; use tokio::runtime::Runtime; -use ipfs_api_backend_hyper::{TryFromUri, IpfsClient, IpfsApi, LoggingLevel, Logger}; -use anyhow::{bail, Result}; -use async_trait::async_trait; -use colored::Colorize; -use std::path::Path; use crate::ipfs::Ipfs; use crate::utils::config::{IPFS_ADDR, IPFS_API_PORT, IPFS_EXE, IPFS_SLEEP_LENGTH, IPFS_BOOT_TIME_OUT}; +/// This struct is a wrapper for the information needed to point the IPFS daemon at a diffrent address +/// than the default. +#[derive(Clone, Debug)] +pub struct IpfsConnInfo { + pub address:String, + pub port:u16 +} + pub struct IpfsDaemon { + conn_info: IpfsConnInfo, client: IpfsClient, tokio: Runtime } impl IpfsDaemon { - pub fn new() -> Result { - let client = IpfsClient::from_host_and_port("http".parse()?, IPFS_ADDR, IPFS_API_PORT)?; - - let runtime = tokio::runtime::Runtime::new().unwrap(); - Ok(Self{ - client, - tokio: runtime - }) - } + /// This method launches the IPFS daemon on the port/address given when the the instance was + /// created. During this proccess it also creates a thread that listens for a shutdown signal + /// and stops the IPFS daemon gracefully if the signal is given. pub async fn launch(&self) -> Result<()>{ //launch the daemon - let api_addr = format!("/ip4/{}/tcp/{}", IPFS_ADDR, IPFS_API_PORT); + let api_addr = format!("/ip4/{}/tcp/{}", self.conn_info.address, self.conn_info.port); println!("Launhing IPFS..."); Command::new(IPFS_EXE) .arg("--api") @@ -69,12 +73,20 @@ impl IpfsDaemon { println!("{}", "IPFS has launched successfully!!".green()); Ok(()) } + + /// This method sends an http signal to the IPFS deamon to shutdown. + /// + /// Note 1: This method should work even if the daemon was not started by this proccess. + /// + /// Note 2: This method return when it recieves an http response from the daemon, and not + /// when the proccess has actually stopped. pub fn shutdown(&self) -> Result<()>{ self.tokio.block_on(async { block_on(self.client.shutdown()) })?; Ok(()) } + async fn is_ipfs_ready(&self) -> bool { let res = self.tokio.block_on(async { self.client.config_show().await @@ -87,6 +99,7 @@ impl IpfsDaemon { Err(_) => false }; } + async fn await_ready(&self) -> Result<()> { let start_time = SystemTime::now(); loop { @@ -111,9 +124,44 @@ impl IpfsDaemon { } } +impl TryFrom for IpfsDaemon{ + type Error = anyhow::Error; + /// This is one of the two main ways to make a new instance of the IPFS daemon struct. Use this + /// method when you want to make a new instance and you need to set the port and address of + /// the daemon you are attempting to refrence + fn try_from(conn_info: IpfsConnInfo) -> Result { + let client = IpfsClient::from_host_and_port( + "http".parse()?, + &conn_info.address, + conn_info.port + )?; + + let runtime = tokio::runtime::Runtime::new()?; + Ok(Self{ + client, + tokio: runtime, + conn_info + }) + } +} + +impl Default for IpfsDaemon { + /// This is one of the two main ways to make a new instance of the IPFS daemon struct. Use this + /// method when you want to make a new instance and you okay with using the default port and address + /// set by the config. + /// + /// Note: This method has the possiblity of throwing an error if the configuration of the port and + /// address is not setup right. + fn default() -> Self { + Self::try_from(IpfsConnInfo{ + address:IPFS_ADDR.to_string(), + port:IPFS_API_PORT + }).unwrap() + } +} impl Clone for IpfsDaemon { fn clone(&self) -> Self { - return Self { client: self.client.clone(), tokio: Runtime::new().unwrap() } + return Self { client: self.client.clone(), tokio: Runtime::new().unwrap(), conn_info: self.conn_info.clone()} } } diff --git a/src/ipfs/tests.rs b/src/ipfs/tests.rs index 5b322b4..39f519f 100644 --- a/src/ipfs/tests.rs +++ b/src/ipfs/tests.rs @@ -14,7 +14,7 @@ use crate::utils::file_management; fn run_ipfs_test(test: T) -> () where T: FnOnce(&IpfsDaemon) -> bool { - let ipfs = IpfsDaemon::new().unwrap(); + let ipfs = IpfsDaemon::default(); // for peer in PEER_ADDRS { // block_on(ipfs.connect_to(peer)).unwrap(); // println!("Connected to peer! {}", peer); From 524330238817d18f8e9204727fdba9702fedfbe3 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Thu, 29 Dec 2022 11:57:05 -0600 Subject: [PATCH 52/63] connect to --- Cargo.lock | 77 +++++++++++++++++++++++++--------------------- Cargo.toml | 2 +- src/ipfs.rs | 5 ++- src/ipfs/daemon.rs | 19 +++++++----- src/ipfs/tests.rs | 29 ++--------------- 5 files changed, 59 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a39a28..5cc039d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.66" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61" [[package]] name = "arrayref" @@ -16,9 +16,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "async-trait" -version = "0.1.59" +version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364" +checksum = "677d1d8ab452a3936018a687b20e6f7cf5363d713b732b8884001317b0e48aa3" dependencies = [ "proc-macro2", "quote", @@ -40,7 +40,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi 0.3.9", ] @@ -788,6 +788,15 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + [[package]] name = "hkdf" version = "0.11.0" @@ -950,8 +959,7 @@ dependencies = [ [[package]] name = "ipfs-api-backend-hyper" version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "114341e043a87eff0e43ec192f0a495988323dc14c468448e62b20aaf96bd1e6" +source = "git+https://github.com/BoisterousCoder/rust-ipfs-api.git#0ce502ad69c114ad5ea715ad431361bf136a25d3" dependencies = [ "async-trait", "bytes", @@ -966,8 +974,7 @@ dependencies = [ [[package]] name = "ipfs-api-prelude" version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf47fa129710ae041d5844a15b1365bdad8551673aee237449ba9dec6bcadc" +source = "git+https://github.com/BoisterousCoder/rust-ipfs-api.git#0ce502ad69c114ad5ea715ad431361bf136a25d3" dependencies = [ "async-trait", "bytes", @@ -990,9 +997,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" [[package]] name = "js-sys" @@ -1032,9 +1039,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.138" +version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" [[package]] name = "libsecp256k1" @@ -1198,11 +1205,11 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] @@ -1356,9 +1363,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5" dependencies = [ "unicode-ident", ] @@ -1397,9 +1404,9 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quote" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" dependencies = [ "proc-macro2", ] @@ -1551,7 +1558,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "semver 1.0.14", + "semver 1.0.16", ] [[package]] @@ -1568,9 +1575,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.11" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde" [[package]] name = "same-file" @@ -1609,9 +1616,9 @@ checksum = "d4f410fedcf71af0345d7607d246e7ad15faaadd49d240ee3b24e5dc21a820ac" [[package]] name = "semver" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" [[package]] name = "serde" @@ -1635,9 +1642,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883" dependencies = [ "itoa", "ryu", @@ -1795,9 +1802,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.105" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908" +checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" dependencies = [ "proc-macro2", "quote", @@ -1853,18 +1860,18 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" dependencies = [ "proc-macro2", "quote", @@ -2030,9 +2037,9 @@ checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" [[package]] name = "unicode-normalization" diff --git a/Cargo.toml b/Cargo.toml index 3aca15a..a0e4cbe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ bytes = "1.2" tokio = { version = "1", features = ["full"] } async-trait = "0.1" futures = "0.3" -ipfs-api-backend-hyper = "0.5" +ipfs-api-backend-hyper = {git="https://github.com/BoisterousCoder/rust-ipfs-api.git"} #This is temporary until change get merge and released into the main package walkdir = "2.3" graceful = "0.1" diff --git a/src/ipfs.rs b/src/ipfs.rs index d9ab13e..5b24d36 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -14,9 +14,8 @@ pub trait Ipfs { /// This method upload a given file or directory at a given path to the IPFS swarm you are /// currently connected to. async fn add(&self, path:&Path) -> Result>; - /// This method adds a given address to the list bootstrap peers in the config. This - /// fuction will not take affect until after a restart of the daemon. - async fn add_bootstrap(&self, peer_id:&str) -> Result<()>; + /// This method connect to the given address, adding the address to the current swarm + async fn connect_to(&self, peer_id:&str) -> Result<()>; /// This method will return a list of all the addresses that are currently connected async fn get_connected(&self) -> Result>; /// This method will change a the value of a given property in the IPFS config diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index ac3876c..b334d16 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -175,14 +175,17 @@ impl Ipfs for IpfsDaemon { (res.name, res.hash) }).collect()); } - async fn add_bootstrap(&self, peer_id: &str) -> Result<()> { - let mut old_peers = self.get_config("Bootstrap") - .await? - .as_array() - .unwrap() - .clone(); - old_peers.push(Value::String(peer_id.to_string())); - self.set_config("Bootstrap", &Value::Array(old_peers)).await + async fn connect_to(&self, peer_id: &str) -> Result<()> { + let messages = self.tokio.block_on(async { + self.client.swarm_connect(peer_id).await + })?.strings; + for msg in messages { + println!("{}", msg.blue()); + if !msg.contains("success"){ + bail!(msg); + } + } + return Ok(()); } async fn get_connected(&self) -> Result> { let peers = self.tokio.block_on(async { diff --git a/src/ipfs/tests.rs b/src/ipfs/tests.rs index 39f519f..82757b7 100644 --- a/src/ipfs/tests.rs +++ b/src/ipfs/tests.rs @@ -113,33 +113,10 @@ fn can_config() { } #[test] #[serial] -fn can_add_bootstrap() { - //TODO: Setup pizza +fn can_connect() { let test_peer = "/dns4/production-ipfs-cluster-us-east-1-node2.runfission.com/tcp/4003/wss/p2p/12D3KooWQ2hL9NschcJ1Suqa1TybJc2ZaacqoQMBT3ziFC7Ye2BZ"; run_ipfs_test(|ipfs| { - block_on(ipfs.add_bootstrap(test_peer)).unwrap(); - let is_config_changed = block_on(ipfs.get_config("Bootstrap")) - .unwrap() - .as_array() - .unwrap() - .contains(&Value::String(test_peer.to_string())); - if !is_config_changed { - println!("{}", "Config failed to be changed!".red()); - } - is_config_changed - }); - thread::sleep(Duration::new(3, 0));//This is to give IPFS enough time to shut down properly - run_ipfs_test(|ipfs| { - let peers = block_on(ipfs.get_connected()).unwrap(); - peers.iter().for_each(|peer| println!("{}", peer.blue())); - let is_config_changed = block_on(ipfs.get_config("Bootstrap")) - .unwrap() - .as_array() - .unwrap() - .contains(&Value::String(test_peer.to_string())); - if !is_config_changed { - println!("{}", "Config failed to be changed!".red()) - } - peers.contains(&test_peer.to_string()) + let res = block_on(ipfs.connect_to(test_peer)); + res.is_ok() }); } \ No newline at end of file From 0758c6b6f342143fa4e9539ba1131b28e1b934be Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 3 Jan 2023 12:42:00 -0600 Subject: [PATCH 53/63] switch to main fork for ipfs-api the changes I made to to my fork were merged with master --- Cargo.lock | 99 +++++++++++++++++++++++++----------------------------- Cargo.toml | 2 +- 2 files changed, 46 insertions(+), 55 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5cc039d..8042852 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -263,6 +263,15 @@ version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +[[package]] +name = "core2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505" +dependencies = [ + "memchr", +] + [[package]] name = "cpufeatures" version = "0.2.5" @@ -741,7 +750,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util 0.7.4", + "tokio-util", "tracing", ] @@ -958,10 +967,12 @@ dependencies = [ [[package]] name = "ipfs-api-backend-hyper" -version = "0.5.0" -source = "git+https://github.com/BoisterousCoder/rust-ipfs-api.git#0ce502ad69c114ad5ea715ad431361bf136a25d3" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9d131b408b4caafe1e7c00d410a09ad3eb7e3ab68690cf668e86904b2176b4" dependencies = [ "async-trait", + "base64 0.13.1", "bytes", "futures", "http", @@ -973,8 +984,9 @@ dependencies = [ [[package]] name = "ipfs-api-prelude" -version = "0.5.0" -source = "git+https://github.com/BoisterousCoder/rust-ipfs-api.git#0ce502ad69c114ad5ea715ad431361bf136a25d3" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b74065805db266ba2c6edbd670b23c4714824a955628472b2e46cc9f3a869cb" dependencies = [ "async-trait", "bytes", @@ -983,14 +995,14 @@ dependencies = [ "dirs", "futures", "http", + "multiaddr", "multibase", - "parity-multiaddr", "serde", "serde_json", "serde_urlencoded", "thiserror", "tokio", - "tokio-util 0.6.10", + "tokio-util", "tracing", "walkdir", ] @@ -1144,6 +1156,24 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "multiaddr" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b53e0cc5907a5c216ba6584bf74be8ab47d6d6289f72793b2dddbf15dc3bf8c" +dependencies = [ + "arrayref", + "byteorder", + "data-encoding", + "multibase", + "multihash", + "percent-encoding", + "serde", + "static_assertions", + "unsigned-varint", + "url", +] + [[package]] name = "multibase" version = "0.9.1" @@ -1157,20 +1187,20 @@ dependencies = [ [[package]] name = "multihash" -version = "0.13.2" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dac63698b887d2d929306ea48b63760431ff8a24fac40ddb22f9c7f49fb7cab" +checksum = "835d6ff01d610179fbce3de1694d007e500bf33a7f29689838941d6bf783ae40" dependencies = [ - "generic-array", + "core2", "multihash-derive", - "unsigned-varint 0.5.1", + "unsigned-varint", ] [[package]] name = "multihash-derive" -version = "0.7.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "424f6e86263cd5294cbd7f1e95746b95aca0e0d66bff31e5a40d6baa87b4aa99" +checksum = "1d6d4752e6230d8ef7adf7bd5d8c4b1f6561c1014c5ba9a37445ccefe18aa1db" dependencies = [ "proc-macro-crate", "proc-macro-error", @@ -1251,24 +1281,6 @@ dependencies = [ "group", ] -[[package]] -name = "parity-multiaddr" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58341485071825827b7f03cf7efd1cb21e6a709bea778fb50227fd45d2f361b4" -dependencies = [ - "arrayref", - "bs58", - "byteorder", - "data-encoding", - "multihash", - "percent-encoding", - "serde", - "static_assertions", - "unsigned-varint 0.7.1", - "url", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -1328,11 +1340,10 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" -version = "1.2.1" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9" +checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" dependencies = [ - "once_cell", "thiserror", "toml", ] @@ -1924,20 +1935,6 @@ dependencies = [ "syn", ] -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-util" version = "0.7.4" @@ -2056,12 +2053,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" -[[package]] -name = "unsigned-varint" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fdeedbf205afadfe39ae559b75c3240f24e257d0ca27e85f85cb82aa19ac35" - [[package]] name = "unsigned-varint" version = "0.7.1" diff --git a/Cargo.toml b/Cargo.toml index a0e4cbe..029fd0c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ bytes = "1.2" tokio = { version = "1", features = ["full"] } async-trait = "0.1" futures = "0.3" -ipfs-api-backend-hyper = {git="https://github.com/BoisterousCoder/rust-ipfs-api.git"} #This is temporary until change get merge and released into the main package +ipfs-api-backend-hyper = "0.6" walkdir = "2.3" graceful = "0.1" From b1b8126158ee744b8b11903d40907d83144263b9 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 4 Jan 2023 16:04:05 -0600 Subject: [PATCH 54/63] Update src/ipfs.rs Co-authored-by: Brian Ginsburg <7957636+bgins@users.noreply.github.com> Signed-off-by: Savannah Jackson --- src/ipfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index 5b24d36..dccd4ef 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -16,7 +16,7 @@ pub trait Ipfs { async fn add(&self, path:&Path) -> Result>; /// This method connect to the given address, adding the address to the current swarm async fn connect_to(&self, peer_id:&str) -> Result<()>; - /// This method will return a list of all the addresses that are currently connected + /// This method returns a list of all the addresses that are currently connected async fn get_connected(&self) -> Result>; /// This method will change a the value of a given property in the IPFS config /// From 88eea6c405c1b8ef6d5e52b0a9ce77daa7b5fc7c Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 4 Jan 2023 16:04:15 -0600 Subject: [PATCH 55/63] Update src/ipfs.rs Co-authored-by: Brian Ginsburg <7957636+bgins@users.noreply.github.com> Signed-off-by: Savannah Jackson --- src/ipfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index dccd4ef..e08c7ee 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -18,7 +18,7 @@ pub trait Ipfs { async fn connect_to(&self, peer_id:&str) -> Result<()>; /// This method returns a list of all the addresses that are currently connected async fn get_connected(&self) -> Result>; - /// This method will change a the value of a given property in the IPFS config + /// This method changes the value of a given property in the IPFS config /// /// Ex. `ipfs.set_config("Datastore.StorageMax", "11GB")` async fn set_config(&self, property:&str, val:&Value) -> Result<()>; From 09fae95ba828c2122e634e0c72563d58d907b99e Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 4 Jan 2023 16:04:28 -0600 Subject: [PATCH 56/63] Update src/ipfs.rs Co-authored-by: Brian Ginsburg <7957636+bgins@users.noreply.github.com> Signed-off-by: Savannah Jackson --- src/ipfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index e08c7ee..775f003 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -11,7 +11,7 @@ pub mod tests; #[async_trait] pub trait Ipfs { - /// This method upload a given file or directory at a given path to the IPFS swarm you are + /// This method uploads a file or directory at a given path to the IPFS swarm you are /// currently connected to. async fn add(&self, path:&Path) -> Result>; /// This method connect to the given address, adding the address to the current swarm From 3f919c1d83bc59e298fbc9cdbaafec10adda7c7b Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 4 Jan 2023 16:04:39 -0600 Subject: [PATCH 57/63] Update src/ipfs.rs Co-authored-by: Brian Ginsburg <7957636+bgins@users.noreply.github.com> Signed-off-by: Savannah Jackson --- src/ipfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index 775f003..825be5f 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -14,7 +14,7 @@ pub trait Ipfs { /// This method uploads a file or directory at a given path to the IPFS swarm you are /// currently connected to. async fn add(&self, path:&Path) -> Result>; - /// This method connect to the given address, adding the address to the current swarm + /// This method connects to the given address, adding the address to the current swarm async fn connect_to(&self, peer_id:&str) -> Result<()>; /// This method returns a list of all the addresses that are currently connected async fn get_connected(&self) -> Result>; From d3d534496ce9a0b87e97ed0f95ebae570c534720 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 4 Jan 2023 16:06:12 -0600 Subject: [PATCH 58/63] Update src/utils/config.rs Co-authored-by: Brian Ginsburg <7957636+bgins@users.noreply.github.com> Signed-off-by: Savannah Jackson --- src/utils/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/config.rs b/src/utils/config.rs index 37f3a95..4d8b224 100644 --- a/src/utils/config.rs +++ b/src/utils/config.rs @@ -3,5 +3,5 @@ pub const IPFS_RETRY_ATTEMPTS:u16 = 4; pub const IPFS_ADDR:&str = "127.0.0.1"; pub const IPFS_EXE:&str = "ipfs"; pub const HTTP_BOUNDARY:&str = "------------------------I_am_a_boundary_123A123"; -pub const IPFS_BOOT_TIME_OUT:u16 = 45;//In seconds +pub const IPFS_BOOT_TIME_OUT:u16 = 45; // In seconds pub const IPFS_SLEEP_LENGTH:u8 = 1;//In seconds \ No newline at end of file From 5c0bc5ba534eb41d7188d17b63f21ab740f551d0 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 4 Jan 2023 16:06:29 -0600 Subject: [PATCH 59/63] Update src/ipfs.rs Co-authored-by: Brian Ginsburg <7957636+bgins@users.noreply.github.com> Signed-off-by: Savannah Jackson --- src/ipfs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index 825be5f..8683b37 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -22,7 +22,7 @@ pub trait Ipfs { /// /// Ex. `ipfs.set_config("Datastore.StorageMax", "11GB")` async fn set_config(&self, property:&str, val:&Value) -> Result<()>; - /// This method will return the value a given property in the IPFS config + /// This method returns the value a property in the IPFS config /// /// Ex. `ipfs.get_config("Datastore.StorageMax")` async fn get_config(&self, property:&str) -> Result; From 831647fd489af80aa65df972f523a9093fd91aca Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 11 Jan 2023 14:18:46 -0600 Subject: [PATCH 60/63] Accidently made changes to the wrong branch --- src/cmd/generate.rs | 24 ++- src/ipfs.rs | 7 +- src/ipfs/daemon.rs | 151 ++++++++++-------- src/lib.rs | 5 +- src/main.rs | 2 +- src/test.rs | 1 + src/{ipfs/tests.rs => test/daemon.rs} | 84 +++++----- .../test/data}/more-tests/also-test.txt | 0 .../data}/more-tests/even more/noper.nope | 0 .../test/data}/more-tests/fission_logo.png | Bin {test-dir => src/test/data}/test.txt | 0 src/utils/config.rs | 14 +- src/utils/file_management.rs | 23 ++- src/utils/http.rs | 128 ++++++++------- src/utils/json.rs | 59 ------- src/utils/math.rs | 4 +- 16 files changed, 240 insertions(+), 262 deletions(-) create mode 100644 src/test.rs rename src/{ipfs/tests.rs => test/daemon.rs} (58%) rename {test-dir => src/test/data}/more-tests/also-test.txt (100%) rename {test-dir => src/test/data}/more-tests/even more/noper.nope (100%) rename {test-dir => src/test/data}/more-tests/fission_logo.png (100%) rename {test-dir => src/test/data}/test.txt (100%) delete mode 100644 src/utils/json.rs diff --git a/src/cmd/generate.rs b/src/cmd/generate.rs index 2030ce6..85ed717 100644 --- a/src/cmd/generate.rs +++ b/src/cmd/generate.rs @@ -1,6 +1,6 @@ use clap::{Args, Subcommand}; -use did_key::{Ed25519KeyPair, KeyMaterial, DIDCore, Config}; use colored::Colorize; +use did_key::{Config, DIDCore, Ed25519KeyPair, KeyMaterial}; #[derive(Args)] pub struct Generate { @@ -18,10 +18,22 @@ pub fn run_command(g: Generate) { GenerateCommands::Credentials => { let keys = did_key::generate::(None); - println!("{}", "✅ Generated an Ed25519 key pair and associated DID".bright_green()); - println!("🗝️ Private key: {}", base64::encode(keys.private_key_bytes().as_slice()).bright_blue()); - println!("🔑 Public key: {}", base64::encode(keys.public_key_bytes().as_slice()).bright_blue()); - println!("🆔 DID: {}", keys.get_did_document(Config::default()).id.bright_blue()); + println!( + "{}", + "✅ Generated an Ed25519 key pair and associated DID".bright_green() + ); + println!( + "🗝️ Private key: {}", + base64::encode(keys.private_key_bytes().as_slice()).bright_blue() + ); + println!( + "🔑 Public key: {}", + base64::encode(keys.public_key_bytes().as_slice()).bright_blue() + ); + println!( + "🆔 DID: {}", + keys.get_did_document(Config::default()).id.bright_blue() + ); } } -} \ No newline at end of file +} diff --git a/src/ipfs.rs b/src/ipfs.rs index 8683b37..a4a71fe 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -6,9 +6,6 @@ use serde_json::Value; pub mod daemon; -#[cfg(test)] -pub mod tests; - #[async_trait] pub trait Ipfs { /// This method uploads a file or directory at a given path to the IPFS swarm you are @@ -25,5 +22,5 @@ pub trait Ipfs { /// This method returns the value a property in the IPFS config /// /// Ex. `ipfs.get_config("Datastore.StorageMax")` - async fn get_config(&self, property:&str) -> Result; -} \ No newline at end of file + async fn get_config(&self, property: &str) -> Result; +} diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index b334d16..3cea33e 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -1,44 +1,48 @@ - use std::collections::HashMap; +use std::path::Path; use std::process::Command; use std::thread; -use std::time::{SystemTime, Duration}; -use std::path::Path; +use std::time::{Duration, SystemTime}; use anyhow::{bail, Result}; use async_trait::async_trait; use colored::Colorize; use futures::executor::block_on; use graceful::SignalGuard; -use ipfs_api_backend_hyper::{TryFromUri, IpfsClient, IpfsApi, LoggingLevel, Logger}; +use ipfs_api_backend_hyper::{IpfsApi, IpfsClient, Logger, LoggingLevel, TryFromUri}; use serde_json::Value; use tokio::runtime::Runtime; use crate::ipfs::Ipfs; -use crate::utils::config::{IPFS_ADDR, IPFS_API_PORT, IPFS_EXE, IPFS_SLEEP_LENGTH, IPFS_BOOT_TIME_OUT}; +use crate::utils::config::{ + IPFS_ADDR, IPFS_API_PORT, IPFS_BOOT_TIME_OUT, IPFS_EXE, IPFS_SLEEP_LENGTH, +}; /// This struct is a wrapper for the information needed to point the IPFS daemon at a diffrent address /// than the default. #[derive(Clone, Debug)] pub struct IpfsConnInfo { - pub address:String, - pub port:u16 + pub address: String, + pub port: u16, } pub struct IpfsDaemon { conn_info: IpfsConnInfo, client: IpfsClient, - tokio: Runtime + tokio: Runtime, } impl IpfsDaemon { /// This method launches the IPFS daemon on the port/address given when the the instance was /// created. During this proccess it also creates a thread that listens for a shutdown signal /// and stops the IPFS daemon gracefully if the signal is given. - pub async fn launch(&self) -> Result<()>{ + pub async fn launch(&self) -> Result<()> { //launch the daemon - let api_addr = format!("/ip4/{}/tcp/{}", self.conn_info.address, self.conn_info.port); - println!("Launhing IPFS..."); + let api_addr = format!( + "/ip4/{}/tcp/{}", + self.conn_info.address, self.conn_info.port + ); + println!("Launching IPFS..."); Command::new(IPFS_EXE) .arg("--api") .arg(&api_addr) @@ -46,15 +50,17 @@ impl IpfsDaemon { .spawn() .unwrap_or_else(|e| panic!("Failed to start IPFS daemon: {}\n This error may be because the Kubo binary is not on your PATH.", e)); - //Wait ipfs to ready + //Wait ipfs to be ready println!("Waiting for IPFS to ready.."); self.await_ready().await?; //Reduce log level for IPFS self.tokio.block_on(async { - self.client.log_level(Logger::All, LoggingLevel::Error).await + self.client + .log_level(Logger::All, LoggingLevel::Error) + .await })?; - + //setup gracefull shutdown println!("Creating gracefull shutdown for IPFS..."); let me = self.clone(); @@ -74,36 +80,32 @@ impl IpfsDaemon { Ok(()) } - /// This method sends an http signal to the IPFS deamon to shutdown. - /// + /// This method sends an http signal to the IPFS deamon to shutdown. + /// /// Note 1: This method should work even if the daemon was not started by this proccess. - /// + /// /// Note 2: This method return when it recieves an http response from the daemon, and not /// when the proccess has actually stopped. - pub fn shutdown(&self) -> Result<()>{ - self.tokio.block_on(async { - block_on(self.client.shutdown()) - })?; + pub fn shutdown(&self) -> Result<()> { + self.tokio + .block_on(async { block_on(self.client.shutdown()) })?; Ok(()) } async fn is_ipfs_ready(&self) -> bool { - let res = self.tokio.block_on(async { - self.client.config_show().await - }); - // if res.is_ok() { - // println!("Config is {}", res.as_ref().unwrap()); - // } + let res = self + .tokio + .block_on(async { self.client.config_show().await }); return match res { Ok(_) => true, - Err(_) => false + Err(_) => false, }; } async fn await_ready(&self) -> Result<()> { let start_time = SystemTime::now(); loop { - println!("{}", "checking if ipfs is ready...".green()); + println!("{}", "Checking if ipfs is ready...".green()); if self.is_ipfs_ready().await { println!("{}", "IPFS is ready!!".green()); @@ -124,24 +126,21 @@ impl IpfsDaemon { } } -impl TryFrom for IpfsDaemon{ +impl TryFrom for IpfsDaemon { type Error = anyhow::Error; /// This is one of the two main ways to make a new instance of the IPFS daemon struct. Use this /// method when you want to make a new instance and you need to set the port and address of /// the daemon you are attempting to refrence fn try_from(conn_info: IpfsConnInfo) -> Result { - let client = IpfsClient::from_host_and_port( - "http".parse()?, - &conn_info.address, - conn_info.port - )?; + let client = + IpfsClient::from_host_and_port("http".parse()?, &conn_info.address, conn_info.port)?; let runtime = tokio::runtime::Runtime::new()?; - Ok(Self{ + Ok(Self { client, tokio: runtime, - conn_info - }) + conn_info, + }) } } @@ -149,73 +148,89 @@ impl Default for IpfsDaemon { /// This is one of the two main ways to make a new instance of the IPFS daemon struct. Use this /// method when you want to make a new instance and you okay with using the default port and address /// set by the config. - /// + /// /// Note: This method has the possiblity of throwing an error if the configuration of the port and /// address is not setup right. fn default() -> Self { - Self::try_from(IpfsConnInfo{ - address:IPFS_ADDR.to_string(), - port:IPFS_API_PORT - }).unwrap() + Self::try_from(IpfsConnInfo { + address: IPFS_ADDR.to_string(), + port: IPFS_API_PORT, + }) + .unwrap() } } impl Clone for IpfsDaemon { fn clone(&self) -> Self { - return Self { client: self.client.clone(), tokio: Runtime::new().unwrap(), conn_info: self.conn_info.clone()} + return Self { + client: self.client.clone(), + tokio: Runtime::new().unwrap(), + conn_info: self.conn_info.clone(), + }; } } #[async_trait] impl Ipfs for IpfsDaemon { async fn add(&self, path: &Path) -> Result> { - let response_list = self.tokio.block_on(async { - self.client.add_path(path).await - })?; - return Ok(response_list.into_iter().map(|res| { - (res.name, res.hash) - }).collect()); + let response_list = self + .tokio + .block_on(async { self.client.add_path(path).await })?; + return Ok(response_list + .into_iter() + .map(|res| (res.name, res.hash)) + .collect()); } async fn connect_to(&self, peer_id: &str) -> Result<()> { - let messages = self.tokio.block_on(async { - self.client.swarm_connect(peer_id).await - })?.strings; + let messages = self + .tokio + .block_on(async { self.client.swarm_connect(peer_id).await })? + .strings; for msg in messages { println!("{}", msg.blue()); - if !msg.contains("success"){ + if !msg.contains("success") { bail!(msg); } } return Ok(()); } async fn get_connected(&self) -> Result> { - let peers = self.tokio.block_on(async { - self.client.swarm_peers().await - })?; + let peers = self + .tokio + .block_on(async { self.client.swarm_peers().await })?; Ok(peers.peers.into_iter().map(|peer| peer.addr).collect()) } - async fn get_config(&self, prop:&str) -> Result{ - let config = self.tokio.block_on(async { - self.client.config_get_json(prop).await - })?; + async fn get_config(&self, prop: &str) -> Result { + let config = self + .tokio + .block_on(async { self.client.config_get_json(prop).await })?; return Ok(config.value); } - async fn set_config(&self, prop:&str, val:&Value) -> Result<()> { + async fn set_config(&self, prop: &str, val: &Value) -> Result<()> { if val.is_boolean() { self.tokio.block_on(async { - self.client.config_set_bool(prop, val.as_bool().unwrap()).await + self.client + .config_set_bool(prop, val.as_bool().unwrap()) + .await })?; return Ok(()); } if val.is_string() { self.tokio.block_on(async { - self.client.config_set_string(prop, val.as_str().unwrap()).await + self.client + .config_set_string(prop, val.as_str().unwrap()) + .await })?; return Ok(()); } - self.tokio.block_on(async { - self.client.config_set_json(prop, &val.to_string()).await - })?; + if val.is_number() || val.is_null() { + bail!( + "{}", + "The IPFS config API does not suport null or number json types" + ) + } + self.tokio + .block_on(async { self.client.config_set_json(prop, &val.to_string()).await })?; return Ok(()); } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index b3822e4..54632a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,7 @@ pub mod cmd; -pub mod legacy; pub mod ipfs; +pub mod legacy; pub mod utils; + +#[cfg(test)] +pub mod test; diff --git a/src/main.rs b/src/main.rs index 7312a9c..310a8e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -71,7 +71,7 @@ fn main() { keyfile, os, verbose, - remote + remote, } => match run_setup_command(username, email, keyfile, os, verbose, remote) { Ok(()) => (), Err(_err) => eprintln!("💥 Failed to execute setup command."), diff --git a/src/test.rs b/src/test.rs new file mode 100644 index 0000000..7b1b652 --- /dev/null +++ b/src/test.rs @@ -0,0 +1 @@ +pub mod daemon; \ No newline at end of file diff --git a/src/ipfs/tests.rs b/src/test/daemon.rs similarity index 58% rename from src/ipfs/tests.rs rename to src/test/daemon.rs index 82757b7..9006315 100644 --- a/src/ipfs/tests.rs +++ b/src/test/daemon.rs @@ -1,43 +1,44 @@ -use std::thread; -use std::time::Duration; +/* + TODO: Most of these integration tests currently rely upon Ipfs. There is an issue open to fix this. See https://github.com/fission-codes/fission-cli/issues/29 +*/ + +const DATA_FOLDER: &'static str = "./src/test/data"; + +use std::path::Path; use colored::Colorize; use futures::executor::block_on; +use serde_json::Value; use serial_test::serial; -use self::daemon::IpfsDaemon; -use super::*; +use crate::ipfs::daemon::IpfsDaemon; use crate::ipfs::Ipfs; use crate::utils::file_management; - fn run_ipfs_test(test: T) -> () - where T: FnOnce(&IpfsDaemon) -> bool +where + T: FnOnce(&IpfsDaemon) -> bool, { let ipfs = IpfsDaemon::default(); - // for peer in PEER_ADDRS { - // block_on(ipfs.connect_to(peer)).unwrap(); - // println!("Connected to peer! {}", peer); - // } block_on(ipfs.launch()).unwrap(); let has_passed = test(&ipfs); ipfs.shutdown().unwrap(); assert!(has_passed) } -fn are_files_uploaded(uploaded_paths:Vec, os_paths:Vec) -> bool{ +fn are_files_uploaded(uploaded_paths: Vec, os_paths: Vec) -> bool { let mut is_uploaded = true; - for os_path in os_paths{ - let mut fixed_os_path = String::new(); - for (i, seg) in os_path.split("/").enumerate() { - if seg != "." && !seg.is_empty() { - fixed_os_path += &(match i { - 1 => String::new(), - 2 => seg.to_string(), - _ => "/".to_string() + seg - }); - } - } + let drop_point = DATA_FOLDER.split("/").count(); + for os_path in os_paths { + let fixed_os_path:String = os_path.split("/").enumerate().filter_map(|(i, seg)| { + return if i < drop_point{ + None + } else if i == drop_point { + Some(seg.to_string()) + } else { + Some("/".to_string() + seg) + }; + }).collect(); let mut is_any_matching = false; 'any: for uploaded_path in &uploaded_paths { @@ -45,11 +46,11 @@ fn are_files_uploaded(uploaded_paths:Vec, os_paths:Vec) -> bool{ println!("{} == {}", fixed_os_path.green(), uploaded_path.green()); is_any_matching = true; break 'any; - }else{ + } else { println!("{} == {}", fixed_os_path.red(), uploaded_path.red()); } - }; - if !is_any_matching{ + } + if !is_any_matching { println!("Failed to match {}", fixed_os_path.red()); is_uploaded = false; } @@ -60,42 +61,35 @@ fn are_files_uploaded(uploaded_paths:Vec, os_paths:Vec) -> bool{ #[test] #[serial] fn can_add_directory() { - let test_dir = "./test-dir/more-tests"; + let test_dir = DATA_FOLDER.to_string() + "/more-tests"; run_ipfs_test(|ipfs| { - - let hashes = block_on(ipfs.add(Path::new(test_dir))).unwrap(); - println!("{}", "Finnished Hashes:".green()); + let hashes = block_on(ipfs.add(Path::new(&test_dir))).unwrap(); + println!("{}", "Finished Hashes:".green()); for (path, hash) in &hashes { println!("{}: {}", path.green(), hash.blue()) } - let files = file_management::get_files_in(test_dir).unwrap(); - - let uploaded_paths = hashes.into_iter() - .map(|(path, _)| path) - .collect(); - let os_paths = files.into_iter() - .map(|(path, _)| path) - .collect(); + let files = file_management::get_files_in(&test_dir).unwrap(); + + let uploaded_paths = hashes.into_iter().map(|(path, _)| path).collect(); + let os_paths = files.into_iter().map(|(path, _)| path).collect(); are_files_uploaded(uploaded_paths, os_paths) }) } #[test] #[serial] fn can_add_file() { - let test_file = "./test-dir/test.txt"; + let test_file = DATA_FOLDER.to_string() +"/test.txt"; run_ipfs_test(|ipfs| { - let hashes = block_on(ipfs.add(Path::new(test_file))).unwrap(); - println!("{}", "Finnished Hashes:\n".green()); + let hashes = block_on(ipfs.add(Path::new(&test_file))).unwrap(); + println!("{}", "Finished Hashes:\n".green()); for (path, hash) in &hashes { println!("{}: {}", path.green(), hash.blue()) } - let uploaded_paths = hashes.into_iter() - .map(|(path, _)| path) - .collect(); + let uploaded_paths = hashes.into_iter().map(|(path, _)| path).collect(); let os_paths = vec![test_file.to_string()]; are_files_uploaded(uploaded_paths, os_paths) - }) + }) } #[test] @@ -119,4 +113,4 @@ fn can_connect() { let res = block_on(ipfs.connect_to(test_peer)); res.is_ok() }); -} \ No newline at end of file +} diff --git a/test-dir/more-tests/also-test.txt b/src/test/data/more-tests/also-test.txt similarity index 100% rename from test-dir/more-tests/also-test.txt rename to src/test/data/more-tests/also-test.txt diff --git a/test-dir/more-tests/even more/noper.nope b/src/test/data/more-tests/even more/noper.nope similarity index 100% rename from test-dir/more-tests/even more/noper.nope rename to src/test/data/more-tests/even more/noper.nope diff --git a/test-dir/more-tests/fission_logo.png b/src/test/data/more-tests/fission_logo.png similarity index 100% rename from test-dir/more-tests/fission_logo.png rename to src/test/data/more-tests/fission_logo.png diff --git a/test-dir/test.txt b/src/test/data/test.txt similarity index 100% rename from test-dir/test.txt rename to src/test/data/test.txt diff --git a/src/utils/config.rs b/src/utils/config.rs index 4d8b224..31f8477 100644 --- a/src/utils/config.rs +++ b/src/utils/config.rs @@ -1,7 +1,7 @@ -pub const IPFS_API_PORT:u16 = 4869; -pub const IPFS_RETRY_ATTEMPTS:u16 = 4; -pub const IPFS_ADDR:&str = "127.0.0.1"; -pub const IPFS_EXE:&str = "ipfs"; -pub const HTTP_BOUNDARY:&str = "------------------------I_am_a_boundary_123A123"; -pub const IPFS_BOOT_TIME_OUT:u16 = 45; // In seconds -pub const IPFS_SLEEP_LENGTH:u8 = 1;//In seconds \ No newline at end of file +pub const IPFS_API_PORT: u16 = 4869; +pub const IPFS_RETRY_ATTEMPTS: u16 = 4; +pub const IPFS_ADDR: &str = "127.0.0.1"; +pub const IPFS_EXE: &str = "ipfs"; +pub const HTTP_MULTIPART_BOUNDARY: &str = "------------------------I_am_a_boundary_123A123"; +pub const IPFS_BOOT_TIME_OUT: u16 = 45; // In seconds +pub const IPFS_SLEEP_LENGTH: u8 = 1; //In seconds diff --git a/src/utils/file_management.rs b/src/utils/file_management.rs index b7b696e..35fa4bb 100644 --- a/src/utils/file_management.rs +++ b/src/utils/file_management.rs @@ -1,27 +1,36 @@ use std::collections::HashMap; -use anyhow::{Result, bail}; +use anyhow::{bail, Result}; use colored::Colorize; use walkdir::WalkDir; -pub fn get_files_in(dir:&str) -> Result>> { +pub fn get_files_in(dir: &str) -> Result>> { let mut files = HashMap::new(); for entry_result in WalkDir::new(dir) { let entry = match entry_result { Ok(x) => x, - Err(e) => bail!("{}\n{}", "failled to get item in directory, failed with error:".red(), e) + Err(e) => bail!( + "{}\n{}", + "failed to get item in directory, failed with error:".red(), + e + ), }; if entry.path().is_file() { let file_data = match std::fs::read(entry.path()) { Ok(x) => x, - Err(e) => bail!("{}\n{}", "failed to read file in directory into a byte vector, failed with error:".red(), e) + Err(e) => bail!( + "{}\n{}", + "failed to read file in directory into a byte vector, failed with error:".red(), + e + ), }; let path = match entry.path().to_str() { Some(x) => x, - None => bail!("failed to get path as string a file") - }.to_string(); + None => bail!("failed to get path as string a file"), + } + .to_string(); files.insert(path, file_data); } } return anyhow::Ok(files); -} \ No newline at end of file +} diff --git a/src/utils/http.rs b/src/utils/http.rs index 018b627..b914f40 100644 --- a/src/utils/http.rs +++ b/src/utils/http.rs @@ -2,102 +2,105 @@ This file is currently dead code. Please remove if it continue to be dead code. */ -use std::{ - collections::HashMap, - io::Write -}; +use std::{collections::HashMap, io::Write}; +use anyhow::Result; use bytes::Bytes; use colored::Colorize; -use anyhow::Result; +use hyper::{body::HttpBody, client::HttpConnector, Body, Client, Method, Request}; use tokio::runtime::Runtime; -use hyper::{ - Client, Body, Method, Request, - client::HttpConnector, - body::HttpBody -}; use crate::utils::config::*; - pub struct PostOptions { - pub headers:HashMap, - pub body: Vec + pub headers: HashMap, + pub body: Vec, } pub struct HttpRequest { pub addr: String, pub args: HashMap, - pub is_multipart:bool, - post_options: Vec//TODO: Better name? + pub is_multipart: bool, + post_options: Vec, //TODO: Better name? } impl HttpRequest { - pub fn new(addr: &str, args: &HashMap<&str, &str>, is_multipart:bool) -> Self{ - let owned_args:HashMap = args.iter() + pub fn new(addr: &str, args: &HashMap<&str, &str>, is_multipart: bool) -> Self { + let owned_args: HashMap = args + .iter() .map(|(key, val)| (key.to_string(), val.to_string())) .collect(); - Self { addr:addr.to_string(), args:owned_args, post_options: vec![], is_multipart } + Self { + addr: addr.to_string(), + args: owned_args, + post_options: vec![], + is_multipart, + } } //TODO: Better name? - pub fn add_body(&mut self, headers: &HashMap<&str, &str>, body: &[u8]){ + pub fn add_body(&mut self, headers: &HashMap<&str, &str>, body: &[u8]) { let owned_body = body.to_vec(); - let owned_headers:HashMap = headers.iter() + let owned_headers: HashMap = headers + .iter() .map(|(key, val)| (key.to_string(), val.to_string())) .collect(); - self.post_options.push(PostOptions { headers: owned_headers, body: owned_body }); + self.post_options.push(PostOptions { + headers: owned_headers, + body: owned_body, + }); } pub fn get_url(&self) -> String { - let mut arg_str:String = self.args.iter() + let mut arg_str: String = self + .args + .iter() .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) .collect(); arg_str.pop(); - return match arg_str.len() == 0{ + return match arg_str.len() == 0 { true => self.addr.to_owned(), - false => format!("{}?{}", self.addr, arg_str) - } + false => format!("{}?{}", self.addr, arg_str), + }; } } -pub struct HttpHandler{ - http_client:Client, - tokio:Runtime +pub struct HttpHandler { + http_client: Client, + tokio: Runtime, } impl HttpHandler { - pub fn new() -> HttpHandler{ + pub fn new() -> HttpHandler { let client = Client::new(); let runtime = tokio::runtime::Runtime::new().unwrap(); - return HttpHandler{ - http_client:client, - tokio:runtime + return HttpHandler { + http_client: client, + tokio: runtime, }; } - - pub async fn send_request(&mut self, options:&HttpRequest) -> Result>{ - let request_url = options.get_url(); - println!("{}", (format!("sending get or post request to \"{}\"", request_url).blue())); - let mut request_builder = Request::builder() - .method(Method::POST) - .uri(request_url); + + pub async fn send_request(&mut self, options: &HttpRequest) -> Result> { + let request_url = options.get_url(); + println!( + "{}", + (format!("sending get or post request to \"{}\"", request_url).blue()) + ); + let mut request_builder = Request::builder().method(Method::POST).uri(request_url); let request = match options.is_multipart { - false => { - match options.post_options.get(0) { - Some(options) => { - for (header_key, header_val) in options.headers.iter(){ - request_builder = request_builder.header(header_key, header_val) - } + false => match options.post_options.get(0) { + Some(options) => { + for (header_key, header_val) in options.headers.iter() { + request_builder = request_builder.header(header_key, header_val) + } - let data = options.body.clone(); - request_builder.body(Body::from(data))? - }, - None => request_builder.body(Body::from(Bytes::new()))? + let data = options.body.clone(); + request_builder.body(Body::from(data))? } - } + None => request_builder.body(Body::from(Bytes::new()))?, + }, true => { let mut body_parts = vec![]; for post_options in &options.post_options { - write!(body_parts, "--{}\r\n", HTTP_BOUNDARY)?; + write!(body_parts, "--{}\r\n", HTTP_MULTIPART_BOUNDARY)?; for (header_prop, header_val) in &post_options.headers { write!(body_parts, "{}: {}\r\n", header_prop, header_val)?; } @@ -107,20 +110,24 @@ impl HttpHandler { }; write!(body_parts, "\r\n{}\r\n", data_text)?; } - write!(body_parts, "--{}--\r\n", HTTP_BOUNDARY)?; + write!(body_parts, "--{}--\r\n", HTTP_MULTIPART_BOUNDARY)?; match options.post_options.len() { 0 => request_builder.body(Body::from(Bytes::new()))?, - _ => { - request_builder - .header("Content-Type", &*format!("multipart/form-data; boundary=\"{}\"", HTTP_BOUNDARY)) - .body(Body::from(body_parts))? - } + _ => request_builder + .header( + "Content-Type", + &*format!( + "multipart/form-data; boundary=\"{}\"", + HTTP_MULTIPART_BOUNDARY + ), + ) + .body(Body::from(body_parts))?, } } }; - let mut response = self.tokio.block_on(async { - self.http_client.request(request).await - })?; + let mut response = self + .tokio + .block_on(async { self.http_client.request(request).await })?; let mut response_data: Vec = vec![]; while let Some(chunk) = response.body_mut().data().await { for byte in chunk? { @@ -129,6 +136,5 @@ impl HttpHandler { } println!("response recieved"); anyhow::Ok(response_data) - } } diff --git a/src/utils/json.rs b/src/utils/json.rs deleted file mode 100644 index ede5806..0000000 --- a/src/utils/json.rs +++ /dev/null @@ -1,59 +0,0 @@ -/* - This file is currently dead code. Please remove if it continue to be dead code. -*/ - -use anyhow::{Result, bail}; -use serde_json::{Map, Value}; - - -/// Ipfs often returns json with a single property with the value being an array. -/// This function simply takes the array in that property and turns it into a vector that can be used in rust. -/// It will return an error result if the json is not formatted in this way. -pub fn value_to_vec(json:&Value, index:&str) -> Result> - where A:Clone + for<'de> serde::Deserialize<'de>{ - anyhow::Ok( match json.get(index) { - Some(list_json) => { - match list_json.as_array() { - Some(list) => { - let mut result_list:Vec = vec![]; - for item_json in list { - result_list.push(match serde_json::from_value(item_json.clone()){ - Ok(x) => x, - Err(_) => bail!("Improperly formatted Json: cannot format value {} in index {} to specified type", item_json, index) - }); - } - result_list - }, - None => bail!("Improperly formatted Json: Value at index {} is not an Array", index) - } - }, - None => bail!("Improperly formatted Json: Cant locate index {}", index) - }) -} - -pub fn change_json_part(root:&Value, loc:I, to:&Value) -> Result - where I: Iterator + Clone{ - if loc.clone().count() == 0 { - // println!("{}", "found it!".red()); - return Ok(to.clone()); - }else if !root.is_object(){ - return Ok(root.clone()); - }else{ - let root_iter = match root.as_object() { - Some(o) => o.iter(), - None => return Ok(Value::Object(serde_json::Map::new())) - }; - let mut new_root:Map = Map::new(); - for (prop, val) in root_iter { - let mut new_loc = loc.clone(); - let prop_to_match = new_loc.next().unwrap().to_string() ; - // println!("{} <=> {} = {}", prop, prop_to_match, prop.to_owned() == prop_to_match); - let new_val = match prop.to_owned() == prop_to_match{ - true => change_json_part(val, new_loc, to)?, - false => change_json_part(val, loc.clone(), to)? - }; - new_root.insert(prop.to_owned(), new_val); - } - return Ok(Value::Object(new_root)); - } -} diff --git a/src/utils/math.rs b/src/utils/math.rs index 9be4aa8..8b12e00 100644 --- a/src/utils/math.rs +++ b/src/utils/math.rs @@ -2,9 +2,9 @@ This file is currently dead code. Please remove if it continue to be dead code. */ -pub fn get_fibonacci(n:u32) -> u64{ +pub fn get_fibonacci(n: u32) -> u64 { if n <= 1 { return n as u64; } return get_fibonacci(n - 1) + get_fibonacci(n - 2); -} \ No newline at end of file +} From e345e6038c09d8840ec04afeb131a47bd8f831c7 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Wed, 11 Jan 2023 14:49:19 -0600 Subject: [PATCH 61/63] mostly copy edits --- src/ipfs/daemon.rs | 22 +++++++++++----------- src/test.rs | 2 +- src/test/daemon.rs | 26 +++++++++++++++----------- src/utils.rs | 1 - 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/src/ipfs/daemon.rs b/src/ipfs/daemon.rs index 3cea33e..543d4a8 100644 --- a/src/ipfs/daemon.rs +++ b/src/ipfs/daemon.rs @@ -33,8 +33,8 @@ pub struct IpfsDaemon { } impl IpfsDaemon { - /// This method launches the IPFS daemon on the port/address given when the the instance was - /// created. During this proccess it also creates a thread that listens for a shutdown signal + /// This method launches the IPFS daemon on the port/address given when the instance was + /// created. During this proccess, it also creates a thread that listens for a shutdown signal /// and stops the IPFS daemon gracefully if the signal is given. pub async fn launch(&self) -> Result<()> { //launch the daemon @@ -50,19 +50,19 @@ impl IpfsDaemon { .spawn() .unwrap_or_else(|e| panic!("Failed to start IPFS daemon: {}\n This error may be because the Kubo binary is not on your PATH.", e)); - //Wait ipfs to be ready + // Wait ipfs to be ready println!("Waiting for IPFS to ready.."); self.await_ready().await?; - //Reduce log level for IPFS + // Reduce log level for IPFS self.tokio.block_on(async { self.client .log_level(Logger::All, LoggingLevel::Error) .await })?; - //setup gracefull shutdown - println!("Creating gracefull shutdown for IPFS..."); + // Setup graceful shutdown + println!("Creating graceful shutdown for IPFS..."); let me = self.clone(); thread::spawn(move || { let signal_guard = SignalGuard::new(); @@ -84,7 +84,7 @@ impl IpfsDaemon { /// /// Note 1: This method should work even if the daemon was not started by this proccess. /// - /// Note 2: This method return when it recieves an http response from the daemon, and not + /// Note 2: This method returns when it recieves an http response from the daemon, not /// when the proccess has actually stopped. pub fn shutdown(&self) -> Result<()> { self.tokio @@ -118,7 +118,7 @@ impl IpfsDaemon { if now.duration_since(start_time)? > Duration::new(IPFS_BOOT_TIME_OUT as u64, 0) { bail!( "{}", - "Failed to start ipfs because the timeout reached!!".red() + "Failed to start IPFS because the timeout reached!!".red() ) } } @@ -128,9 +128,9 @@ impl IpfsDaemon { impl TryFrom for IpfsDaemon { type Error = anyhow::Error; - /// This is one of the two main ways to make a new instance of the IPFS daemon struct. Use this + /// This is one of the two ways to make a new instance of the IPFS daemon struct. Use this /// method when you want to make a new instance and you need to set the port and address of - /// the daemon you are attempting to refrence + /// the daemon you are attempting to reference fn try_from(conn_info: IpfsConnInfo) -> Result { let client = IpfsClient::from_host_and_port("http".parse()?, &conn_info.address, conn_info.port)?; @@ -145,7 +145,7 @@ impl TryFrom for IpfsDaemon { } impl Default for IpfsDaemon { - /// This is one of the two main ways to make a new instance of the IPFS daemon struct. Use this + /// This is one of the two ways to make a new instance of the IPFS daemon struct. Use this /// method when you want to make a new instance and you okay with using the default port and address /// set by the config. /// diff --git a/src/test.rs b/src/test.rs index 7b1b652..d6bbb01 100644 --- a/src/test.rs +++ b/src/test.rs @@ -1 +1 @@ -pub mod daemon; \ No newline at end of file +pub mod daemon; diff --git a/src/test/daemon.rs b/src/test/daemon.rs index 9006315..5e45e12 100644 --- a/src/test/daemon.rs +++ b/src/test/daemon.rs @@ -30,15 +30,19 @@ fn are_files_uploaded(uploaded_paths: Vec, os_paths: Vec) -> boo let mut is_uploaded = true; let drop_point = DATA_FOLDER.split("/").count(); for os_path in os_paths { - let fixed_os_path:String = os_path.split("/").enumerate().filter_map(|(i, seg)| { - return if i < drop_point{ - None - } else if i == drop_point { - Some(seg.to_string()) - } else { - Some("/".to_string() + seg) - }; - }).collect(); + let fixed_os_path: String = os_path + .split("/") + .enumerate() + .filter_map(|(i, seg)| { + return if i < drop_point { + None + } else if i == drop_point { + Some(seg.to_string()) + } else { + Some("/".to_string() + seg) + }; + }) + .collect(); let mut is_any_matching = false; 'any: for uploaded_path in &uploaded_paths { @@ -61,7 +65,7 @@ fn are_files_uploaded(uploaded_paths: Vec, os_paths: Vec) -> boo #[test] #[serial] fn can_add_directory() { - let test_dir = DATA_FOLDER.to_string() + "/more-tests"; + let test_dir = DATA_FOLDER.to_string() + "/more-tests"; run_ipfs_test(|ipfs| { let hashes = block_on(ipfs.add(Path::new(&test_dir))).unwrap(); println!("{}", "Finished Hashes:".green()); @@ -79,7 +83,7 @@ fn can_add_directory() { #[test] #[serial] fn can_add_file() { - let test_file = DATA_FOLDER.to_string() +"/test.txt"; + let test_file = DATA_FOLDER.to_string() + "/test.txt"; run_ipfs_test(|ipfs| { let hashes = block_on(ipfs.add(Path::new(&test_file))).unwrap(); println!("{}", "Finished Hashes:\n".green()); diff --git a/src/utils.rs b/src/utils.rs index 9fb2645..7492d19 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,4 @@ pub mod config; pub mod file_management; pub mod http; -pub mod json; pub mod math; From a3c934ada3063873168e16b790eef6ff929e1e79 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 17 Jan 2023 13:12:16 -0600 Subject: [PATCH 62/63] ignored doc tests --- src/ipfs.rs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/ipfs.rs b/src/ipfs.rs index a4a71fe..63d64d4 100644 --- a/src/ipfs.rs +++ b/src/ipfs.rs @@ -5,7 +5,6 @@ use async_trait::async_trait; use serde_json::Value; pub mod daemon; - #[async_trait] pub trait Ipfs { /// This method uploads a file or directory at a given path to the IPFS swarm you are @@ -17,10 +16,27 @@ pub trait Ipfs { async fn get_connected(&self) -> Result>; /// This method changes the value of a given property in the IPFS config /// - /// Ex. `ipfs.set_config("Datastore.StorageMax", "11GB")` + /// ```no_run + /// use fission::ipfs::daemon::IpfsDaemon; + /// use fission::ipfs::Ipfs; + /// use futures::executor::block_on; + /// use serde_json::Value; + /// + /// let ipfs = IpfsDaemon::default(); + /// let config_value = Value::from("11GB"); + /// block_on(ipfs.set_config("Datastore.StorageMax", &config_value)).unwrap(); + /// ``` async fn set_config(&self, property:&str, val:&Value) -> Result<()>; + /// This method returns the value a property in the IPFS config /// - /// Ex. `ipfs.get_config("Datastore.StorageMax")` + /// ```no_run + /// use fission::ipfs::daemon::IpfsDaemon; + /// use fission::ipfs::Ipfs; + /// use futures::executor::block_on; + /// + /// let ipfs = IpfsDaemon::default(); + /// let config_value = block_on(ipfs.get_config("Datastore.StorageMax")).unwrap(); + /// ``` async fn get_config(&self, property: &str) -> Result; } From 1a8010050ac2b2a4a451fb1e79b4d941276fb885 Mon Sep 17 00:00:00 2001 From: Savannah Jackson Date: Tue, 17 Jan 2023 20:26:46 -0600 Subject: [PATCH 63/63] Removing dead code --- src/utils.rs | 2 - src/utils/http.rs | 140 ---------------------------------------------- src/utils/math.rs | 10 ---- 3 files changed, 152 deletions(-) delete mode 100644 src/utils/http.rs delete mode 100644 src/utils/math.rs diff --git a/src/utils.rs b/src/utils.rs index 7492d19..dd7f660 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,2 @@ pub mod config; pub mod file_management; -pub mod http; -pub mod math; diff --git a/src/utils/http.rs b/src/utils/http.rs deleted file mode 100644 index b914f40..0000000 --- a/src/utils/http.rs +++ /dev/null @@ -1,140 +0,0 @@ -/* - This file is currently dead code. Please remove if it continue to be dead code. -*/ - -use std::{collections::HashMap, io::Write}; - -use anyhow::Result; -use bytes::Bytes; -use colored::Colorize; -use hyper::{body::HttpBody, client::HttpConnector, Body, Client, Method, Request}; -use tokio::runtime::Runtime; - -use crate::utils::config::*; - -pub struct PostOptions { - pub headers: HashMap, - pub body: Vec, -} - -pub struct HttpRequest { - pub addr: String, - pub args: HashMap, - pub is_multipart: bool, - post_options: Vec, //TODO: Better name? -} - -impl HttpRequest { - pub fn new(addr: &str, args: &HashMap<&str, &str>, is_multipart: bool) -> Self { - let owned_args: HashMap = args - .iter() - .map(|(key, val)| (key.to_string(), val.to_string())) - .collect(); - Self { - addr: addr.to_string(), - args: owned_args, - post_options: vec![], - is_multipart, - } - } - //TODO: Better name? - pub fn add_body(&mut self, headers: &HashMap<&str, &str>, body: &[u8]) { - let owned_body = body.to_vec(); - let owned_headers: HashMap = headers - .iter() - .map(|(key, val)| (key.to_string(), val.to_string())) - .collect(); - self.post_options.push(PostOptions { - headers: owned_headers, - body: owned_body, - }); - } - pub fn get_url(&self) -> String { - let mut arg_str: String = self - .args - .iter() - .flat_map(|(prop, val)| format!("{}={}&", prop, val).chars().collect::>()) - .collect(); - arg_str.pop(); - return match arg_str.len() == 0 { - true => self.addr.to_owned(), - false => format!("{}?{}", self.addr, arg_str), - }; - } -} - -pub struct HttpHandler { - http_client: Client, - tokio: Runtime, -} - -impl HttpHandler { - pub fn new() -> HttpHandler { - let client = Client::new(); - let runtime = tokio::runtime::Runtime::new().unwrap(); - return HttpHandler { - http_client: client, - tokio: runtime, - }; - } - - pub async fn send_request(&mut self, options: &HttpRequest) -> Result> { - let request_url = options.get_url(); - println!( - "{}", - (format!("sending get or post request to \"{}\"", request_url).blue()) - ); - let mut request_builder = Request::builder().method(Method::POST).uri(request_url); - let request = match options.is_multipart { - false => match options.post_options.get(0) { - Some(options) => { - for (header_key, header_val) in options.headers.iter() { - request_builder = request_builder.header(header_key, header_val) - } - - let data = options.body.clone(); - request_builder.body(Body::from(data))? - } - None => request_builder.body(Body::from(Bytes::new()))?, - }, - true => { - let mut body_parts = vec![]; - for post_options in &options.post_options { - write!(body_parts, "--{}\r\n", HTTP_MULTIPART_BOUNDARY)?; - for (header_prop, header_val) in &post_options.headers { - write!(body_parts, "{}: {}\r\n", header_prop, header_val)?; - } - let data_text = unsafe { - //TODO: find a way to do this safely - std::str::from_utf8_unchecked(post_options.body.as_slice()) - }; - write!(body_parts, "\r\n{}\r\n", data_text)?; - } - write!(body_parts, "--{}--\r\n", HTTP_MULTIPART_BOUNDARY)?; - match options.post_options.len() { - 0 => request_builder.body(Body::from(Bytes::new()))?, - _ => request_builder - .header( - "Content-Type", - &*format!( - "multipart/form-data; boundary=\"{}\"", - HTTP_MULTIPART_BOUNDARY - ), - ) - .body(Body::from(body_parts))?, - } - } - }; - let mut response = self - .tokio - .block_on(async { self.http_client.request(request).await })?; - let mut response_data: Vec = vec![]; - while let Some(chunk) = response.body_mut().data().await { - for byte in chunk? { - response_data.push(byte); - } - } - println!("response recieved"); - anyhow::Ok(response_data) - } -} diff --git a/src/utils/math.rs b/src/utils/math.rs deleted file mode 100644 index 8b12e00..0000000 --- a/src/utils/math.rs +++ /dev/null @@ -1,10 +0,0 @@ -/* - This file is currently dead code. Please remove if it continue to be dead code. -*/ - -pub fn get_fibonacci(n: u32) -> u64 { - if n <= 1 { - return n as u64; - } - return get_fibonacci(n - 1) + get_fibonacci(n - 2); -}