package main
import (
"bufio"
"context"
"fmt"
"io/ioutil"
"os"
_ "time"
// ipfsaddr "github.com/ipfs/go-ipfs-addr"
libp2p "github.com/libp2p/go-libp2p"
host "github.com/libp2p/go-libp2p-host"
inet "github.com/libp2p/go-libp2p-net"
peerstore "github.com/libp2p/go-libp2p-peerstore"
"github.com/libp2p/go-libp2p-crypto"
"github.com/libp2p/go-floodsub"
ma "github.com/multiformats/go-multiaddr"
)
var ho host . Host
//var dhtPtr *dht.IpfsDHT
var TopicName string = "libp2p-demo-chat"
func parseArgs ( ) ( bool , string ) {
usage := fmt . Sprintf ( "Usage: %s [-b] [PRIVATE_KEY]\n\n-b is bootstrap mode (creates DHT)\nPRIVATE_KEY is the path to a private key like '../util/private_key.bin'\n" , os . Args [ 0 ] )
var bBootstrap bool = false
var privKeyFilePath string
var args [ ] string = os . Args [ 1 : ]
if ( len ( args ) == 0 ) || ( len ( args ) > 2 ) {
fmt . Printf ( "Error: wrong number of arguments\n\n%s" , usage )
os . Exit ( 1 )
}
if args [ 0 ] == "-b" {
bBootstrap = true
args = args [ 1 : ]
}
privKeyFilePath = args [ 0 ]
return bBootstrap , privKeyFilePath
}
func handleConn ( conn inet . Conn ) {
ctx := context . Background ( )
h := ho
fmt . Printf ( "<NOTICE> Got connection from %v\n" , conn . RemoteMultiaddr ( ) . String ( ) )
_ = h
_ = ctx
}
func main ( ) {
ctx := context . Background ( )
bBootstrap , privKeyFilePath := parseArgs ( )
fmt . Printf ( "Starting up in " )
if bBootstrap {
fmt . Printf ( "bootstrapper mode" )
} else {
fmt . Printf ( "peer mode" )
}
fmt . Printf ( " with private key '%s'\n" , privKeyFilePath )
//
// Read the private key
//
var privBytes [ ] byte
privBytes , err := ioutil . ReadFile ( privKeyFilePath )
if err != nil {
fmt . Println ( "ioutil.ReadFile: failed: %v" , err )
panic ( err )
}
var priv crypto . PrivKey
priv , err = crypto . UnmarshalPrivateKey ( privBytes )
if err != nil {
fmt . Println ( "crypto.UnmarshalPrivateKey: failed: %v" , err )
panic ( err )
}
//
// Construct our libp2p host
//
var host host . Host
if bBootstrap {
host , err = libp2p . New ( ctx ,
libp2p . ListenAddrStrings ( "/ip4/0.0.0.0/tcp/9876" ) ,
libp2p . Identity ( priv ) ,
)
} else {
host , err = libp2p . New ( ctx ,
libp2p . Identity ( priv ) ,
)
}
if err != nil {
fmt . Println ( "libp2p.New: failed: %v" , err )
panic ( err )
}
// ho = host
//fmt.Printf("To connect, run:\n")
//fmt.Printf("node js-dht-test/index.js %s/ipfs/%s\n", host.Addrs()[0], host.ID().Pretty())
//
// Construct a floodsub instance for this host
//
fsub , err := floodsub . NewFloodSub ( ctx , host )
if err != nil {
fmt . Println ( "Error (floodsub.NewFloodSub): %v" , err )
panic ( err )
}
//
// If we are the bootstrap node, don't try to connec to any peers.
// Else: try to connect to the bootstrap node.
//
const bootstrapAddrIP4Str string = "127.0.0.1"
if ! bBootstrap {
var bootstrapMultiAddr ma . Multiaddr
var pinfo * peerstore . PeerInfo
bootstrapMultiAddrStr := fmt . Sprintf ( "/ip4/%s/tcp/9876/ipfs/QmehVYruznbyDZuHBV4vEHESpDevMoAovET6aJ9oRuEzWa" , bootstrapAddrIP4Str )
fmt . Printf ( "bootstrapping to '%s'...\n" , bootstrapMultiAddrStr )
bootstrapMultiAddr , err := ma . NewMultiaddr ( bootstrapMultiAddrStr )
if err != nil {
fmt . Println ( "Error (ma.NewMultiaddr): %v" , err )
panic ( err )
}
pinfo , err = peerstore . InfoFromP2pAddr ( bootstrapMultiAddr )
if err != nil {
fmt . Println ( "Error (ma.NewMultiaddr): %v" , err )
panic ( err )
}
if err := host . Connect ( ctx , * pinfo ) ; err != nil {
fmt . Println ( "bootstrapping to peer failed: " , err )
}
}
//
// Subscribe to the topic and wait for messages published on that topic
//
sub , err := fsub . Subscribe ( TopicName )
if err != nil {
fmt . Println ( "Error (fsub.Subscribe): %v" , err )
panic ( err )
}
// Go and listen for messages from them, and print them to the screen
go func ( ) {
for {
msg , err := sub . Next ( ctx )
if err != nil {
fmt . Println ( "Error (sub.Next): %v" , err )
panic ( err )
}
fmt . Printf ( "%s: %s\n" , msg . GetFrom ( ) , string ( msg . GetData ( ) ) )
}
} ( )
host . Network ( ) . SetConnHandler ( handleConn )
if bBootstrap {
fmt . Println ( "Bootstrapper running. Ctrl+C to exit." )
for true {
}
} else {
// Now, wait for input from the user, and send that out!
fmt . Println ( "Type something and hit enter to send to other subscribers:" )
scan := bufio . NewScanner ( os . Stdin )
for scan . Scan ( ) {
if err := fsub . Publish ( TopicName , scan . Bytes ( ) ) ; err != nil {
panic ( err )
}
}
}
// //
// // Construct a DHT for peer discovery if we are the bootstrap node.
// // Else: construct a DHT client for peer discovery and connect to bootstrap node.
// //
// d, err := dht.New(ctx, host, dhtopts.Client(false))
// if err != nil {
// panic(err)
// }
// dhtPtr = d
}