From 2336b055b4c95409013f043f96562d9c668a6d72 Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Sun, 30 Apr 2017 18:42:11 -0700 Subject: [PATCH 01/11] Add simple peer and swarm creation --- .gitignore | 1 + cumulus-peer/peer.go | 73 ++++++++++++++++++++++++++++++++++++++++++++ main.go | 26 ++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 cumulus-peer/peer.go create mode 100644 main.go diff --git a/.gitignore b/.gitignore index a4e785e..5e4e640 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Compiled Object files, Static and Dynamic libs (Shared Objects) +cumulus *.o *.a *.so diff --git a/cumulus-peer/peer.go b/cumulus-peer/peer.go new file mode 100644 index 0000000..c257140 --- /dev/null +++ b/cumulus-peer/peer.go @@ -0,0 +1,73 @@ +package cumulusPeer + +import ( + "context" + "fmt" + "log" + + crypto "github.com/libp2p/go-libp2p-crypto" + host "github.com/libp2p/go-libp2p-host" + peer "github.com/libp2p/go-libp2p-peer" + pstore "github.com/libp2p/go-libp2p-peerstore" + swarm "github.com/libp2p/go-libp2p-swarm" + ma "github.com/multiformats/go-multiaddr" + bhost "github.com/libp2p/go-libp2p/p2p/host/basic" +) + +// Cumulus peers communicate over this TCP port +const CumulusPort int = 8765 + +// Create a Cumulus host. +// This may throw an error if we fail to create a key pair, a pid, or a new +// multiaddress. +func MakeHost() (host.Host, error) { + // Generate a key pair for this host. We will only use the pudlic key to + // obtain a valid host ID. + _, pub, err := crypto.GenerateKeyPair(crypto.RSA, 2048) + if err != nil { + return nil, err + } + + // Obtain Peer ID from public key + pid, err := peer.IDFromPublicKey(pub) + if err != nil { + return nil, err + } + + // Create a multiaddress (IP address and TCP port for this peer) + addr, err := ma.NewMultiaddr( + fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", + CumulusPort)) + if err != nil { + return nil, err + } + + // Create a peerstore (this stores information about other peers in the + // Cumulus network) + ps := pstore.NewPeerstore() + + // Create swarm (this is the interface to the libP2P Network) using the + // multiaddress, peerID, and peerStore we just created + netwrk, err := swarm.NewNetwork( + context.Background(), + []ma.Multiaddr{addr}, + pid, + ps, + nil) + if err != nil { + return nil, err + } + + basicHost := bhost.New(netwrk) + + // Build host multiaddress + hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", + basicHost.ID().Pretty())) + + // Now we can build a full multiaddress to reach this host + // by encapsulating both addresses: + fullAddr := addr.Encapsulate(hostAddr) + log.Printf("I am %s\n", fullAddr) + + return basicHost, nil +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..a1d42e7 --- /dev/null +++ b/main.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "log" + + golog "github.com/ipfs/go-log" + gologging "github.com/whyrusleeping/go-logging" + cmlPeer "github.com/ubclaunchpad/cumulus/cumulus-peer" +) + +func main() { + fmt.Println("Starting Cumulus Peer") + + // Set up a logger. Change to DEBUG for extra info + golog.SetAllLoggers(gologging.INFO) + + // Set up a new host on the Cumulus network + host, err := cmlPeer.MakeHost() + if err != nil { + log.Fatal(err) + } + + // TODO: remove this when we figure out what to do with this host. + fmt.Println(host.ID()) +} From 1c4278d20bd94b6b79687c27ba568f80db371767 Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Thu, 4 May 2017 23:14:08 -0700 Subject: [PATCH 02/11] Update cumuluspeer and add logger Create cumuluspeer BasicStreamHandler and ExtractPeerInfo Add logger Main now parses command line arguments specifying multiaddress of peer to connect to --- cumulus-peer/peer.go | 83 +++++++++++++++++++++++++++++++++++++++----- logging/logger.go | 31 +++++++++++++++++ main.go | 67 +++++++++++++++++++++++++++++------ 3 files changed, 162 insertions(+), 19 deletions(-) create mode 100644 logging/logger.go diff --git a/cumulus-peer/peer.go b/cumulus-peer/peer.go index c257140..a65c66c 100644 --- a/cumulus-peer/peer.go +++ b/cumulus-peer/peer.go @@ -1,21 +1,57 @@ -package cumulusPeer +package cumuluspeer import ( + "bufio" "context" "fmt" - "log" + logger "github.com/ubclaunchpad/cumulus/logging" crypto "github.com/libp2p/go-libp2p-crypto" host "github.com/libp2p/go-libp2p-host" peer "github.com/libp2p/go-libp2p-peer" + net "github.com/libp2p/go-libp2p-net" pstore "github.com/libp2p/go-libp2p-peerstore" swarm "github.com/libp2p/go-libp2p-swarm" ma "github.com/multiformats/go-multiaddr" bhost "github.com/libp2p/go-libp2p/p2p/host/basic" ) -// Cumulus peers communicate over this TCP port -const CumulusPort int = 8765 +const ( + CumulusPort = 8765 // Cumulus peers communicate over this TCP port + CumulusProtocol = "/cumulate/0.0.1" // Cumulus communication protocol +) + +// A basic StreamHandler for a very basic host. +// This should be passed as the second argument to SetStreamHandler(). +// This is called when a remote peer opens a new stream with the host that +// SetStreamHandler() is called on. +// We may want to implement another type of StreamHandler in the future. +func BasicStreamHandler(s net.Stream) { + logger.Log.Info("Setting basic stream handler.") + defer s.Close() + doCumulate(s) +} + +// Communicate with peers. +// TODO: Update this to do something useful. For now it just reads from the +// stream and writes back what it read. +func doCumulate(s net.Stream) { + buf := bufio.NewReader(s) + str, err := buf.ReadString('\n') + if err != nil { + logger.Log.Error(err) + return + } + + logger.Log.Info("Read: %s", str) + _, err = s.Write([]byte(str)) + if err != nil { + logger.Log.Error(err) + return + } + + logger.Log.Info("Done now. Bye!") +} // Create a Cumulus host. // This may throw an error if we fail to create a key pair, a pid, or a new @@ -28,13 +64,13 @@ func MakeHost() (host.Host, error) { return nil, err } - // Obtain Peer ID from public key + // Obtain Peer ID from public key. pid, err := peer.IDFromPublicKey(pub) if err != nil { return nil, err } - // Create a multiaddress (IP address and TCP port for this peer) + // Create a multiaddress (IP address and TCP port for this peer). addr, err := ma.NewMultiaddr( fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", CumulusPort)) @@ -43,11 +79,11 @@ func MakeHost() (host.Host, error) { } // Create a peerstore (this stores information about other peers in the - // Cumulus network) + // Cumulus network). ps := pstore.NewPeerstore() // Create swarm (this is the interface to the libP2P Network) using the - // multiaddress, peerID, and peerStore we just created + // multiaddress, peerID, and peerStore we just created. netwrk, err := swarm.NewNetwork( context.Background(), []ma.Multiaddr{addr}, @@ -58,6 +94,7 @@ func MakeHost() (host.Host, error) { return nil, err } + // Actually create the host with the network we just set up. basicHost := bhost.New(netwrk) // Build host multiaddress @@ -67,7 +104,35 @@ func MakeHost() (host.Host, error) { // Now we can build a full multiaddress to reach this host // by encapsulating both addresses: fullAddr := addr.Encapsulate(hostAddr) - log.Printf("I am %s\n", fullAddr) + logger.Log.Notice("I am", fullAddr) return basicHost, nil } + +// Extracts target's the peer ID and multiaddress from the given multiaddress. +// Returns peer ID (esentially 46 character hash created by the peer) +// and the peer's multiaddress in the form /ip4//tcp/. +func ExtractPeerInfo(peerma string) (peer.ID, ma.Multiaddr) { + ipfsaddr, err := ma.NewMultiaddr(peerma) + if err != nil { + logger.Log.Error(err) + } + + pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS) + if err != nil { + logger.Log.Error(err) + } + + peerid, err := peer.IDB58Decode(pid) + if err != nil { + logger.Log.Error(err) + } + + // Decapsulate the /ipfs/ part from the target + // /ip4//ipfs/ becomes /ip4/ + targetPeerAddr, _ := ma.NewMultiaddr( + fmt.Sprintf("/ipfs/%s", peer.IDB58Encode(peerid))) + trgtAddr := ipfsaddr.Decapsulate(targetPeerAddr) + + return peerid, trgtAddr +} diff --git a/logging/logger.go b/logging/logger.go new file mode 100644 index 0000000..28c4a69 --- /dev/null +++ b/logging/logger.go @@ -0,0 +1,31 @@ +package logger + +import ( + "os" + + gologging "github.com/op/go-logging" +) + +// Set up pretty logger +var ( + Log = gologging.MustGetLogger("example") + format = gologging.MustStringFormatter( + `%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{color:reset} %{message}`, + ) + + logBackend = gologging.NewLogBackend(os.Stderr, "", 0) + + // For messages written to logBackend we want to add some additional + // information to the output, including the used log level and the name of + // the function. + logBackendFormatter = gologging.NewBackendFormatter(logBackend, format) + + // Only errors and more severe messages should be sent to LogBackend + logBackendLeveled = gologging.AddModuleLevel(logBackend) +) + +// Set up logging level and backend +func Init() { + logBackendLeveled.SetLevel(gologging.ERROR, "") + gologging.SetBackend(logBackendLeveled, logBackendFormatter) +} diff --git a/main.go b/main.go index a1d42e7..eb970ba 100644 --- a/main.go +++ b/main.go @@ -1,26 +1,73 @@ package main import ( + "context" + "flag" "fmt" - "log" + "io/ioutil" - golog "github.com/ipfs/go-log" - gologging "github.com/whyrusleeping/go-logging" - cmlPeer "github.com/ubclaunchpad/cumulus/cumulus-peer" + logger "github.com/ubclaunchpad/cumulus/logging" + cumuluspeer "github.com/ubclaunchpad/cumulus/cumulus-peer" + pstore "github.com/libp2p/go-libp2p-peerstore" ) func main() { fmt.Println("Starting Cumulus Peer") - // Set up a logger. Change to DEBUG for extra info - golog.SetAllLoggers(gologging.INFO) + // Initialize Cumulus logger + logger.Init() + + // Get and parse command line arguments + // targetPeer is a Multiaddr representing the target peer to connect to + // when joining the Cumulus Network. + targetPeer := flag.String("p", "", "target peer to connect to") + flag.Parse() // Set up a new host on the Cumulus network - host, err := cmlPeer.MakeHost() + host, err := cumuluspeer.MakeHost() if err != nil { - log.Fatal(err) + logger.Log.Error(err) } - // TODO: remove this when we figure out what to do with this host. - fmt.Println(host.ID()) + // Set the host StreamHandler for the Cumulus Protocol and use + // BasicStreamHandler as its StreamHandler. + host.SetStreamHandler(cumuluspeer.CumulusProtocol, + cumuluspeer.BasicStreamHandler) + + if *targetPeer == "" { + // No target was specified, wait for incoming connections + logger.Log.Info("No target provided. Listening for incoming connections...") + select {} // Hang until someone connects to us + } + + // Target is specified so connect to it and remember its address + peerid, targetAddr := cumuluspeer.ExtractPeerInfo(*targetPeer) + + // Store the peer's address in this host's PeerStore + host.Peerstore().AddAddr(peerid, targetAddr, pstore.PermanentAddrTTL) + + logger.Log.Notice("Connected to Cumulus Peer:") + logger.Log.Notice("\tPeer ID:", peerid.Pretty()) + logger.Log.Notice("\tPeer Address:", targetAddr) + + // Open a stream with the peer + stream, err := host.NewStream(context.Background(), peerid, + cumuluspeer.CumulusProtocol) + if err != nil { + logger.Log.Error(err) + } + + // Send a message to the peer + _, err = stream.Write([]byte("Hello, world!\n")) + if err != nil { + logger.Log.Error(err) + } + + // Read the reply from the peer + reply, err := ioutil.ReadAll(stream) + if err != nil { + logger.Log.Error(err) + } + + logger.Log.Info("read reply: %q\n", reply) } From 784cd068c6239d7180bb4f40cc0127d58615602f Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Fri, 5 May 2017 22:56:26 -0700 Subject: [PATCH 03/11] Switch logger to Logrus, add port selection through CLI --- cumulus-peer/peer.go | 46 ++++++++++++++++++++++++-------------------- logging/logger.go | 31 ----------------------------- main.go | 39 +++++++++++++++++++------------------ 3 files changed, 45 insertions(+), 71 deletions(-) delete mode 100644 logging/logger.go diff --git a/cumulus-peer/peer.go b/cumulus-peer/peer.go index a65c66c..f382ef9 100644 --- a/cumulus-peer/peer.go +++ b/cumulus-peer/peer.go @@ -5,7 +5,7 @@ import ( "context" "fmt" - logger "github.com/ubclaunchpad/cumulus/logging" + log "github.com/sirupsen/logrus" crypto "github.com/libp2p/go-libp2p-crypto" host "github.com/libp2p/go-libp2p-host" peer "github.com/libp2p/go-libp2p-peer" @@ -27,7 +27,7 @@ const ( // SetStreamHandler() is called on. // We may want to implement another type of StreamHandler in the future. func BasicStreamHandler(s net.Stream) { - logger.Log.Info("Setting basic stream handler.") + log.Info("Setting basic stream handler.") defer s.Close() doCumulate(s) } @@ -39,43 +39,41 @@ func doCumulate(s net.Stream) { buf := bufio.NewReader(s) str, err := buf.ReadString('\n') if err != nil { - logger.Log.Error(err) + log.Error(err) return } - logger.Log.Info("Read: %s", str) + log.Info("Read: %s", str) _, err = s.Write([]byte(str)) if err != nil { - logger.Log.Error(err) + log.Error(err) return } - logger.Log.Info("Done now. Bye!") + log.Info("Done now. Bye!") } // Create a Cumulus host. // This may throw an error if we fail to create a key pair, a pid, or a new // multiaddress. -func MakeHost() (host.Host, error) { +func MakeHost(port int) (host.Host, pstore.Peerstore, error) { // Generate a key pair for this host. We will only use the pudlic key to // obtain a valid host ID. _, pub, err := crypto.GenerateKeyPair(crypto.RSA, 2048) if err != nil { - return nil, err + return nil, nil, err } // Obtain Peer ID from public key. pid, err := peer.IDFromPublicKey(pub) if err != nil { - return nil, err + return nil, nil, err } // Create a multiaddress (IP address and TCP port for this peer). - addr, err := ma.NewMultiaddr( - fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", - CumulusPort)) + addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) if err != nil { - return nil, err + return nil, nil, err } // Create a peerstore (this stores information about other peers in the @@ -91,7 +89,7 @@ func MakeHost() (host.Host, error) { ps, nil) if err != nil { - return nil, err + return nil, nil, err } // Actually create the host with the network we just set up. @@ -104,28 +102,34 @@ func MakeHost() (host.Host, error) { // Now we can build a full multiaddress to reach this host // by encapsulating both addresses: fullAddr := addr.Encapsulate(hostAddr) - logger.Log.Notice("I am", fullAddr) + log.Info("I am ", fullAddr) - return basicHost, nil + // Add this host's address to its peerstore (avoid's net/identi error) + ps.AddAddr(pid, fullAddr, pstore.PermanentAddrTTL) + + return basicHost, ps, nil } // Extracts target's the peer ID and multiaddress from the given multiaddress. // Returns peer ID (esentially 46 character hash created by the peer) // and the peer's multiaddress in the form /ip4//tcp/. -func ExtractPeerInfo(peerma string) (peer.ID, ma.Multiaddr) { +func ExtractPeerInfo(peerma string) (peer.ID, ma.Multiaddr, error) { ipfsaddr, err := ma.NewMultiaddr(peerma) if err != nil { - logger.Log.Error(err) + log.Error(err) + return "-", nil, err } pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS) if err != nil { - logger.Log.Error(err) + log.Error(err) + return "-", nil, err } peerid, err := peer.IDB58Decode(pid) if err != nil { - logger.Log.Error(err) + log.Error(err) + return "-", nil, err } // Decapsulate the /ipfs/ part from the target @@ -134,5 +138,5 @@ func ExtractPeerInfo(peerma string) (peer.ID, ma.Multiaddr) { fmt.Sprintf("/ipfs/%s", peer.IDB58Encode(peerid))) trgtAddr := ipfsaddr.Decapsulate(targetPeerAddr) - return peerid, trgtAddr + return peerid, trgtAddr, nil } diff --git a/logging/logger.go b/logging/logger.go deleted file mode 100644 index 28c4a69..0000000 --- a/logging/logger.go +++ /dev/null @@ -1,31 +0,0 @@ -package logger - -import ( - "os" - - gologging "github.com/op/go-logging" -) - -// Set up pretty logger -var ( - Log = gologging.MustGetLogger("example") - format = gologging.MustStringFormatter( - `%{color}%{time:15:04:05.000} %{shortfunc} ▶ %{level:.4s} %{color:reset} %{message}`, - ) - - logBackend = gologging.NewLogBackend(os.Stderr, "", 0) - - // For messages written to logBackend we want to add some additional - // information to the output, including the used log level and the name of - // the function. - logBackendFormatter = gologging.NewBackendFormatter(logBackend, format) - - // Only errors and more severe messages should be sent to LogBackend - logBackendLeveled = gologging.AddModuleLevel(logBackend) -) - -// Set up logging level and backend -func Init() { - logBackendLeveled.SetLevel(gologging.ERROR, "") - gologging.SetBackend(logBackendLeveled, logBackendFormatter) -} diff --git a/main.go b/main.go index eb970ba..4fba8af 100644 --- a/main.go +++ b/main.go @@ -3,30 +3,28 @@ package main import ( "context" "flag" - "fmt" "io/ioutil" - logger "github.com/ubclaunchpad/cumulus/logging" + log "github.com/sirupsen/logrus" cumuluspeer "github.com/ubclaunchpad/cumulus/cumulus-peer" pstore "github.com/libp2p/go-libp2p-peerstore" ) func main() { - fmt.Println("Starting Cumulus Peer") - - // Initialize Cumulus logger - logger.Init() + log.Info("Starting Cumulus Peer") // Get and parse command line arguments // targetPeer is a Multiaddr representing the target peer to connect to // when joining the Cumulus Network. - targetPeer := flag.String("p", "", "target peer to connect to") + // port is the port to communicate over (defaults to peer.CumulusPort) + targetPeer := flag.String("t", "", "target peer to connect to") + port := flag.Int("p", cumuluspeer.CumulusPort, "TCP port to use") flag.Parse() // Set up a new host on the Cumulus network - host, err := cumuluspeer.MakeHost() + host, ps, err := cumuluspeer.MakeHost(*port) if err != nil { - logger.Log.Error(err) + log.Fatal(err) } // Set the host StreamHandler for the Cumulus Protocol and use @@ -36,38 +34,41 @@ func main() { if *targetPeer == "" { // No target was specified, wait for incoming connections - logger.Log.Info("No target provided. Listening for incoming connections...") + log.Info("No target provided. Listening for incoming connections...") select {} // Hang until someone connects to us } // Target is specified so connect to it and remember its address - peerid, targetAddr := cumuluspeer.ExtractPeerInfo(*targetPeer) + peerid, targetAddr, err := cumuluspeer.ExtractPeerInfo(*targetPeer) + if err != nil { + log.Fatal(err) + } // Store the peer's address in this host's PeerStore - host.Peerstore().AddAddr(peerid, targetAddr, pstore.PermanentAddrTTL) + ps.AddAddr(peerid, targetAddr, pstore.PermanentAddrTTL) - logger.Log.Notice("Connected to Cumulus Peer:") - logger.Log.Notice("\tPeer ID:", peerid.Pretty()) - logger.Log.Notice("\tPeer Address:", targetAddr) + log.Info("Connected to Cumulus Peer:") + log.Info("\tPeer ID:", peerid.Pretty()) + log.Info("\tPeer Address:", targetAddr) // Open a stream with the peer stream, err := host.NewStream(context.Background(), peerid, cumuluspeer.CumulusProtocol) if err != nil { - logger.Log.Error(err) + log.Fatal(err) } // Send a message to the peer _, err = stream.Write([]byte("Hello, world!\n")) if err != nil { - logger.Log.Error(err) + log.Error(err) } // Read the reply from the peer reply, err := ioutil.ReadAll(stream) if err != nil { - logger.Log.Error(err) + log.Error(err) } - logger.Log.Info("read reply: %q\n", reply) + log.Infof("Read reply: %s", string(reply)) } From 6832cc3f4f2065611353d9129d980bfb3f68d85a Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Fri, 5 May 2017 23:59:14 -0700 Subject: [PATCH 04/11] Update travis, add MakeBasicHostTest --- .travis.yml | 3 +++ cumulus.go | 5 ----- cumulus_test.go | 11 ---------- {cumulus-peer => cumuluspeer}/peer.go | 4 +++- cumuluspeer/peer_test.go | 30 +++++++++++++++++++++++++++ main.go | 4 ++-- 6 files changed, 38 insertions(+), 19 deletions(-) delete mode 100644 cumulus.go delete mode 100644 cumulus_test.go rename {cumulus-peer => cumuluspeer}/peer.go (97%) create mode 100644 cumuluspeer/peer_test.go diff --git a/.travis.yml b/.travis.yml index 013de8f..b5abde0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,5 +5,8 @@ go: - master before_install: - go get github.com/mattn/goveralls + - go get github.com/sirupsen/logrus + - go get github.com/libp2p/go-libp2p + - go get github.com/multiformats/go-multiaddr script: - $HOME/gopath/bin/goveralls -service=travis-ci diff --git a/cumulus.go b/cumulus.go deleted file mode 100644 index 7799827..0000000 --- a/cumulus.go +++ /dev/null @@ -1,5 +0,0 @@ -package cumulus - -func dummy() bool { - return true -} diff --git a/cumulus_test.go b/cumulus_test.go deleted file mode 100644 index 1b5cef9..0000000 --- a/cumulus_test.go +++ /dev/null @@ -1,11 +0,0 @@ -package cumulus - -import ( - "testing" -) - -func TestCumulus(t *testing.T) { - if !dummy() { - t.Fail() - } -} diff --git a/cumulus-peer/peer.go b/cumuluspeer/peer.go similarity index 97% rename from cumulus-peer/peer.go rename to cumuluspeer/peer.go index f382ef9..21e514c 100644 --- a/cumulus-peer/peer.go +++ b/cumuluspeer/peer.go @@ -56,7 +56,9 @@ func doCumulate(s net.Stream) { // Create a Cumulus host. // This may throw an error if we fail to create a key pair, a pid, or a new // multiaddress. -func MakeHost(port int) (host.Host, pstore.Peerstore, error) { +func MakeBasicHost(port int) (host.Host, pstore.Peerstore, error) { + // Make sure we received a valid port number + // Generate a key pair for this host. We will only use the pudlic key to // obtain a valid host ID. _, pub, err := crypto.GenerateKeyPair(crypto.RSA, 2048) diff --git a/cumuluspeer/peer_test.go b/cumuluspeer/peer_test.go new file mode 100644 index 0000000..86d8808 --- /dev/null +++ b/cumuluspeer/peer_test.go @@ -0,0 +1,30 @@ +package cumuluspeer_test + +import ( + "testing" + + cumuluspeer "github.com/ubclaunchpad/cumulus/cumuluspeer" +) + +// Tests if we can make a basic host on a valid TCP port +func TestMakeBasicHostValidPort(t *testing.T) { + h, ps, err := cumuluspeer.MakeBasicHost(8000) + if err != nil { + t.Fail() + } + + if h == nil { + t.Fail() + } + + if ps == nil { + t.Fail() + } + + if ps != h.Peerstore() { + t.Fail() + } +} + +// TODO Test ExtractPeerInfo +// TODO Test BasicStreamHandler diff --git a/main.go b/main.go index 4fba8af..d3940d8 100644 --- a/main.go +++ b/main.go @@ -6,7 +6,7 @@ import ( "io/ioutil" log "github.com/sirupsen/logrus" - cumuluspeer "github.com/ubclaunchpad/cumulus/cumulus-peer" + cumuluspeer "github.com/ubclaunchpad/cumulus/cumuluspeer" pstore "github.com/libp2p/go-libp2p-peerstore" ) @@ -22,7 +22,7 @@ func main() { flag.Parse() // Set up a new host on the Cumulus network - host, ps, err := cumuluspeer.MakeHost(*port) + host, ps, err := cumuluspeer.MakeBasicHost(*port) if err != nil { log.Fatal(err) } From fd96a01b08de6ef9cdbc572ca1f931304198f2ef Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Sat, 6 May 2017 10:05:02 -0700 Subject: [PATCH 05/11] Update travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b5abde0..d1d6242 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ go: before_install: - go get github.com/mattn/goveralls - go get github.com/sirupsen/logrus - - go get github.com/libp2p/go-libp2p + - go get github.com/libp2p/go-libp2p/p2p - go get github.com/multiformats/go-multiaddr script: - $HOME/gopath/bin/goveralls -service=travis-ci From 124f0c9841a9dc4fbf737e42905cebd9f6db6696 Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Sat, 6 May 2017 10:09:58 -0700 Subject: [PATCH 06/11] Update travis.yml again (maybe this time?) --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d1d6242..0b9b607 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,7 @@ go: before_install: - go get github.com/mattn/goveralls - go get github.com/sirupsen/logrus - - go get github.com/libp2p/go-libp2p/p2p + - go get -d github.com/libp2p/go-libp2p - go get github.com/multiformats/go-multiaddr script: - $HOME/gopath/bin/goveralls -service=travis-ci From d9c9e51280553a38917c3a3b63aef5e59f99cd40 Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Sat, 6 May 2017 10:15:34 -0700 Subject: [PATCH 07/11] Yet another permutation of travis settings --- .travis.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0b9b607..013de8f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,8 +5,5 @@ go: - master before_install: - go get github.com/mattn/goveralls - - go get github.com/sirupsen/logrus - - go get -d github.com/libp2p/go-libp2p - - go get github.com/multiformats/go-multiaddr script: - $HOME/gopath/bin/goveralls -service=travis-ci From 980788983f11ab5d3d8e70f34a44bf42ecd382e7 Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Sat, 6 May 2017 11:37:39 -0700 Subject: [PATCH 08/11] Update peer tests and add IP address flag --- cumuluspeer/peer.go | 7 ++++--- cumuluspeer/peer_test.go | 10 +++++++++- main.go | 10 ++++++---- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/cumuluspeer/peer.go b/cumuluspeer/peer.go index 21e514c..ebf1179 100644 --- a/cumuluspeer/peer.go +++ b/cumuluspeer/peer.go @@ -17,8 +17,9 @@ import ( ) const ( - CumulusPort = 8765 // Cumulus peers communicate over this TCP port + DefaultPort = 8765 // Cumulus peers communicate over this TCP port CumulusProtocol = "/cumulate/0.0.1" // Cumulus communication protocol + DefaultIP = "127.0.0.1" // Default Host IP address if none given ) // A basic StreamHandler for a very basic host. @@ -56,7 +57,7 @@ func doCumulate(s net.Stream) { // Create a Cumulus host. // This may throw an error if we fail to create a key pair, a pid, or a new // multiaddress. -func MakeBasicHost(port int) (host.Host, pstore.Peerstore, error) { +func MakeBasicHost(ip string, port int) (host.Host, pstore.Peerstore, error) { // Make sure we received a valid port number // Generate a key pair for this host. We will only use the pudlic key to @@ -73,7 +74,7 @@ func MakeBasicHost(port int) (host.Host, pstore.Peerstore, error) { } // Create a multiaddress (IP address and TCP port for this peer). - addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/127.0.0.1/tcp/%d", port)) + addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, port)) if err != nil { return nil, nil, err } diff --git a/cumuluspeer/peer_test.go b/cumuluspeer/peer_test.go index 86d8808..064438d 100644 --- a/cumuluspeer/peer_test.go +++ b/cumuluspeer/peer_test.go @@ -8,7 +8,7 @@ import ( // Tests if we can make a basic host on a valid TCP port func TestMakeBasicHostValidPort(t *testing.T) { - h, ps, err := cumuluspeer.MakeBasicHost(8000) + h, ps, err := cumuluspeer.MakeBasicHost(cumuluspeer.DefaultIP, 8000) if err != nil { t.Fail() } @@ -26,5 +26,13 @@ func TestMakeBasicHostValidPort(t *testing.T) { } } +// Make sure MakeBasicHost fails with invalid IP +func TestMakeBasicHostInvalidIP(t *testing.T) { + _, _, err := cumuluspeer.MakeBasicHost("asdfasdf", 123) + if err == nil { + t.Fail() + } +} + // TODO Test ExtractPeerInfo // TODO Test BasicStreamHandler diff --git a/main.go b/main.go index d3940d8..c056526 100644 --- a/main.go +++ b/main.go @@ -16,13 +16,15 @@ func main() { // Get and parse command line arguments // targetPeer is a Multiaddr representing the target peer to connect to // when joining the Cumulus Network. - // port is the port to communicate over (defaults to peer.CumulusPort) + // port is the port to communicate over (defaults to peer.DefaultPort). + // ip is the public IP address of the this host. targetPeer := flag.String("t", "", "target peer to connect to") - port := flag.Int("p", cumuluspeer.CumulusPort, "TCP port to use") + port := flag.Int("p", cumuluspeer.DefaultPort, "TCP port to use for this host") + ip := flag.String("i", cumuluspeer.DefaultIP, "IP address to use for this host") flag.Parse() // Set up a new host on the Cumulus network - host, ps, err := cumuluspeer.MakeBasicHost(*port) + host, ps, err := cumuluspeer.MakeBasicHost(*ip, *port) if err != nil { log.Fatal(err) } @@ -70,5 +72,5 @@ func main() { log.Error(err) } - log.Infof("Read reply: %s", string(reply)) + log.Info("Read reply: ", string(reply)) } From 4bac6890ab099b5f4b6c881d9036867e30b31d58 Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Sat, 6 May 2017 18:27:19 -0700 Subject: [PATCH 09/11] Update travis, refactor peer, add tests --- .travis.yml | 1 + cumuluspeer/peer.go | 145 ----------------------------------- cumuluspeer/peer_test.go | 38 ---------- main.go | 97 ++++++++++++------------ peer/peer.go | 146 ++++++++++++++++++++++++++++++++++++ peer/peer_test.go | 158 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 356 insertions(+), 229 deletions(-) delete mode 100644 cumuluspeer/peer.go delete mode 100644 cumuluspeer/peer_test.go create mode 100644 peer/peer.go create mode 100644 peer/peer_test.go diff --git a/.travis.yml b/.travis.yml index 013de8f..8a50181 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,4 @@ before_install: - go get github.com/mattn/goveralls script: - $HOME/gopath/bin/goveralls -service=travis-ci + - go test ./... diff --git a/cumuluspeer/peer.go b/cumuluspeer/peer.go deleted file mode 100644 index ebf1179..0000000 --- a/cumuluspeer/peer.go +++ /dev/null @@ -1,145 +0,0 @@ -package cumuluspeer - -import ( - "bufio" - "context" - "fmt" - - log "github.com/sirupsen/logrus" - crypto "github.com/libp2p/go-libp2p-crypto" - host "github.com/libp2p/go-libp2p-host" - peer "github.com/libp2p/go-libp2p-peer" - net "github.com/libp2p/go-libp2p-net" - pstore "github.com/libp2p/go-libp2p-peerstore" - swarm "github.com/libp2p/go-libp2p-swarm" - ma "github.com/multiformats/go-multiaddr" - bhost "github.com/libp2p/go-libp2p/p2p/host/basic" -) - -const ( - DefaultPort = 8765 // Cumulus peers communicate over this TCP port - CumulusProtocol = "/cumulate/0.0.1" // Cumulus communication protocol - DefaultIP = "127.0.0.1" // Default Host IP address if none given -) - -// A basic StreamHandler for a very basic host. -// This should be passed as the second argument to SetStreamHandler(). -// This is called when a remote peer opens a new stream with the host that -// SetStreamHandler() is called on. -// We may want to implement another type of StreamHandler in the future. -func BasicStreamHandler(s net.Stream) { - log.Info("Setting basic stream handler.") - defer s.Close() - doCumulate(s) -} - -// Communicate with peers. -// TODO: Update this to do something useful. For now it just reads from the -// stream and writes back what it read. -func doCumulate(s net.Stream) { - buf := bufio.NewReader(s) - str, err := buf.ReadString('\n') - if err != nil { - log.Error(err) - return - } - - log.Info("Read: %s", str) - _, err = s.Write([]byte(str)) - if err != nil { - log.Error(err) - return - } - - log.Info("Done now. Bye!") -} - -// Create a Cumulus host. -// This may throw an error if we fail to create a key pair, a pid, or a new -// multiaddress. -func MakeBasicHost(ip string, port int) (host.Host, pstore.Peerstore, error) { - // Make sure we received a valid port number - - // Generate a key pair for this host. We will only use the pudlic key to - // obtain a valid host ID. - _, pub, err := crypto.GenerateKeyPair(crypto.RSA, 2048) - if err != nil { - return nil, nil, err - } - - // Obtain Peer ID from public key. - pid, err := peer.IDFromPublicKey(pub) - if err != nil { - return nil, nil, err - } - - // Create a multiaddress (IP address and TCP port for this peer). - addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, port)) - if err != nil { - return nil, nil, err - } - - // Create a peerstore (this stores information about other peers in the - // Cumulus network). - ps := pstore.NewPeerstore() - - // Create swarm (this is the interface to the libP2P Network) using the - // multiaddress, peerID, and peerStore we just created. - netwrk, err := swarm.NewNetwork( - context.Background(), - []ma.Multiaddr{addr}, - pid, - ps, - nil) - if err != nil { - return nil, nil, err - } - - // Actually create the host with the network we just set up. - basicHost := bhost.New(netwrk) - - // Build host multiaddress - hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", - basicHost.ID().Pretty())) - - // Now we can build a full multiaddress to reach this host - // by encapsulating both addresses: - fullAddr := addr.Encapsulate(hostAddr) - log.Info("I am ", fullAddr) - - // Add this host's address to its peerstore (avoid's net/identi error) - ps.AddAddr(pid, fullAddr, pstore.PermanentAddrTTL) - - return basicHost, ps, nil -} - -// Extracts target's the peer ID and multiaddress from the given multiaddress. -// Returns peer ID (esentially 46 character hash created by the peer) -// and the peer's multiaddress in the form /ip4//tcp/. -func ExtractPeerInfo(peerma string) (peer.ID, ma.Multiaddr, error) { - ipfsaddr, err := ma.NewMultiaddr(peerma) - if err != nil { - log.Error(err) - return "-", nil, err - } - - pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS) - if err != nil { - log.Error(err) - return "-", nil, err - } - - peerid, err := peer.IDB58Decode(pid) - if err != nil { - log.Error(err) - return "-", nil, err - } - - // Decapsulate the /ipfs/ part from the target - // /ip4//ipfs/ becomes /ip4/ - targetPeerAddr, _ := ma.NewMultiaddr( - fmt.Sprintf("/ipfs/%s", peer.IDB58Encode(peerid))) - trgtAddr := ipfsaddr.Decapsulate(targetPeerAddr) - - return peerid, trgtAddr, nil -} diff --git a/cumuluspeer/peer_test.go b/cumuluspeer/peer_test.go deleted file mode 100644 index 064438d..0000000 --- a/cumuluspeer/peer_test.go +++ /dev/null @@ -1,38 +0,0 @@ -package cumuluspeer_test - -import ( - "testing" - - cumuluspeer "github.com/ubclaunchpad/cumulus/cumuluspeer" -) - -// Tests if we can make a basic host on a valid TCP port -func TestMakeBasicHostValidPort(t *testing.T) { - h, ps, err := cumuluspeer.MakeBasicHost(cumuluspeer.DefaultIP, 8000) - if err != nil { - t.Fail() - } - - if h == nil { - t.Fail() - } - - if ps == nil { - t.Fail() - } - - if ps != h.Peerstore() { - t.Fail() - } -} - -// Make sure MakeBasicHost fails with invalid IP -func TestMakeBasicHostInvalidIP(t *testing.T) { - _, _, err := cumuluspeer.MakeBasicHost("asdfasdf", 123) - if err == nil { - t.Fail() - } -} - -// TODO Test ExtractPeerInfo -// TODO Test BasicStreamHandler diff --git a/main.go b/main.go index c056526..1d07bcf 100644 --- a/main.go +++ b/main.go @@ -1,76 +1,81 @@ package main import ( - "context" - "flag" - "io/ioutil" + "context" + "flag" + "io/ioutil" - log "github.com/sirupsen/logrus" - cumuluspeer "github.com/ubclaunchpad/cumulus/cumuluspeer" - pstore "github.com/libp2p/go-libp2p-peerstore" + pstore "github.com/libp2p/go-libp2p-peerstore" + log "github.com/sirupsen/logrus" + peer "github.com/ubclaunchpad/cumulus/peer" ) func main() { - log.Info("Starting Cumulus Peer") + log.Info("Starting Cumulus Peer") - // Get and parse command line arguments - // targetPeer is a Multiaddr representing the target peer to connect to - // when joining the Cumulus Network. - // port is the port to communicate over (defaults to peer.DefaultPort). - // ip is the public IP address of the this host. - targetPeer := flag.String("t", "", "target peer to connect to") - port := flag.Int("p", cumuluspeer.DefaultPort, "TCP port to use for this host") - ip := flag.String("i", cumuluspeer.DefaultIP, "IP address to use for this host") - flag.Parse() + // Get and parse command line arguments + // targetPeer is a Multiaddr representing the target peer to connect to + // when joining the Cumulus Network. + // port is the port to communicate over (defaults to peer.DefaultPort). + // ip is the public IP address of the this host. + targetPeer := flag.String("t", "", "target peer to connect to") + port := flag.Int("p", peer.DefaultPort, "TCP port to use for this host") + ip := flag.String("i", peer.DefaultIP, "IP address to use for this host") + debug := flag.Bool("d", false, "Enable debug logging") + flag.Parse() - // Set up a new host on the Cumulus network - host, ps, err := cumuluspeer.MakeBasicHost(*ip, *port) - if err != nil { - log.Fatal(err) - } + if *debug { + log.SetLevel(log.DebugLevel) + } - // Set the host StreamHandler for the Cumulus Protocol and use - // BasicStreamHandler as its StreamHandler. - host.SetStreamHandler(cumuluspeer.CumulusProtocol, - cumuluspeer.BasicStreamHandler) + // Set up a new host on the Cumulus network + host, err := peer.NewPeer(*ip, *port) + if err != nil { + log.Fatal(err) + } - if *targetPeer == "" { - // No target was specified, wait for incoming connections - log.Info("No target provided. Listening for incoming connections...") - select {} // Hang until someone connects to us - } + // Set the host StreamHandler for the Cumulus Protocol and use + // BasicStreamHandler as its StreamHandler. + host.SetStreamHandler(peer.CumulusProtocol, host.Receive) + if *targetPeer == "" { + // No target was specified, wait for incoming connections + log.Info("No target provided. Listening for incoming connections...") + select {} // Hang until someone connects to us + } - // Target is specified so connect to it and remember its address - peerid, targetAddr, err := cumuluspeer.ExtractPeerInfo(*targetPeer) - if err != nil { - log.Fatal(err) - } + // Target is specified so connect to it and remember its address + peerid, targetAddr, err := peer.ExtractPeerInfo(*targetPeer) + if err != nil { + log.Fatal(err) + } - // Store the peer's address in this host's PeerStore - ps.AddAddr(peerid, targetAddr, pstore.PermanentAddrTTL) + // Store the peer's address in this host's PeerStore + host.Peerstore().AddAddr(peerid, targetAddr, pstore.PermanentAddrTTL) - log.Info("Connected to Cumulus Peer:") - log.Info("\tPeer ID:", peerid.Pretty()) - log.Info("\tPeer Address:", targetAddr) + log.Info("Connected to Cumulus Peer:") + log.Info("Peer ID:", peerid.Pretty()) + log.Info("Peer Address:", targetAddr) - // Open a stream with the peer - stream, err := host.NewStream(context.Background(), peerid, - cumuluspeer.CumulusProtocol) + // Open a stream with the peer + stream, err := host.NewStream(context.Background(), peerid, + peer.CumulusProtocol) if err != nil { log.Fatal(err) } - // Send a message to the peer + // Send a message to the peer _, err = stream.Write([]byte("Hello, world!\n")) if err != nil { log.Error(err) } - // Read the reply from the peer + // Read the reply from the peer reply, err := ioutil.ReadAll(stream) if err != nil { log.Error(err) } - log.Info("Read reply: ", string(reply)) + log.Debugf("Peer %s read reply: ", host.ID(), string(reply)) + + stream.Close() } diff --git a/peer/peer.go b/peer/peer.go new file mode 100644 index 0000000..0abf1dc --- /dev/null +++ b/peer/peer.go @@ -0,0 +1,146 @@ +package peer + +import ( + "bufio" + "context" + "fmt" + + crypto "github.com/libp2p/go-libp2p-crypto" + host "github.com/libp2p/go-libp2p-host" + net "github.com/libp2p/go-libp2p-net" + lpeer "github.com/libp2p/go-libp2p-peer" + pstore "github.com/libp2p/go-libp2p-peerstore" + swarm "github.com/libp2p/go-libp2p-swarm" + bhost "github.com/libp2p/go-libp2p/p2p/host/basic" + ma "github.com/multiformats/go-multiaddr" + log "github.com/sirupsen/logrus" +) + +const ( + // DefaultPort is the TCP port hosts will communicate over if none is + // provided + DefaultPort = 8765 + + // CumulusProtocol is the name of the protocol peers communicate over + CumulusProtocol = "/cumulus/0.0.1" + + // DefaultIP is the IP address new hosts will use if none if provided + DefaultIP = "127.0.0.1" +) + +// Peer is a cumulus Peer composed of a host +type Peer struct { + host.Host +} + +// NewPeer creates a Cumulus host with the given IP addr and TCP port. +// This may throw an error if we fail to create a key pair, a pid, or a new +// multiaddress. +func NewPeer(ip string, port int) (*Peer, error) { + // Make sure we received a valid port number + + // Generate a key pair for this host. We will only use the pudlic key to + // obtain a valid host ID. + // Cannot throw error with given arguments + _, pub, _ := crypto.GenerateKeyPair(crypto.RSA, 2048) + + // Obtain Peer ID from public key. + // Cannot throw error with given argument + pid, _ := lpeer.IDFromPublicKey(pub) + + // Create a multiaddress (IP address and TCP port for this peer). + addr, err := ma.NewMultiaddr(fmt.Sprintf("/ip4/%s/tcp/%d", ip, port)) + if err != nil { + return nil, err + } + + ps := pstore.NewPeerstore() + + // Create swarm (this is the interface to the libP2P Network) using the + // multiaddress, peerID, and peerStore we just created. + netwrk, err := swarm.NewNetwork( + context.Background(), + []ma.Multiaddr{addr}, + pid, + ps, + nil) + if err != nil { + return nil, err + } + + // Actually create the host and peer with the network we just set up. + host := bhost.New(netwrk) + peer := &Peer{Host: host} + + // Build host multiaddress + hostAddr, _ := ma.NewMultiaddr(fmt.Sprintf("/ipfs/%s", + host.ID().Pretty())) + + // Now we can build a full multiaddress to reach this host + // by encapsulating both addresses: + fullAddr := addr.Encapsulate(hostAddr) + log.Info("I am ", fullAddr) + + // Add this host's address to its peerstore (avoid's net/identi error) + ps.AddAddr(pid, fullAddr, pstore.PermanentAddrTTL) + + return peer, nil +} + +// Receive is the function that gets called when a remote peer +// opens a new stream with the host that SetStreamHandler() is called on. +// This should be passed as the second argument to SetStreamHandler(). +// We may want to implement another type of StreamHandler in the future. +func (p *Peer) Receive(s net.Stream) { + log.Debug("Setting basic stream handler.") + defer s.Close() + p.doCumulus(s) +} + +// Communicate with peers. +// TODO: Update this to do something useful. For now it just reads from the +// stream and writes back what it read. +func (p *Peer) doCumulus(s net.Stream) { + buf := bufio.NewReader(s) + str, err := buf.ReadString('\n') + if err != nil { + log.Error(err) + return + } + + log.Debugf("Peer %s read: %s", p.ID(), str) + _, err = s.Write([]byte(str)) + if err != nil { + log.Error(err) + return + } +} + +// ExtractPeerInfo extracts the peer ID and multiaddress from the +// given multiaddress. +// Returns peer ID (esentially 46 character hash created by the peer) +// and the peer's multiaddress in the form /ip4//tcp/. +func ExtractPeerInfo(peerma string) (lpeer.ID, ma.Multiaddr, error) { + ipfsaddr, err := ma.NewMultiaddr(peerma) + if err != nil { + return "-", nil, err + } + + // Cannot throw error when passed P_IPFS + pid, _ := ipfsaddr.ValueForProtocol(ma.P_IPFS) + + // Cannot return error if no error was returned in NewMultiaddr + peerid, _ := lpeer.IDB58Decode(pid) + + // Decapsulate the /ipfs/ part from the target + // /ip4//ipfs/ becomes /ip4/ + targetPeerAddr, err := ma.NewMultiaddr( + fmt.Sprintf("/ipfs/%s", lpeer.IDB58Encode(peerid))) + if err != nil { + return "-", nil, err + } + + trgtAddr := ipfsaddr.Decapsulate(targetPeerAddr) + + return peerid, trgtAddr, nil +} diff --git a/peer/peer_test.go b/peer/peer_test.go new file mode 100644 index 0000000..0d59c25 --- /dev/null +++ b/peer/peer_test.go @@ -0,0 +1,158 @@ +package peer + +import ( + "context" + "fmt" + "testing" + + pstore "github.com/libp2p/go-libp2p-peerstore" + log "github.com/sirupsen/logrus" +) + +func TestMain(t *testing.T) { + // Disable logging for tests + log.SetLevel(log.FatalLevel) +} + +func TestNewPeerDefault(t *testing.T) { + h, err := NewPeer(DefaultIP, DefaultPort) + if err != nil { + t.Fail() + } + + if h == nil { + t.Fail() + } + + if h.Peerstore() == nil { + t.Fail() + } +} + +func TestNewPeerValidPort(t *testing.T) { + h, err := NewPeer(DefaultIP, 8000) + if err != nil { + t.Fail() + } + + if h == nil { + t.Fail() + } + + if h.Peerstore() == nil { + t.Fail() + } +} + +func TestNewPeerValidIP(t *testing.T) { + _, err := NewPeer("123.211.231.45", DefaultPort) + if err == nil { + t.Fail() + } +} + +func TestNewPeerInvalidIP(t *testing.T) { + _, err := NewPeer("asdfasdf", 123) + if err == nil { + t.Fail() + } +} + +func TestExtractPeerInfoValidMultiAddr(t *testing.T) { + peerma := "/ip4/127.0.0.1/tcp/8765/ipfs/QmQdfp9Ug4MoLRsBToDPN2aQhg2jPtmmA8UidQUTXGjZcy" + pid, ma, err := ExtractPeerInfo(peerma) + + if err != nil { + t.Fail() + } + + if pid.Pretty() != "QmQdfp9Ug4MoLRsBToDPN2aQhg2jPtmmA8UidQUTXGjZcy" { + t.Fail() + } + + if ma.String() != "/ip4/127.0.0.1/tcp/8765" { + t.Fail() + } +} + +func TestExtractPeerInfoInvalidIP(t *testing.T) { + peerma := "/ip4/203.532.211.5/tcp/8765/ipfs/Qmb89FuJ8UG3dpgUqEYu9eUqK474uP3mx32WnQ7kePXp8N" + _, _, err := ExtractPeerInfo(peerma) + + if err == nil { + t.Fail() + } +} + +func TestReceiveValidMessage(t *testing.T) { + receiver, err := NewPeer(DefaultIP, DefaultPort) + if err != nil { + t.Fail() + } + + sender, err := NewPeer(DefaultIP, 8080) + if err != nil { + t.Fail() + } + + receiver.SetStreamHandler(CumulusProtocol, receiver.Receive) + sender.SetStreamHandler(CumulusProtocol, sender.Receive) + + receiverMA := fmt.Sprintf("%s/ipfs/%s", + receiver.Addrs()[0].String(), receiver.ID().Pretty()) + + receiverID, receiverAddr, err := ExtractPeerInfo(receiverMA) + if err != nil { + t.Fail() + } + + sender.Peerstore().AddAddr(receiverID, receiverAddr, pstore.PermanentAddrTTL) + stream, err := sender.NewStream(context.Background(), receiverID, + CumulusProtocol) + if err != nil { + t.Fail() + } + + _, err = stream.Write([]byte("Hello, world!\n")) + if err != nil { + t.Fail() + } + + stream.Close() +} + +func TestReceiveInvalidMessage(t *testing.T) { + receiver, err := NewPeer(DefaultIP, DefaultPort) + if err != nil { + t.Fail() + } + + sender, err := NewPeer(DefaultIP, 8080) + if err != nil { + t.Fail() + } + + receiver.SetStreamHandler(CumulusProtocol, receiver.Receive) + + receiverMA := fmt.Sprintf("%s/ipfs/%s", + receiver.Addrs()[0].String(), receiver.ID().Pretty()) + + receiverID, receiverAddr, err := ExtractPeerInfo(receiverMA) + if err != nil { + t.Fail() + } + + sender.Peerstore().AddAddr(receiverID, receiverAddr, pstore.PermanentAddrTTL) + stream, err := sender.NewStream(context.Background(), receiverID, + CumulusProtocol) + if err != nil { + t.Fail() + } + + _, err = stream.Write([]byte("Hello, world!")) + if err != nil { + t.Fail() + } + + stream.Close() +} From a013db6a9885d0c739049d56fe8b2e2b2fe3411f Mon Sep 17 00:00:00 2001 From: Bruno Bachmann Date: Sun, 7 May 2017 00:29:23 -0700 Subject: [PATCH 10/11] Add peer.Connect(peer), add peer test --- main.go | 23 +++-------------------- peer/peer.go | 36 ++++++++++++++++++++++++++++++++++-- peer/peer_test.go | 35 +++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 38 deletions(-) diff --git a/main.go b/main.go index 1d07bcf..ae85459 100644 --- a/main.go +++ b/main.go @@ -1,11 +1,9 @@ package main import ( - "context" "flag" "io/ioutil" - pstore "github.com/libp2p/go-libp2p-peerstore" log "github.com/sirupsen/logrus" peer "github.com/ubclaunchpad/cumulus/peer" ) @@ -43,24 +41,9 @@ func main() { select {} // Hang until someone connects to us } - // Target is specified so connect to it and remember its address - peerid, targetAddr, err := peer.ExtractPeerInfo(*targetPeer) + stream, err := host.Connect(*targetPeer) if err != nil { - log.Fatal(err) - } - - // Store the peer's address in this host's PeerStore - host.Peerstore().AddAddr(peerid, targetAddr, pstore.PermanentAddrTTL) - - log.Info("Connected to Cumulus Peer:") - log.Info("Peer ID:", peerid.Pretty()) - log.Info("Peer Address:", targetAddr) - - // Open a stream with the peer - stream, err := host.NewStream(context.Background(), peerid, - peer.CumulusProtocol) - if err != nil { - log.Fatal(err) + log.Error(err) } // Send a message to the peer @@ -75,7 +58,7 @@ func main() { log.Error(err) } - log.Debugf("Peer %s read reply: ", host.ID(), string(reply)) + log.Debugf("Peer %s read reply: %s", host.ID(), string(reply)) stream.Close() } diff --git a/peer/peer.go b/peer/peer.go index 0abf1dc..ece18d7 100644 --- a/peer/peer.go +++ b/peer/peer.go @@ -109,6 +109,7 @@ func (p *Peer) doCumulus(s net.Stream) { } log.Debugf("Peer %s read: %s", p.ID(), str) + _, err = s.Write([]byte(str)) if err != nil { log.Error(err) @@ -121,15 +122,20 @@ func (p *Peer) doCumulus(s net.Stream) { // Returns peer ID (esentially 46 character hash created by the peer) // and the peer's multiaddress in the form /ip4//tcp/. func ExtractPeerInfo(peerma string) (lpeer.ID, ma.Multiaddr, error) { + log.Debug("Extracting peer info from ", peerma) + ipfsaddr, err := ma.NewMultiaddr(peerma) if err != nil { return "-", nil, err } // Cannot throw error when passed P_IPFS - pid, _ := ipfsaddr.ValueForProtocol(ma.P_IPFS) + pid, err := ipfsaddr.ValueForProtocol(ma.P_IPFS) + if err != nil { + return "-", nil, err + } - // Cannot return error if no error was returned in NewMultiaddr + // Cannot return error if no error was returned in ValueForProtocol peerid, _ := lpeer.IDB58Decode(pid) // Decapsulate the /ipfs/ part from the target @@ -144,3 +150,29 @@ func ExtractPeerInfo(peerma string) (lpeer.ID, ma.Multiaddr, error) { return peerid, trgtAddr, nil } + +// Connect adds the given multiaddress to p's Peerstore and opens a stream +// with the peer at that multiaddress if the multiaddress is valid, otherwise +// returns error. +func (p *Peer) Connect(peerma string) (net.Stream, error) { + peerid, targetAddr, err := ExtractPeerInfo(peerma) + if err != nil { + return nil, err + } + + // Store the peer's address in this host's PeerStore + p.Peerstore().AddAddr(peerid, targetAddr, pstore.PermanentAddrTTL) + + log.Debug("Connected to Cumulus Peer:") + log.Debug("Peer ID:", peerid.Pretty()) + log.Debug("Peer Address:", targetAddr) + + // Open a stream with the peer + stream, err := p.NewStream(context.Background(), peerid, + CumulusProtocol) + if err != nil { + return nil, err + } + + return stream, nil +} diff --git a/peer/peer_test.go b/peer/peer_test.go index 0d59c25..0be379b 100644 --- a/peer/peer_test.go +++ b/peer/peer_test.go @@ -1,11 +1,9 @@ package peer import ( - "context" "fmt" "testing" - pstore "github.com/libp2p/go-libp2p-peerstore" log "github.com/sirupsen/logrus" ) @@ -101,14 +99,7 @@ func TestReceiveValidMessage(t *testing.T) { receiverMA := fmt.Sprintf("%s/ipfs/%s", receiver.Addrs()[0].String(), receiver.ID().Pretty()) - receiverID, receiverAddr, err := ExtractPeerInfo(receiverMA) - if err != nil { - t.Fail() - } - - sender.Peerstore().AddAddr(receiverID, receiverAddr, pstore.PermanentAddrTTL) - stream, err := sender.NewStream(context.Background(), receiverID, - CumulusProtocol) + stream, err := sender.Connect(receiverMA) if err != nil { t.Fail() } @@ -137,22 +128,34 @@ func TestReceiveInvalidMessage(t *testing.T) { receiverMA := fmt.Sprintf("%s/ipfs/%s", receiver.Addrs()[0].String(), receiver.ID().Pretty()) - receiverID, receiverAddr, err := ExtractPeerInfo(receiverMA) + stream, err := sender.Connect(receiverMA) if err != nil { t.Fail() } - sender.Peerstore().AddAddr(receiverID, receiverAddr, pstore.PermanentAddrTTL) - stream, err := sender.NewStream(context.Background(), receiverID, - CumulusProtocol) + _, err = stream.Write([]byte("Hello, world!")) if err != nil { t.Fail() } - _, err = stream.Write([]byte("Hello, world!")) + stream.Close() +} + +func TestReceiveInvalidAddress(t *testing.T) { + receiver, err := NewPeer(DefaultIP, DefaultPort) if err != nil { t.Fail() } - stream.Close() + sender, err := NewPeer(DefaultIP, 8080) + if err != nil { + t.Fail() + } + + receiver.SetStreamHandler(CumulusProtocol, receiver.Receive) + + _, err = sender.Connect(receiver.Addrs()[0].String()) + if err == nil { + t.Fail() + } } From 4a89e2ce694027ef916795b207958a92d09e5784 Mon Sep 17 00:00:00 2001 From: Jordan Schalm Date: Sun, 7 May 2017 11:51:46 -0700 Subject: [PATCH 11/11] test goveralls --- main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.go b/main.go index ae85459..aa175ea 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,7 @@ import ( "io/ioutil" log "github.com/sirupsen/logrus" - peer "github.com/ubclaunchpad/cumulus/peer" + "github.com/ubclaunchpad/cumulus/peer" ) func main() {