aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Cargo.lock40
-rw-r--r--README.md7
-rw-r--r--TODO7
-rw-r--r--src/bin/geniza-net.rs28
-rw-r--r--src/bin/geniza.rs166
-rw-r--r--src/bitfield.rs63
-rw-r--r--src/helpers.rs61
-rw-r--r--src/lib.rs27
-rw-r--r--src/peer.rs31
-rw-r--r--src/synchronizer.rs (renamed from src/node.rs)68
11 files changed, 390 insertions, 109 deletions
diff --git a/.gitignore b/.gitignore
index df7782e..a7ad7c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,6 @@
papers/
target/
+scratch/
**/*.rs.bk
*.o
*.a
diff --git a/Cargo.lock b/Cargo.lock
index 087ec25..438da58 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -20,7 +20,7 @@ dependencies = [
"difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"environment 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -90,9 +90,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -107,7 +107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
-version = "2.28.0"
+version = "2.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -208,7 +208,7 @@ version = "0.1.0"
dependencies = [
"assert_cli 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "clap 2.28.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
"data-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"error-chain 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -408,7 +408,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -418,22 +418,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
-version = "1.0.23"
+version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
-version = "1.0.23"
+version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive_internals 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive_internals"
-version = "0.17.0"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -442,13 +442,13 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.7"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -461,7 +461,7 @@ dependencies = [
"error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"pulldown-cmark 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -473,7 +473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
"libsodium-sys 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -621,7 +621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum cargo_metadata 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1f56ec3e469bca7c276f2eea015aa05c5e381356febdbb0683c2580189604537"
"checksum cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a9b13a57efd6b30ecd6598ebdb302cca617930b5470647570468a65d12ef9719"
"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de"
-"checksum clap 2.28.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dc34bf7d5d66268b466b9852bca925ec1d2650654dab4da081e63fd230145c2e"
+"checksum clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)" = "110d43e343eb29f4f51c1db31beb879d546db27998577e5715270a54bcf41d3f"
"checksum colored 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b0aa3473e85a3161b59845d6096b289bb577874cafeaf75ea1b1beaa6572c7fc"
"checksum data-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "099d2591f809713931cd770f2bdf4b8a4d2eb7314bc762da4c375ecaa74af80f"
"checksum dbghelp-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "97590ba53bcb8ac28279161ca943a924d1fd4a8fb3fa63302591647c4fc5b850"
@@ -662,10 +662,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum same-file 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d931a44fdaa43b8637009e7632a02adc4f2b2e0733c08caa4cf00e8da4a117a7"
"checksum semver 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bee2bc909ab2d8d60dab26e8cad85b25d795b14603a0dcb627b78b9d30b6454b"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7c37d7f192f00041e8a613e936717923a71bc0c9051fc4425a49b104140f05"
-"checksum serde_derive 1.0.23 (registry+https://github.com/rust-lang/crates.io-index)" = "0672de7300b02bac3f3689f8faea813c4a1ea9fe0cb49e80f714231d267518a2"
-"checksum serde_derive_internals 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "32f1926285523b2db55df263d2aa4eb69ddcfa7a7eade6430323637866b513ab"
-"checksum serde_json 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ea28ea0cca944668919bec6af209864a8dfe769fd2b0b723f36b22e20c1bf69f"
+"checksum serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1c57ab4ec5fa85d08aaf8ed9245899d9bbdd66768945b21113b84d5f595cb6a1"
+"checksum serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "02c92ea07b6e49b959c1481804ebc9bfd92d3c459f1274c9a9546829e42a66ce"
+"checksum serde_derive_internals 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75c6aac7b99801a16db5b40b7bf0d7e4ba16e76fbf231e32a4677f271cac0603"
+"checksum serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7cf5b0b5b4bd22eeecb7e01ac2e1225c7ef5e4272b79ee28a8392a8c8489c839"
"checksum skeptic 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c8431f8fca168e2db4be547bd8329eac70d095dff1444fee4b0fa0fabc7df75a"
"checksum sodiumoxide 0.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb5cb2f14f9a51352ad65e59257a0a9459d5a36a3615f3d53a974c82fdaaa00a"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
diff --git a/README.md b/README.md
index e6a5e46..654614a 100644
--- a/README.md
+++ b/README.md
@@ -30,15 +30,16 @@ it will eat-your-data!
- [x] import file to register
- [x] export file from register
- [x] import/export directories recursively
-- [ ] Networking
+- [ ] Protocol
- [x] send/receive encrypted messages to a known host
- - [ ] receive entire register from a known host
- - [ ] share (upload) register to a known host
- [ ] bitfields
- [ ] Discovery
- [x] centralized DNS
- [ ] mDNS (local DNS)
- [ ] DHT (distributed hash table)
+- [ ] Peer Synchronization
+ - [ ] receive entire register from a known host
+ - [ ] share (upload) register to a known host
- [ ] Wrapper commands
- [ ] clone
- [ ] share
diff --git a/TODO b/TODO
index f1ccb08..c702002 100644
--- a/TODO
+++ b/TODO
@@ -1,11 +1,10 @@
next:
+- DatPeer wrapper API
+- Synchronizer API
- clean up node bitfield implementation
- "insert" API for HyperRegister
-- crude single-thread drive+network clone
- sparse register clone
-- "needed data chunks" and progress function?
-- crude single-thread drive+network broadcast
- 'geniza clone' command
- 'geniza checkout' command
- 'geniza init', 'geniza commit' commands
@@ -28,7 +27,7 @@ Backburner:
- API to link and run from, eg, python
- uTP transport
- in-memory storage backend
-- WASM
+- compile to WASM... play in browser?
- multi-connection network sync (per-connection state, etc)
- duplicate file/chunk optimizations
- secret_key-in-home helpers (read/write)
diff --git a/src/bin/geniza-net.rs b/src/bin/geniza-net.rs
index 6d38eae..0c82e6d 100644
--- a/src/bin/geniza-net.rs
+++ b/src/bin/geniza-net.rs
@@ -12,22 +12,6 @@ use geniza::*;
use std::path::Path;
use clap::{App, SubCommand, Arg};
-fn parse_dat_key(raw_key: &str) -> Result<Vec<u8>> {
-
- if raw_key.len() != 32 * 2 {
- bail!("dat key not correct length");
- }
- let mut key_bytes = vec![];
- for i in 0..32 {
- let r = u8::from_str_radix(&raw_key[2 * i..2 * i + 2], 16);
- match r {
- Ok(b) => key_bytes.push(b),
- Err(e) => bail!("Problem with hex: {}", e),
- };
- }
- Ok(key_bytes)
-}
-
fn run() -> Result<()> {
env_logger::init().unwrap();
@@ -81,7 +65,7 @@ fn run() -> Result<()> {
("connect", Some(subm)) => {
let host_port = subm.value_of("host_port").unwrap();
let dat_key = subm.value_of("dat_key").unwrap();
- let key_bytes = parse_dat_key(&dat_key)?;
+ let key_bytes = parse_dat_address(&dat_key)?;
DatConnection::connect(host_port, &key_bytes, false)?;
println!("Done!");
}
@@ -89,7 +73,7 @@ fn run() -> Result<()> {
let host_port = subm.value_of("host_port").unwrap();
let dat_key = subm.value_of("dat_key").unwrap();
let count: u64 = subm.value_of("count").unwrap().parse().unwrap();
- let key_bytes = parse_dat_key(&dat_key)?;
+ let key_bytes = parse_dat_address(&dat_key)?;
let mut dc = DatConnection::connect(host_port, &key_bytes, false)?;
dc.receive_some(false, count)?;
dc.receive_some(true, count)?;
@@ -97,7 +81,7 @@ fn run() -> Result<()> {
}
("discovery-key", Some(subm)) => {
let dat_key = subm.value_of("dat_key").unwrap();
- let key_bytes = parse_dat_key(&dat_key)?;
+ let key_bytes = parse_dat_address(&dat_key)?;
let disc_key = make_discovery_key(&key_bytes);
for b in disc_key {
print!("{:02x}", b);
@@ -106,7 +90,7 @@ fn run() -> Result<()> {
}
("discovery-dns-name", Some(subm)) => {
let dat_key = subm.value_of("dat_key").unwrap();
- let key_bytes = parse_dat_key(&dat_key)?;
+ let key_bytes = parse_dat_address(&dat_key)?;
let disc_key = make_discovery_key(&key_bytes);
for b in 0..20 {
print!("{:02x}", disc_key[b]);
@@ -115,7 +99,7 @@ fn run() -> Result<()> {
}
("discover-dns", Some(subm)) => {
let dat_key = subm.value_of("dat_key").unwrap();
- let key_bytes = parse_dat_key(&dat_key)?;
+ let key_bytes = parse_dat_address(&dat_key)?;
let peers = discover_peers_dns(&key_bytes)?;
if peers.len() == 0 {
println!("No peers found!");
@@ -128,7 +112,7 @@ fn run() -> Result<()> {
("naive-clone", Some(subm)) => {
let host_port = subm.value_of("host_port").unwrap();
let dat_key = subm.value_of("dat_key").unwrap();
- let key_bytes = parse_dat_key(&dat_key)?;
+ let key_bytes = parse_dat_address(&dat_key)?;
let dir = Path::new(subm.value_of("dat-dir").unwrap());
let mut metadata = SleepDirRegister::create(&dir, "metadata")?;
node_simple_clone(host_port, &key_bytes, &mut metadata, false)?;
diff --git a/src/bin/geniza.rs b/src/bin/geniza.rs
new file mode 100644
index 0000000..f5c73b0
--- /dev/null
+++ b/src/bin/geniza.rs
@@ -0,0 +1,166 @@
+// Free Software under GPL-3.0, see LICENSE
+// Copyright 2017 Bryan Newbold
+
+extern crate clap;
+extern crate env_logger;
+#[macro_use]
+extern crate error_chain;
+extern crate geniza;
+
+// TODO: more careful import
+use geniza::*;
+use std::path::{Path, PathBuf};
+use clap::{App, SubCommand};
+use std::env::current_dir;
+
+
+// Helper to find a dat directory somewhere in the parent to the current working directory (or None
+// if not found)
+fn find_dat_dir() -> Option<PathBuf> {
+ let mut here: &Path = &current_dir().unwrap();
+ loop {
+ let check = here.join(".dat");
+ if check.is_dir() && check.join("metadata.tree").is_file() {
+ return Some(check);
+ };
+ here = match here.parent() {
+ None => return None,
+ Some(t) => t,
+ }
+ }
+}
+
+fn run() -> Result<()> {
+ env_logger::init().unwrap();
+
+ let matches = App::new("geniza")
+ .version(env!("CARGO_PKG_VERSION"))
+ .subcommand(
+ SubCommand::with_name("clone")
+ .about("Finds and downloads a dat archive from the network into a given folder")
+ .arg_from_usage("<address> 'dat address (public key) to fetch'")
+ .arg_from_usage("[dir] 'directory to clone into'")
+ .arg_from_usage("--full 'pull and save complete history (not just latest version)'"),
+ )
+ .subcommand(
+ SubCommand::with_name("init")
+ .about("Creates a data archive in the current directory")
+ .arg_from_usage("[dir] 'init somewhere other than current directory'"),
+ )
+ .subcommand(
+ SubCommand::with_name("status")
+ .about("Displays current status of archive and checkout")
+ )
+ .subcommand(
+ SubCommand::with_name("log")
+ .about("Displays version history of the archive")
+ )
+ .subcommand(
+ SubCommand::with_name("checkout")
+ .about("Copies (or overwrites) files from dat archive")
+ .arg_from_usage("<path> 'relative path to checkout'"),
+ )
+ .subcommand(
+ SubCommand::with_name("add")
+ .about("Adds a path to the current dat archive")
+ .arg_from_usage("<path> 'file to delete from dat archive'"),
+ )
+ .subcommand(
+ SubCommand::with_name("rm")
+ .about("Removes a path from the current dat archive, and from disk (danger!)")
+ .arg_from_usage("<path> 'file to delete from dat archive'"),
+ )
+ .subcommand(
+ SubCommand::with_name("ls")
+ .about("Lists contents of the archive")
+ .arg_from_usage("[path] 'path to display'")
+ .arg_from_usage("--recursive 'show directory recursively'"),
+ )
+ .subcommand(
+ SubCommand::with_name("seed")
+ .about("Uploads indefinately to any peer")
+ )
+ .subcommand(
+ SubCommand::with_name("pull")
+ .about("Pulls highest known version from all possible peers")
+ .arg_from_usage("--forever 'continues to search for updates forever'"),
+ )
+ .get_matches();
+
+ match matches.subcommand() {
+ ("clone", Some(subm)) => {
+ let dat_key = subm.value_of("dat_key").unwrap();
+ let _key_bytes = parse_dat_address(&dat_key)?;
+ unimplemented!();
+ //let dir = Path::new(subm.value_of("dat-dir").unwrap());
+ //let mut metadata = SleepDirRegister::create(&dir, "metadata")?;
+ //node_simple_clone(host_port, &key_bytes, &mut metadata, false)?;
+ }
+ ("init", Some(subm)) => {
+ let _dir = Path::new(subm.value_of("dir").unwrap());
+ unimplemented!();
+ }
+ ("status", Some(_subm)) => {
+ unimplemented!();
+ }
+ ("log", Some(_subm)) => {
+ let dat_dir = match find_dat_dir() {
+ Some(p) => p,
+ None => {
+ println!("Couldn't find '.dat/' in the current or (any parent) directory.");
+ println!("Are you running from inside a Dat archive?");
+ ::std::process::exit(-1);
+ }
+ };
+ println!("{:?}", dat_dir);
+ let mut drive = DatDrive::open(dat_dir, false)?;
+ for entry in drive.history(0) {
+ let entry = entry?;
+ if let Some(stat) = entry.stat {
+ if stat.get_blocks() == 0 {
+ println!("{}\t[chg] {}",
+ entry.index, entry.path.display());
+ } else {
+ println!("{}\t[put] {}\t{} bytes ({} blocks)",
+ entry.index, entry.path.display(), stat.get_size(), stat.get_blocks());
+ }
+ } else {
+ println!("{}\t[del] {}",
+ entry.index, entry.path.display());
+ }
+ }
+ }
+ ("checkout", Some(subm)) => {
+ let _path = Path::new(subm.value_of("path").unwrap());
+ unimplemented!();
+ }
+ ("add", Some(subm)) => {
+ let _path = Path::new(subm.value_of("path").unwrap());
+ unimplemented!();
+ }
+ ("rm", Some(subm)) => {
+ let _path = Path::new(subm.value_of("path").unwrap());
+ unimplemented!();
+ }
+ ("ls", Some(subm)) => {
+ let _path = Path::new(subm.value_of("path").unwrap());
+ unimplemented!();
+ }
+ ("seed", Some(subm)) => {
+ let _path = Path::new(subm.value_of("path").unwrap());
+ unimplemented!();
+ }
+ ("pull", Some(subm)) => {
+ let _path = Path::new(subm.value_of("path").unwrap());
+ unimplemented!();
+ }
+ _ => {
+ println!("Missing or unimplemented command!");
+ println!("{}", matches.usage());
+ ::std::process::exit(-1);
+ }
+ }
+ Ok(())
+}
+
+quick_main!(run);
diff --git a/src/bitfield.rs b/src/bitfield.rs
new file mode 100644
index 0000000..018ccbc
--- /dev/null
+++ b/src/bitfield.rs
@@ -0,0 +1,63 @@
+
+use errors::*;
+use integer_encoding::VarInt;
+use bit_field::BitArray;
+use network_msgs::Have;
+
+pub struct Bitfield {
+ inner: Vec<u64>,
+}
+
+impl Bitfield {
+
+ pub fn from_have_msg(msg: &Have) -> Bitfield {
+ unimplemented!()
+ }
+
+ pub fn get(&self, index: u64) -> Result<bool> {
+ unimplemented!()
+ }
+}
+
+pub fn decode_bitfield(raw_bf: &[u8]) -> Result<Vec<u8>> {
+ let mut offset = 0; // byte offset that we have read up to
+ if raw_bf.len() < 1 {
+ bail!("Expected (varint-encoded) bitfield to have len>=1");
+ }
+ let mut bit_array: Vec<u8> = vec![];
+ while offset < raw_bf.len() {
+ let (header, inc): (u64, usize) = VarInt::decode_var(&raw_bf[offset..]);
+ offset += inc;
+
+ if (header & 0x01) == 0x01 {
+ // compressed
+ let bit = (header & 0x02) == 0x02;
+ let run_len = header >> 2;
+ if bit {
+ bit_array.append(&mut vec![0xFF; run_len as usize]);
+ } else {
+ bit_array.append(&mut vec![0x00; run_len as usize]);
+ }
+ } else {
+ // uncompressed
+ let byte_count = header >> 1;
+ let mut data = raw_bf[offset..(offset + byte_count as usize)].to_vec();
+ bit_array.append(&mut data);
+ offset += byte_count as usize;
+ }
+ }
+ // XXX: HACK
+ bit_array.reverse();
+ return Ok(bit_array);
+}
+
+/// Finds the index of the lowest bit
+pub fn max_high_bit(bf: &[u8]) -> u64 {
+ // XXX: HACK, going backwards
+ for i in 0..bf.bit_length() {
+ if bf.get_bit(i) {
+ return (bf.bit_length() - i - 1) as u64;
+ }
+ }
+ return 0;
+}
diff --git a/src/helpers.rs b/src/helpers.rs
new file mode 100644
index 0000000..32f0e25
--- /dev/null
+++ b/src/helpers.rs
@@ -0,0 +1,61 @@
+
+use errors::*;
+use crypto::digest::Digest;
+use crypto::blake2b::Blake2b;
+
+/// Helper to calculate a discovery key from a public key. 'key' should be 32 bytes; the returned
+/// array will also be 32 bytes long.
+///
+/// dat discovery keys are calculated as a BLAKE2b "keyed hash" (using the passed key) of the string
+/// "hypercore" (with no trailing null byte).
+pub fn make_discovery_key(key: &[u8]) -> Vec<u8> {
+ let mut discovery_key = [0; 32];
+ let mut hash = Blake2b::new_keyed(32, key);
+ hash.input(&"hypercore".as_bytes());
+ hash.result(&mut discovery_key);
+ discovery_key.to_vec()
+}
+
+/// Helper to parse a dat address (aka, public key) in string format.
+///
+/// Address can start with 'dat://'. It should contain 64 hexadecimal characters.
+pub fn parse_dat_address(input: &str) -> Result<Vec<u8>> {
+
+ let raw_key = if input.starts_with("dat://") {
+ &input[6..]
+ } else {
+ input
+ };
+ if raw_key.len() != 32 * 2 {
+ bail!("dat key not correct length");
+ }
+ let mut key_bytes = vec![];
+ for i in 0..32 {
+ let r = u8::from_str_radix(&raw_key[2 * i..2 * i + 2], 16);
+ match r {
+ Ok(b) => key_bytes.push(b),
+ Err(e) => bail!("Problem with hex: {}", e),
+ };
+ }
+ Ok(key_bytes)
+}
+
+#[test]
+fn test_parse_dat_address() {
+
+ assert!(parse_dat_address(
+ "c7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d597").is_ok());
+ assert!(parse_dat_address(
+ "C7638882870ABD4044D6467B0738F15E3A36F57C3A7F7F3417FD7E4E0841D597").is_ok());
+ assert!(parse_dat_address(
+ "dat://c7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d597").is_ok());
+
+ assert!(parse_dat_address(
+ "c7638882870ab").is_err());
+ assert!(parse_dat_address(
+ "g7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d597").is_err());
+ assert!(parse_dat_address(
+ "dat://c7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d5970").is_err());
+ assert!(parse_dat_address(
+ "dat://c7638882870abd4044d6467b0738f15e3a36f57c3a7f7f3417fd7e4e0841d59").is_err());
+}
diff --git a/src/lib.rs b/src/lib.rs
index bc62d78..e3ad197 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -46,6 +46,10 @@ mod errors {
pub use errors::*;
// Organize code internally (files, modules), but pull it all into a flat namespace to export.
+mod helpers;
+pub use helpers::*;
+mod bitfield;
+pub use bitfield::*;
mod sleep_file;
pub use sleep_file::*;
mod sleep_register;
@@ -56,25 +60,10 @@ mod protocol;
pub use protocol::*;
pub mod network_msgs;
pub mod metadata_msgs;
-mod node;
-pub use node::*;
mod discovery;
pub use discovery::*;
-
-// Shared functions
-use crypto::digest::Digest;
-use crypto::blake2b::Blake2b;
-
-/// Helper to calculate a discovery key from a public key. 'key' should be 32 bytes; the returned
-/// array will also be 32 bytes long.
-///
-/// dat discovery keys are calculated as a BLAKE2b "keyed hash" (using the passed key) of the string
-/// "hypercore" (with no trailing null byte).
-pub fn make_discovery_key(key: &[u8]) -> Vec<u8> {
- let mut discovery_key = [0; 32];
- let mut hash = Blake2b::new_keyed(32, key);
- hash.input(&"hypercore".as_bytes());
- hash.result(&mut discovery_key);
- discovery_key.to_vec()
-}
+mod peer;
+pub use peer::*;
+mod synchronizer;
+pub use synchronizer::*;
diff --git a/src/peer.rs b/src/peer.rs
new file mode 100644
index 0000000..29b90a2
--- /dev/null
+++ b/src/peer.rs
@@ -0,0 +1,31 @@
+
+use errors::*;
+use sleep_register::{HyperRegister, SleepDirRegister};
+use protocol::DatConnection;
+use bitfield::Bitfield;
+
+pub struct DatPeer {
+ registers: Vec<SleepDirRegister>,
+ connection: DatConnection,
+ have_log: Vec<Vec<Bitfield>>,
+}
+
+impl DatPeer {
+
+ pub fn new(connection: DatConnection, registers: Vec<SleepDirRegister>) -> DatPeer {
+ DatPeer {
+ registers,
+ connection,
+ have_log: vec![],
+ }
+ }
+
+ pub fn has(self, register: u64, index: u64) -> Result<bool> {
+ for bitfield in self.have_log[register as usize].iter() {
+ if bitfield.get(index)? {
+ return Ok(true)
+ }
+ }
+ Ok(false)
+ }
+}
diff --git a/src/node.rs b/src/synchronizer.rs
index 582bf3d..4e803fb 100644
--- a/src/node.rs
+++ b/src/synchronizer.rs
@@ -1,60 +1,46 @@
use errors::*;
use network_msgs::*;
+use bitfield::*;
use protocol::{DatNetMessage, DatConnection};
-use integer_encoding::VarInt;
-use bit_field::BitArray;
use sleep_register::HyperRegister;
+use peer::DatPeer;
+use sleep_register::SleepDirRegister;
+
+pub enum SyncMode {
+ RxMax,
+ RxEndless,
+ TxEndless,
+ RxTxEndless,
+}
-fn decode_bitfiled(raw_bf: &[u8]) -> Result<Vec<u8>> {
- let mut offset = 0; // byte offset that we have read up to
- if raw_bf.len() < 1 {
- bail!("Expected (varint-encoded) bitfield to have len>=1");
- }
- let mut bit_array: Vec<u8> = vec![];
- while offset < raw_bf.len() {
- let (header, inc): (u64, usize) = VarInt::decode_var(&raw_bf[offset..]);
- offset += inc;
-
- if (header & 0x01) == 0x01 {
- // compressed
- let bit = (header & 0x02) == 0x02;
- let run_len = header >> 2;
- if bit {
- bit_array.append(&mut vec![0xFF; run_len as usize]);
- } else {
- bit_array.append(&mut vec![0x00; run_len as usize]);
- }
- } else {
- // uncompressed
- let byte_count = header >> 1;
- let mut data = raw_bf[offset..(offset + byte_count as usize)].to_vec();
- bit_array.append(&mut data);
- offset += byte_count as usize;
- }
- }
- // XXX: HACK
- bit_array.reverse();
- return Ok(bit_array);
+pub struct Synchronizer {
+ peers: Vec<DatPeer>,
+ registers: Vec<SleepDirRegister>,
+ mode: SyncMode,
+ wanted: Bitfield,
+ inflight: Vec<Vec<u64>>,
}
-/// Finds the index of the lowest bit
-fn max_high_bit(bf: &[u8]) -> u64 {
- // XXX: HACK, going backwards
- for i in 0..bf.bit_length() {
- if bf.get_bit(i) {
- return (bf.bit_length() - i - 1) as u64;
- }
+impl Synchronizer {
+
+ pub fn next_wanted(&mut self, reg: u64) -> Option<(u64, u64)> {
+ // XXX
+ None
+ }
+
+ pub fn tick(&mut self) -> Result<()> {
+ Ok(())
}
- return 0;
}
+
fn max_index(have_msg: &Have) -> Result<u64> {
if have_msg.has_length() {
return Ok(have_msg.get_start() + have_msg.get_length());
} else if have_msg.has_bitfield() {
let raw_bf = have_msg.get_bitfield();
- let bf = decode_bitfiled(raw_bf)?;
+ let bf = decode_bitfield(raw_bf)?;
trace!("decoded bitfield: {:?}", bf);
return Ok(max_high_bit(&bf));
} else {