2021-04-13 18:54:06 +00:00
package waku
2021-03-18 23:21:45 +00:00
import (
"context"
"crypto/rand"
"encoding/hex"
2021-04-13 18:54:06 +00:00
"errors"
2021-03-18 23:21:45 +00:00
"fmt"
"net"
"os"
"os/signal"
"syscall"
2021-03-23 14:46:16 +00:00
"github.com/ethereum/go-ethereum/crypto"
2021-04-13 18:54:06 +00:00
dssql "github.com/ipfs/go-ds-sql"
logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p-peerstore/pstoreds"
2021-03-18 23:21:45 +00:00
"github.com/spf13/cobra"
"github.com/spf13/viper"
2021-04-13 18:54:06 +00:00
"github.com/status-im/go-waku/waku/persistence"
"github.com/status-im/go-waku/waku/persistence/sqlite"
2021-03-18 23:21:45 +00:00
"github.com/status-im/go-waku/waku/v2/node"
)
2021-04-13 18:54:06 +00:00
var log = logging . Logger ( "wakunode" )
2021-03-18 23:21:45 +00:00
func randomHex ( n int ) ( string , error ) {
bytes := make ( [ ] byte , n )
if _ , err := rand . Read ( bytes ) ; err != nil {
return "" , err
}
return hex . EncodeToString ( bytes ) , nil
}
2021-04-13 18:54:06 +00:00
func checkError ( err error , msg string ) {
if err != nil {
if msg != "" {
msg = msg + ": "
}
log . Fatal ( msg , err )
}
}
2021-03-18 23:21:45 +00:00
var rootCmd = & cobra . Command {
Use : "waku" ,
Short : "Start a waku node" ,
Long : ` Start a waku node... ` ,
// Uncomment the following line if your bare application
// has an action associated with it:
Run : func ( cmd * cobra . Command , args [ ] string ) {
port , _ := cmd . Flags ( ) . GetInt ( "port" )
relay , _ := cmd . Flags ( ) . GetBool ( "relay" )
key , _ := cmd . Flags ( ) . GetString ( "nodekey" )
store , _ := cmd . Flags ( ) . GetBool ( "store" )
2021-04-12 17:59:41 +00:00
dbPath , _ := cmd . Flags ( ) . GetString ( "dbpath" )
2021-03-18 23:21:45 +00:00
storenode , _ := cmd . Flags ( ) . GetString ( "storenode" )
staticnodes , _ := cmd . Flags ( ) . GetStringSlice ( "staticnodes" )
2021-04-15 21:23:07 +00:00
topics , _ := cmd . Flags ( ) . GetStringSlice ( "topics" )
2021-03-18 23:21:45 +00:00
2021-03-30 14:13:33 +00:00
hostAddr , _ := net . ResolveTCPAddr ( "tcp" , fmt . Sprint ( "0.0.0.0:" , port ) )
2021-03-18 23:21:45 +00:00
2021-04-13 18:54:06 +00:00
var err error
2021-03-18 23:21:45 +00:00
if key == "" {
key , err = randomHex ( 32 )
2021-04-13 18:54:06 +00:00
checkError ( err , "Could not generate random key" )
2021-03-18 23:21:45 +00:00
}
2021-03-23 14:46:16 +00:00
prvKey , err := crypto . HexToECDSA ( key )
2021-03-18 23:21:45 +00:00
2021-04-13 18:54:06 +00:00
if dbPath == "" {
checkError ( errors . New ( "dbpath can't be null" ) , "" )
2021-03-18 23:21:45 +00:00
}
2021-04-13 18:54:06 +00:00
db , err := sqlite . NewDB ( dbPath )
checkError ( err , "Could not connect to DB" )
ctx := context . Background ( )
// Create persistent peerstore
queries , err := sqlite . NewQueries ( "peerstore" , db )
checkError ( err , "Peerstore" )
datastore := dssql . NewDatastore ( db , queries )
opts := pstoreds . DefaultOpts ( )
peerStore , err := pstoreds . NewPeerstore ( ctx , datastore , opts )
checkError ( err , "Peerstore" )
wakuNode , err := node . New ( ctx , prvKey , [ ] net . Addr { hostAddr } , libp2p . Peerstore ( peerStore ) )
checkError ( err , "Wakunode" )
2021-03-18 23:21:45 +00:00
if relay {
wakuNode . MountRelay ( )
}
2021-04-13 18:54:06 +00:00
if store {
dbStore , err := persistence . NewDBStore ( persistence . WithDB ( db ) )
checkError ( err , "DBStore" )
2021-04-15 02:19:31 +00:00
err = wakuNode . MountStore ( true , dbStore )
2021-04-13 18:54:06 +00:00
checkError ( err , "Error mounting store" )
2021-04-12 17:59:41 +00:00
2021-03-18 23:21:45 +00:00
wakuNode . StartStore ( )
}
2021-04-15 21:23:07 +00:00
for _ , t := range topics {
nodeTopic := node . Topic ( t )
_ , err := wakuNode . Subscribe ( & nodeTopic )
checkError ( err , "Error subscring to topic" )
}
2021-03-18 23:21:45 +00:00
if storenode != "" && ! store {
2021-04-13 18:54:06 +00:00
checkError ( errors . New ( "Store protocol was not started" ) , "" )
2021-03-18 23:21:45 +00:00
} else {
if storenode != "" {
wakuNode . AddStorePeer ( storenode )
}
}
if len ( staticnodes ) > 0 {
for _ , n := range staticnodes {
go wakuNode . DialPeer ( n )
}
}
// Wait for a SIGINT or SIGTERM signal
ch := make ( chan os . Signal , 1 )
signal . Notify ( ch , syscall . SIGINT , syscall . SIGTERM )
<- ch
fmt . Println ( "\n\n\nReceived signal, shutting down..." )
// shut the node down
2021-03-22 16:45:13 +00:00
wakuNode . Stop ( )
2021-04-13 18:54:06 +00:00
err = db . Close ( )
checkError ( err , "DBClose" )
2021-03-18 23:21:45 +00:00
} ,
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute ( ) {
cobra . CheckErr ( rootCmd . Execute ( ) )
}
func init ( ) {
cobra . OnInitialize ( initConfig )
rootCmd . Flags ( ) . Int ( "port" , 9000 , "Libp2p TCP listening port (0 for random)" )
rootCmd . Flags ( ) . String ( "nodekey" , "" , "P2P node private key as hex (default random)" )
2021-04-15 21:23:07 +00:00
rootCmd . Flags ( ) . StringSlice ( "topics" , [ ] string { string ( node . DefaultWakuTopic ) } , fmt . Sprintf ( "List of topics to listen (default %s)" , node . DefaultWakuTopic ) )
2021-03-18 23:21:45 +00:00
rootCmd . Flags ( ) . StringSlice ( "staticnodes" , [ ] string { } , "Multiaddr of peer to directly connect with. Argument may be repeated" )
rootCmd . Flags ( ) . Bool ( "store" , false , "Enable store protocol" )
2021-04-12 17:59:41 +00:00
rootCmd . Flags ( ) . String ( "dbpath" , "./store.db" , "Path to DB file" )
2021-03-18 23:21:45 +00:00
rootCmd . Flags ( ) . String ( "storenode" , "" , "Multiaddr of peer to connect with for waku store protocol" )
rootCmd . Flags ( ) . Bool ( "relay" , true , "Enable relay protocol" )
}
func initConfig ( ) {
viper . AutomaticEnv ( ) // read in environment variables that match
}