diff --git a/main.go b/main.go index aedc6d5..2bf253b 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ import ( "lux/node" "lux/proto" "lux/rpc" + "net/netip" "os" "os/signal" "strconv" @@ -359,6 +360,29 @@ type HostConfig struct { } `xml:"node"` } +type HostStaticWAN struct { + addr4 netip.Addr + addr6 netip.Addr +} + +func NewHostStaticWAN(ip4 string, ip6 string) (HostStaticWAN, error) { + addr4, err := netip.ParseAddr(ip4) + if err != nil { + return HostStaticWAN{}, err + } + + addr6, err := netip.ParseAddr(ip6) + if err != nil { + return HostStaticWAN{}, err + } + + return HostStaticWAN{addr4, addr6}, nil +} + +func (wan *HostStaticWAN) Provide() (host.LuxOption, error) { + return &host.LuxOptionWAN{Addr4: wan.addr4, Addr6: wan.addr6}, nil +} + func hostMain() { xmlBytes, err := os.ReadFile(configPath) if err != nil { @@ -394,6 +418,11 @@ func hostMain() { os.Exit(1) } + if config.Heartbeat == 0 { + fmt.Fprintln(os.Stderr, "no minute interval provided in !") + os.Exit(1) + } + // daemonize if needed if daemonize { becomeDaemon() @@ -403,14 +432,74 @@ func hostMain() { host := host.NewLuxHost(config.Hostname, hostKey, ks) // populate option providers + for _, option := range config.Options { + if option.Type == "wan" { + wan := &option.WAN + + if wan.Method == "static" { + provider, err := NewHostStaticWAN(wan.Addr4, wan.Addr6) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to create static wan provider: %v\n", err) + os.Exit(1) + } + + host.AddOptionProvider(&provider) + } + } + } + + // add nodes + for _, node := range config.Nodes { + nodeId, err := proto.ParseLuxID(node.ID) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to parse node id: %v\n", err) + os.Exit(1) + } + + if err := host.AddNode(nodeId, node.Exterior); err != nil { + fmt.Fprintf(os.Stderr, "failed to add node: %v\n", err) + os.Exit(1) + } + } // start host + host.Start() // start heartbeat timer + stopChan := make(chan struct{}) + ticker := time.NewTicker(time.Duration(config.Heartbeat) * time.Minute) + go func() { + for { + select { + case <-ticker.C: + if err := host.Heartbeat(); err != nil { + fmt.Fprintf(os.Stderr, "failed to heartbeat: %v\n", err) + } + case <-stopChan: + ticker.Stop() + return + } + } + }() // handle signals in main thread + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + +signaling: + for { + sig := <-sigs + switch sig { + case syscall.SIGINT: + break signaling + case syscall.SIGTERM: + break signaling + } + } // stop host + close(stopChan) + host.Stop() } var rpcPath string