{"action":"created","comment":{"url":"https://api.github.com/repos/dirvine/crust/pulls/comments/28851446","id":28851446,"diff_hunk":"@@ -0,0 +1,214 @@\n+// Copyright 2015 MaidSafe.net limited\n+//\n+// This MaidSafe Software is licensed to you under (1) the MaidSafe.net Commercial License,\n+// version 1.0 or later, or (2) The General Public License (GPL), version 3, depending on which\n+// licence you accepted on initial access to the Software (the \"Licences\").\n+//\n+// By contributing code to the MaidSafe Software, or to this project generally, you agree to be\n+// bound by the terms of the MaidSafe Contributor Agreement, version 1.0, found in the root\n+// directory of this project at LICENSE, COPYING and CONTRIBUTOR respectively and also\n+// available at: http://www.maidsafe.net/licenses\n+//\n+// Unless required by applicable law or agreed to in writing, the MaidSafe Software distributed\n+// under the GPL Licence is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS\n+// OF ANY KIND, either express or implied.\n+//\n+// See the Licences for the specific language governing permissions and limitations relating to\n+// use of the MaidSafe Software.\n+\n+// String.as_str() is unstable; waiting RFC revision\n+// http://doc.rust-lang.org/nightly/std/string/struct.String.html#method.as_str\n+#![feature(convert)]\n+\n+extern crate crust;\n+extern crate rustc_serialize;\n+extern crate docopt;\n+\n+use crust::{Endpoint, Port};\n+use crust::ConnectionManager;\n+use docopt::Docopt;\n+use std::sync::mpsc::channel;\n+use std::io;\n+use std::net::SocketAddr;\n+use std::str::FromStr;\n+\n+// TODO: switching order of CL params, eg --speed x --bootstrap node\n+//       gives an error parsing node as usize... so order is strict for now\n+static USAGE: &'static str = \"\n+Usage: crust_node -h\n+       crust_node -o <port>\n+       crust_node -b <peer>\n+       crust_node -b <peer> -s <speed>\n+\n+Options:\n+    -h, --help        Display this help message.\n+    -o, --origin      Start a crust node as server, i.e. only listening on specified port.\n+    -b, --bootstrap   Start a crust node and bootstrap off the peer.\n+                      If no bootstrap node is provided beacon will be used.\n+    -s, --speed       Optional send data at maximum speed (bytes/second)\n+\";\n+\n+#[derive(RustcDecodable, Debug)]\n+struct Args {\n+  arg_peer : Option<String>,\n+  arg_speed : Option<usize>,\n+  arg_port : Option<String>,\n+  flag_help : bool,\n+  flag_bootstrap : bool,\n+  flag_speed : bool,\n+  flag_origin : bool\n+}\n+\n+// simple \"NodeInfo\", without PKI\n+#[derive(Clone)]\n+struct CrustNode {\n+  pub endpoint : Endpoint,\n+  pub connected : bool\n+}\n+\n+impl CrustNode {\n+  pub fn new(endpoint : Endpoint, connected : bool) -> CrustNode {\n+    CrustNode{\n+      endpoint : endpoint,\n+      connected : connected\n+    }\n+  }\n+  pub fn set_connected(&mut self) {self.connected = true;}\n+  pub fn set_disconnected(&mut self) {self.connected = false;}\n+}\n+\n+struct FlatWorld {\n+  our_eps : Vec<Endpoint>,\n+  crust_nodes : Vec<CrustNode>\n+}\n+\n+// simple \"routing table\" without any structure\n+impl FlatWorld {\n+  pub fn new(our_endpoints : Vec<Endpoint>) -> FlatWorld {\n+    FlatWorld {\n+      our_eps : our_endpoints,\n+      crust_nodes : Vec::with_capacity(40)\n+    }\n+  }\n+\n+  // Will add node if not duplicated.  Returns true when added.\n+  pub fn add_node(&mut self, new_node : CrustNode) -> bool {\n+    if self.crust_nodes.iter()\n+                       .filter(|node| node.endpoint == new_node.endpoint)\n+                       .count() == 0 &&\n+       self.our_eps.iter()\n+                   .filter(|& our_ep| our_ep == &new_node.endpoint)\n+                   .count() == 0 {\n+      self.crust_nodes.push(new_node);\n+      return true;\n+    }\n+    return false;\n+  }\n+\n+  pub fn drop_node(&mut self, lost_node : CrustNode) -> bool {\n+    for node in self.crust_nodes.iter_mut() {\n+      if node.endpoint == lost_node.endpoint {\n+        node.set_disconnected();\n+        return true;\n+      }\n+    }\n+    return false;\n+  }\n+\n+  pub fn get_connected_nodes(&self) -> Vec<CrustNode> {\n+    self.crust_nodes.iter()\n+                    .filter_map(|node| if node.connected == true {\n+                      Some(node.clone())\n+                      } else {None})\n+                    .collect::<Vec<_>>()\n+  }\n+\n+  pub fn get_all_nodes(&self) -> Vec<CrustNode> {\n+    self.crust_nodes.clone()\n+  }\n+}\n+\n+fn main() {\n+\n+  let args : Args = Docopt::new(USAGE)\n+                     .and_then(|d| d.decode())\n+                     .unwrap_or_else(|e| e.exit());\n+\n+  if !args.flag_help { println!(\"{:?}\", args); };  // TODO: remove; here for debug\n+  if args.flag_help {\n+    println!(\"{:?}\", args);     // print help message\n+    return;\n+  };\n+\n+  let (cm_tx, cm_rx) = channel();\n+  let cm = ConnectionManager::new(cm_tx);\n+  let cm_eps = match cm.start_listening(vec![Port::Tcp(5483u16)]) {\n+    Ok(eps) => eps,\n+    Err(e) => panic!(\"Connection manager failed to start on arbitrary TCP port: {}\", e)\n+  };\n+  assert!(cm_eps.len() > 0);\n+  for ep in &cm_eps {\n+    match *ep {\n+      Endpoint::Tcp(socket) => println!(\"Connection manager now listening on TCP socket {}\", socket)\n+    };\n+  };\n+  let mut my_flat_world : FlatWorld = FlatWorld::new(cm_eps);\n+\n+  let mut default_bootstrap = !args.flag_bootstrap;\n+  if args.flag_bootstrap {\n+    match args.arg_peer {\n+      Some(peer) => {\n+        // String.as_str() is unstable; waiting RFC revision\n+        // http://doc.rust-lang.org/nightly/std/string/struct.String.html#method.as_str\n+        let bootstrap_address = match SocketAddr::from_str(peer.as_str()) {\n+          Ok(addr) => addr,\n+          Err(_) => panic!(\"Failed to parse bootstrap peer as valid IPv4 or IPv6 address: {}\", peer)\n+        };\n+        match cm.bootstrap(Some(vec![Endpoint::Tcp(bootstrap_address)])) {\n+          Ok(endpoint) =>  my_flat_world.add_node(CrustNode::new(endpoint, true)),\n+          Err(e) => { println!(\"Failed to bootstrap from provided peer: {}, with error : {}\", peer, e);\n+                      panic!(\"Not resulting to default discovery of bootstrap nodes. Exiting\"); }\n+                      // default_bootstrap = true; }\n+        };\n+      },\n+      None => { println!(\"No peer address provided, resort to default\");\n+                default_bootstrap = true; }\n+    }\n+  }\n+\n+  // resort to default bootstrapping methods\n+  if default_bootstrap && !args.flag_origin {","path":"examples/crust_node.rs","position":180,"original_position":180,"commit_id":"a1ea351bcf4400275ef258c5a53760594be9552c","original_commit_id":"a1ea351bcf4400275ef258c5a53760594be9552c","user":{"login":"benjaminbollen","id":5057507,"avatar_url":"https://avatars.githubusercontent.com/u/5057507?v=3","gravatar_id":"","url":"https://api.github.com/users/benjaminbollen","html_url":"https://github.com/benjaminbollen","followers_url":"https://api.github.com/users/benjaminbollen/followers","following_url":"https://api.github.com/users/benjaminbollen/following{/other_user}","gists_url":"https://api.github.com/users/benjaminbollen/gists{/gist_id}","starred_url":"https://api.github.com/users/benjaminbollen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/benjaminbollen/subscriptions","organizations_url":"https://api.github.com/users/benjaminbollen/orgs","repos_url":"https://api.github.com/users/benjaminbollen/repos","events_url":"https://api.github.com/users/benjaminbollen/events{/privacy}","received_events_url":"https://api.github.com/users/benjaminbollen/received_events","type":"User","site_admin":false},"body":"Qi, the intention of copying the boolean `flag_bootstrap` into a mutable `default_bootstrap` at L157 was explicitly to be able to mutate it in L174: if a user provides commandline --bootstrap but writes nothing behind it `arg_peer` is `None`, but `flag_bootstrap` is true.  So logically that is \"default bootstrap\" to me, hence I overwrote it.  Minor detail, but now you could skip all bootstrapping attempts altogether. ","created_at":"2015-04-22T07:59:28Z","updated_at":"2015-04-22T07:59:28Z","html_url":"https://github.com/dirvine/crust/pull/35#discussion_r28851446","pull_request_url":"https://api.github.com/repos/dirvine/crust/pulls/35","_links":{"self":{"href":"https://api.github.com/repos/dirvine/crust/pulls/comments/28851446"},"html":{"href":"https://github.com/dirvine/crust/pull/35#discussion_r28851446"},"pull_request":{"href":"https://api.github.com/repos/dirvine/crust/pulls/35"}}},"pull_request":{"url":"https://api.github.com/repos/dirvine/crust/pulls/35","id":33830615,"html_url":"https://github.com/dirvine/crust/pull/35","diff_url":"https://github.com/dirvine/crust/pull/35.diff","patch_url":"https://github.com/dirvine/crust/pull/35.patch","issue_url":"https://api.github.com/repos/dirvine/crust/issues/35","number":35,"state":"open","locked":false,"title":"WIP DO NOT MERGE Maid 960 cli crust node","user":{"login":"maqi","id":568777,"avatar_url":"https://avatars.githubusercontent.com/u/568777?v=3","gravatar_id":"","url":"https://api.github.com/users/maqi","html_url":"https://github.com/maqi","followers_url":"https://api.github.com/users/maqi/followers","following_url":"https://api.github.com/users/maqi/following{/other_user}","gists_url":"https://api.github.com/users/maqi/gists{/gist_id}","starred_url":"https://api.github.com/users/maqi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maqi/subscriptions","organizations_url":"https://api.github.com/users/maqi/orgs","repos_url":"https://api.github.com/users/maqi/repos","events_url":"https://api.github.com/users/maqi/events{/privacy}","received_events_url":"https://api.github.com/users/maqi/received_events","type":"User","site_admin":false},"body":"\n\n<!-- Reviewable:start -->\n[<img src=\"https://reviewable.io/review_button.png\" height=40 alt=\"Review on Reviewable\"/>](https://reviewable.io/reviews/dirvine/crust/35)\n<!-- Reviewable:end -->\n","created_at":"2015-04-22T06:54:34Z","updated_at":"2015-04-22T07:59:28Z","closed_at":null,"merged_at":null,"merge_commit_sha":"344e44d72e21ca0712f3943cddd2d8def10aca9c","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/dirvine/crust/pulls/35/commits","review_comments_url":"https://api.github.com/repos/dirvine/crust/pulls/35/comments","review_comment_url":"https://api.github.com/repos/dirvine/crust/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dirvine/crust/issues/35/comments","statuses_url":"https://api.github.com/repos/dirvine/crust/statuses/a1ea351bcf4400275ef258c5a53760594be9552c","head":{"label":"maqi:MAID-960_CLI_crust_node","ref":"MAID-960_CLI_crust_node","sha":"a1ea351bcf4400275ef258c5a53760594be9552c","user":{"login":"maqi","id":568777,"avatar_url":"https://avatars.githubusercontent.com/u/568777?v=3","gravatar_id":"","url":"https://api.github.com/users/maqi","html_url":"https://github.com/maqi","followers_url":"https://api.github.com/users/maqi/followers","following_url":"https://api.github.com/users/maqi/following{/other_user}","gists_url":"https://api.github.com/users/maqi/gists{/gist_id}","starred_url":"https://api.github.com/users/maqi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maqi/subscriptions","organizations_url":"https://api.github.com/users/maqi/orgs","repos_url":"https://api.github.com/users/maqi/repos","events_url":"https://api.github.com/users/maqi/events{/privacy}","received_events_url":"https://api.github.com/users/maqi/received_events","type":"User","site_admin":false},"repo":{"id":33644235,"name":"crust","full_name":"maqi/crust","owner":{"login":"maqi","id":568777,"avatar_url":"https://avatars.githubusercontent.com/u/568777?v=3","gravatar_id":"","url":"https://api.github.com/users/maqi","html_url":"https://github.com/maqi","followers_url":"https://api.github.com/users/maqi/followers","following_url":"https://api.github.com/users/maqi/following{/other_user}","gists_url":"https://api.github.com/users/maqi/gists{/gist_id}","starred_url":"https://api.github.com/users/maqi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maqi/subscriptions","organizations_url":"https://api.github.com/users/maqi/orgs","repos_url":"https://api.github.com/users/maqi/repos","events_url":"https://api.github.com/users/maqi/events{/privacy}","received_events_url":"https://api.github.com/users/maqi/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/maqi/crust","description":"Reliable p2p network connections in Rust with NAT traversal. One of the most needed libraries for any server-less / decentralised projects","fork":true,"url":"https://api.github.com/repos/maqi/crust","forks_url":"https://api.github.com/repos/maqi/crust/forks","keys_url":"https://api.github.com/repos/maqi/crust/keys{/key_id}","collaborators_url":"https://api.github.com/repos/maqi/crust/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/maqi/crust/teams","hooks_url":"https://api.github.com/repos/maqi/crust/hooks","issue_events_url":"https://api.github.com/repos/maqi/crust/issues/events{/number}","events_url":"https://api.github.com/repos/maqi/crust/events","assignees_url":"https://api.github.com/repos/maqi/crust/assignees{/user}","branches_url":"https://api.github.com/repos/maqi/crust/branches{/branch}","tags_url":"https://api.github.com/repos/maqi/crust/tags","blobs_url":"https://api.github.com/repos/maqi/crust/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/maqi/crust/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/maqi/crust/git/refs{/sha}","trees_url":"https://api.github.com/repos/maqi/crust/git/trees{/sha}","statuses_url":"https://api.github.com/repos/maqi/crust/statuses/{sha}","languages_url":"https://api.github.com/repos/maqi/crust/languages","stargazers_url":"https://api.github.com/repos/maqi/crust/stargazers","contributors_url":"https://api.github.com/repos/maqi/crust/contributors","subscribers_url":"https://api.github.com/repos/maqi/crust/subscribers","subscription_url":"https://api.github.com/repos/maqi/crust/subscription","commits_url":"https://api.github.com/repos/maqi/crust/commits{/sha}","git_commits_url":"https://api.github.com/repos/maqi/crust/git/commits{/sha}","comments_url":"https://api.github.com/repos/maqi/crust/comments{/number}","issue_comment_url":"https://api.github.com/repos/maqi/crust/issues/comments{/number}","contents_url":"https://api.github.com/repos/maqi/crust/contents/{+path}","compare_url":"https://api.github.com/repos/maqi/crust/compare/{base}...{head}","merges_url":"https://api.github.com/repos/maqi/crust/merges","archive_url":"https://api.github.com/repos/maqi/crust/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/maqi/crust/downloads","issues_url":"https://api.github.com/repos/maqi/crust/issues{/number}","pulls_url":"https://api.github.com/repos/maqi/crust/pulls{/number}","milestones_url":"https://api.github.com/repos/maqi/crust/milestones{/number}","notifications_url":"https://api.github.com/repos/maqi/crust/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/maqi/crust/labels{/name}","releases_url":"https://api.github.com/repos/maqi/crust/releases{/id}","created_at":"2015-04-09T02:33:06Z","updated_at":"2015-04-09T02:33:10Z","pushed_at":"2015-04-22T07:12:36Z","git_url":"git://github.com/maqi/crust.git","ssh_url":"git@github.com:maqi/crust.git","clone_url":"https://github.com/maqi/crust.git","svn_url":"https://github.com/maqi/crust","homepage":null,"size":186,"stargazers_count":0,"watchers_count":0,"language":"Rust","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"dirvine:master","ref":"master","sha":"51ee987ad09f9f7f2281a0aca43e570c9ec49837","user":{"login":"dirvine","id":123627,"avatar_url":"https://avatars.githubusercontent.com/u/123627?v=3","gravatar_id":"","url":"https://api.github.com/users/dirvine","html_url":"https://github.com/dirvine","followers_url":"https://api.github.com/users/dirvine/followers","following_url":"https://api.github.com/users/dirvine/following{/other_user}","gists_url":"https://api.github.com/users/dirvine/gists{/gist_id}","starred_url":"https://api.github.com/users/dirvine/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dirvine/subscriptions","organizations_url":"https://api.github.com/users/dirvine/orgs","repos_url":"https://api.github.com/users/dirvine/repos","events_url":"https://api.github.com/users/dirvine/events{/privacy}","received_events_url":"https://api.github.com/users/dirvine/received_events","type":"User","site_admin":false},"repo":{"id":33324427,"name":"crust","full_name":"dirvine/crust","owner":{"login":"dirvine","id":123627,"avatar_url":"https://avatars.githubusercontent.com/u/123627?v=3","gravatar_id":"","url":"https://api.github.com/users/dirvine","html_url":"https://github.com/dirvine","followers_url":"https://api.github.com/users/dirvine/followers","following_url":"https://api.github.com/users/dirvine/following{/other_user}","gists_url":"https://api.github.com/users/dirvine/gists{/gist_id}","starred_url":"https://api.github.com/users/dirvine/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dirvine/subscriptions","organizations_url":"https://api.github.com/users/dirvine/orgs","repos_url":"https://api.github.com/users/dirvine/repos","events_url":"https://api.github.com/users/dirvine/events{/privacy}","received_events_url":"https://api.github.com/users/dirvine/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/dirvine/crust","description":"Reliable p2p network connections in Rust with NAT traversal. One of the most needed libraries for any server-less / decentralised projects","fork":false,"url":"https://api.github.com/repos/dirvine/crust","forks_url":"https://api.github.com/repos/dirvine/crust/forks","keys_url":"https://api.github.com/repos/dirvine/crust/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dirvine/crust/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dirvine/crust/teams","hooks_url":"https://api.github.com/repos/dirvine/crust/hooks","issue_events_url":"https://api.github.com/repos/dirvine/crust/issues/events{/number}","events_url":"https://api.github.com/repos/dirvine/crust/events","assignees_url":"https://api.github.com/repos/dirvine/crust/assignees{/user}","branches_url":"https://api.github.com/repos/dirvine/crust/branches{/branch}","tags_url":"https://api.github.com/repos/dirvine/crust/tags","blobs_url":"https://api.github.com/repos/dirvine/crust/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dirvine/crust/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dirvine/crust/git/refs{/sha}","trees_url":"https://api.github.com/repos/dirvine/crust/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dirvine/crust/statuses/{sha}","languages_url":"https://api.github.com/repos/dirvine/crust/languages","stargazers_url":"https://api.github.com/repos/dirvine/crust/stargazers","contributors_url":"https://api.github.com/repos/dirvine/crust/contributors","subscribers_url":"https://api.github.com/repos/dirvine/crust/subscribers","subscription_url":"https://api.github.com/repos/dirvine/crust/subscription","commits_url":"https://api.github.com/repos/dirvine/crust/commits{/sha}","git_commits_url":"https://api.github.com/repos/dirvine/crust/git/commits{/sha}","comments_url":"https://api.github.com/repos/dirvine/crust/comments{/number}","issue_comment_url":"https://api.github.com/repos/dirvine/crust/issues/comments{/number}","contents_url":"https://api.github.com/repos/dirvine/crust/contents/{+path}","compare_url":"https://api.github.com/repos/dirvine/crust/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dirvine/crust/merges","archive_url":"https://api.github.com/repos/dirvine/crust/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dirvine/crust/downloads","issues_url":"https://api.github.com/repos/dirvine/crust/issues{/number}","pulls_url":"https://api.github.com/repos/dirvine/crust/pulls{/number}","milestones_url":"https://api.github.com/repos/dirvine/crust/milestones{/number}","notifications_url":"https://api.github.com/repos/dirvine/crust/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dirvine/crust/labels{/name}","releases_url":"https://api.github.com/repos/dirvine/crust/releases{/id}","created_at":"2015-04-02T18:16:59Z","updated_at":"2015-04-21T17:23:57Z","pushed_at":"2015-04-22T07:48:42Z","git_url":"git://github.com/dirvine/crust.git","ssh_url":"git@github.com:dirvine/crust.git","clone_url":"https://github.com/dirvine/crust.git","svn_url":"https://github.com/dirvine/crust","homepage":null,"size":1801,"stargazers_count":5,"watchers_count":5,"language":"Rust","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":13,"mirror_url":null,"open_issues_count":8,"forks":13,"open_issues":8,"watchers":5,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dirvine/crust/pulls/35"},"html":{"href":"https://github.com/dirvine/crust/pull/35"},"issue":{"href":"https://api.github.com/repos/dirvine/crust/issues/35"},"comments":{"href":"https://api.github.com/repos/dirvine/crust/issues/35/comments"},"review_comments":{"href":"https://api.github.com/repos/dirvine/crust/pulls/35/comments"},"review_comment":{"href":"https://api.github.com/repos/dirvine/crust/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dirvine/crust/pulls/35/commits"},"statuses":{"href":"https://api.github.com/repos/dirvine/crust/statuses/a1ea351bcf4400275ef258c5a53760594be9552c"}}}}