network/cmd/node/main.go
anonpenguin b7d8c42464 Remove DHT dependency and simplify peer discovery
Replace DHT-based discovery with bootstrap peerstore and peer exchange.
Update config and code to remove DHT references and dependencies. Add
data directory override support in node config. Cleanup related config
files and dependencies.
2025-08-14 14:02:58 +03:00

212 lines
6.6 KiB
Go

package main
import (
"context"
"flag"
"fmt"
"log"
"os"
"os/signal"
"path/filepath"
"syscall"
"git.debros.io/DeBros/network/pkg/anyoneproxy"
"git.debros.io/DeBros/network/pkg/config"
"git.debros.io/DeBros/network/pkg/logging"
"git.debros.io/DeBros/network/pkg/node"
"go.uber.org/zap"
)
func setup_logger(component logging.Component) (logger *logging.ColoredLogger) {
var err error
logger, err = logging.NewColoredLogger(component, true)
if err != nil {
log.Fatalf("Failed to create logger: %v", err)
}
return logger
}
func parse_and_return_network_flags() (dataDir, nodeID *string, p2pPort, rqlHTTP, rqlRaft *int, disableAnon *bool, rqlJoinAddr *string, advAddr *string, help *bool) {
logger := setup_logger(logging.ComponentNode)
dataDir = flag.String("data", "", "Data directory (auto-detected if not provided)")
nodeID = flag.String("id", "", "Node identifier (for running multiple local nodes)")
p2pPort = flag.Int("p2p-port", 4001, "LibP2P listen port")
rqlHTTP = flag.Int("rqlite-http-port", 5001, "RQLite HTTP API port")
rqlRaft = flag.Int("rqlite-raft-port", 7001, "RQLite Raft port")
disableAnon = flag.Bool("disable-anonrc", false, "Disable Anyone proxy routing (defaults to enabled on 127.0.0.1:9050)")
rqlJoinAddr = flag.String("rqlite-join-address", "", "RQLite address to join (e.g., /ip4/)")
advAddr = flag.String("adv-addr", "127.0.0.1", "Default Addvertise address for rqlite and rafts")
help = flag.Bool("help", false, "Show help")
flag.Parse()
logger.Info("Successfully parsed all flags and arguments.")
return
}
func disable_anon_proxy(disableAnon *bool) bool {
anyoneproxy.SetDisabled(*disableAnon)
logger := setup_logger(logging.ComponentAnyone)
if *disableAnon {
logger.Info("Anyone proxy routing is disabled. This means the node will not use the default Tor proxy for anonymous routing.\n")
}
return true
}
func check_if_should_open_help(help *bool) {
if *help {
flag.Usage()
return
}
}
func select_data_dir(dataDir *string, nodeID *string) {
logger := setup_logger(logging.ComponentNode)
if *nodeID == "" {
*dataDir = "./data/node"
}
logger.Info("Successfully selected Data Directory of: %s", zap.String("dataDir", *dataDir))
}
func startNode(ctx context.Context, cfg *config.Config, port int) error {
logger := setup_logger(logging.ComponentNode)
// Create and start node using the unified node implementation
n, err := node.NewNode(cfg)
if err != nil {
logger.Error("failed to create node: %v", zap.Error(err))
}
if err := n.Start(ctx); err != nil {
logger.Error("failed to start node: %v", zap.Error(err))
}
// Save the peer ID to a file for CLI access (especially useful for bootstrap)
peerID := n.GetPeerID()
peerInfoFile := filepath.Join(cfg.Node.DataDir, "peer.info")
peerMultiaddr := fmt.Sprintf("/ip4/0.0.0.0/tcp/%d/p2p/%s", port, peerID)
if err := os.WriteFile(peerInfoFile, []byte(peerMultiaddr), 0644); err != nil {
logger.Error("Failed to save peer info: %v", zap.Error(err))
} else {
logger.Info("Peer info saved to: %s", zap.String("path", peerInfoFile))
logger.Info("Bootstrap multiaddr: %s", zap.String("path", peerMultiaddr))
}
logger.Info("Node started successfully")
// Wait for context cancellation
<-ctx.Done()
// Stop node
return n.Stop()
}
// load_args_into_config applies command line argument overrides to the config
func load_args_into_config(cfg *config.Config, p2pPort, rqlHTTP, rqlRaft *int, rqlJoinAddr *string, advAddr *string, dataDir *string) {
logger := setup_logger(logging.ComponentNode)
// Apply RQLite HTTP port override
if *rqlHTTP != 5001 {
cfg.Database.RQLitePort = *rqlHTTP
logger.ComponentInfo(logging.ComponentNode, "Overriding RQLite HTTP port", zap.Int("port", *rqlHTTP))
}
// Apply RQLite Raft port override
if *rqlRaft != 7001 {
cfg.Database.RQLiteRaftPort = *rqlRaft
logger.ComponentInfo(logging.ComponentNode, "Overriding RQLite Raft port", zap.Int("port", *rqlRaft))
}
// Apply P2P port override
if *p2pPort != 4001 {
cfg.Node.ListenAddresses = []string{
fmt.Sprintf("/ip4/0.0.0.0/tcp/%d", *p2pPort),
}
logger.ComponentInfo(logging.ComponentNode, "Overriding P2P port", zap.Int("port", *p2pPort))
}
// Apply RQLite join address
if *rqlJoinAddr != "" {
cfg.Database.RQLiteJoinAddress = *rqlJoinAddr
logger.ComponentInfo(logging.ComponentNode, "Setting RQLite join address", zap.String("address", *rqlJoinAddr))
}
if *advAddr != "" {
cfg.Discovery.HttpAdvAddress = fmt.Sprintf("%s:%d", *advAddr, *rqlHTTP)
cfg.Discovery.RaftAdvAddress = fmt.Sprintf("%s:%d", *advAddr, *rqlRaft)
}
if *dataDir != "" {
cfg.Node.DataDir = *dataDir
}
}
func main() {
logger := setup_logger(logging.ComponentNode)
dataDir, nodeID, p2pPort, rqlHTTP, rqlRaft, disableAnon, rqlJoinAddr, advAddr, help := parse_and_return_network_flags()
disable_anon_proxy(disableAnon)
check_if_should_open_help(help)
select_data_dir(dataDir, nodeID)
// Load Node Configuration
var cfg *config.Config
cfg = config.DefaultConfig()
logger.ComponentInfo(logging.ComponentNode, "Default configuration loaded successfully")
// Apply command line argument overrides
load_args_into_config(cfg, p2pPort, rqlHTTP, rqlRaft, rqlJoinAddr, advAddr, dataDir)
logger.ComponentInfo(logging.ComponentNode, "Command line arguments applied to configuration")
// LibP2P uses configurable port (default 4001); RQLite uses 5001 (HTTP) and 7001 (Raft)
port := *p2pPort
logger.ComponentInfo(logging.ComponentNode, "Node configuration summary",
zap.Strings("listen_addresses", cfg.Node.ListenAddresses),
zap.Int("rqlite_http_port", cfg.Database.RQLitePort),
zap.Int("rqlite_raft_port", cfg.Database.RQLiteRaftPort),
zap.Int("p2p_port", port),
zap.Strings("bootstrap_peers", cfg.Discovery.BootstrapPeers),
zap.String("rqlite_join_address", cfg.Database.RQLiteJoinAddress),
zap.String("data_directory", *dataDir))
// Create context for graceful shutdown
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Start node in a goroutine
errChan := make(chan error, 1)
doneChan := make(chan struct{})
go func() {
if err := startNode(ctx, cfg, port); err != nil {
errChan <- err
}
close(doneChan)
}()
// Wait for interrupt signal or error
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
select {
case err := <-errChan:
logger.ComponentError(logging.ComponentNode, "Failed to start node", zap.Error(err))
os.Exit(1)
case <-c:
logger.ComponentInfo(logging.ComponentNode, "Shutting down node...")
cancel()
// Wait for node goroutine to finish cleanly
<-doneChan
logger.ComponentInfo(logging.ComponentNode, "Node shutdown complete")
}
}