diff options
Diffstat (limited to 'main.go')
| -rw-r--r-- | main.go | 133 |
1 files changed, 133 insertions, 0 deletions
@@ -0,0 +1,133 @@ +package main + +import ( + "context" + "encoding/base64" + "encoding/binary" + "fmt" + "os" + "os/signal" + "time" + + "github.com/charmbracelet/log" + "github.com/meshnet-gophers/meshtastic-go" + pb "github.com/meshnet-gophers/meshtastic-go/meshtastic" + flag "github.com/spf13/pflag" + "golang.org/x/crypto/curve25519" +) + +func main() { + var args struct { + DbDir string + LogsDir string + ConfigPath string + Interface string + Relentless bool + } + flag.StringVarP(&args.DbDir, "dbdir", "", "./data/", "The path to the database directory") + flag.StringVarP(&args.LogsDir, "logsdir", "", "./logs/", "The path to the logs directory") + flag.StringVarP(&args.ConfigPath, "config", "c", "./config.json", "The path to the config.json") + flag.StringVarP(&args.Interface, "interface", "i", "kava", "Mesh interface (kava, mqtt)") + flag.BoolVarP(&args.Relentless, "relentless", "r", false, "Relentless reconnect to modem") + flag.Parse() + + log.SetLevel(log.DebugLevel) + cfg, err := ReadConfig(args.ConfigPath) + if err != nil { + log.Fatal(err) + } + pbChannels := make([]*pb.ChannelSettings, len(cfg.Channels)) + for i, channel := range cfg.Channels { + var pbChannelSettings = pb.ChannelSettings{ + Name: channel.Name, + Psk: channel.PSK, + } + pbChannels[i] = &pbChannelSettings + } + + var nodeID meshtastic.NodeID + if len(cfg.NodeID) == 4 { + nodeID = meshtastic.NodeID(binary.BigEndian.Uint32(cfg.NodeID)) + } else if len(cfg.NodeID) == 0 { + nodeID, err = meshtastic.RandomNodeID() + if err != nil { + log.Fatal(err) + } + } + log.Print("Config:") + log.Print(" Database", "directory", args.DbDir) + log.Print(" Logs", "directory", args.LogsDir) + log.Print(" Node", "id", nodeID, "short", cfg.ShortName, "name", cfg.Name) + nodeConfig := NodeConfig{ + DatabaseDir: args.DbDir, + LogsDir: args.LogsDir, + NodeID: nodeID, + LongName: cfg.Name, + ShortName: cfg.ShortName, + DefaultHops: cfg.DefaultHops, + MaxHops: cfg.MaxHops, + Channels: &pb.ChannelSet{Settings: pbChannels}, + BroadcastNodeInfoInterval: time.Duration(cfg.NodeBroadcastInterval * float64(time.Second)), + BroadcastPositionInterval: time.Duration(cfg.Position.BroadcastInterval * float64(time.Second)), + // Position paramters + PositionLatitudeI: int32(cfg.Position.Latitude * 1.e7), + PositionLongitudeI: int32(cfg.Position.Longitude * 1.e7), + PositionAltitude: int32(cfg.Position.Altitude), + // Device Metrics + DeviceMetricsBroadcastInterval: time.Duration(cfg.DeviceMetrics.BroadcastInterval * float64(time.Second)), + DeviceMetricsUPSAddress: cfg.DeviceMetrics.UPSAddress, + TCPListenAddr: "0.0.0.0:4403", + } + if len(cfg.X25519Key) == 32 { + nodeConfig.X25519SecretKey = cfg.X25519Key + nodeConfig.X25519PublicKey, err = curve25519.X25519(nodeConfig.X25519SecretKey, curve25519.Basepoint) + if err != nil { + log.Fatal(err) + } + log.Print(" X25519PublicKey", "base64", base64.StdEncoding.EncodeToString(nodeConfig.X25519PublicKey), "hex", fmt.Sprintf("%x", nodeConfig.X25519PublicKey)) + } else if len(cfg.X25519Key) != 0 { + log.Fatal("invalid x25519 key") + } + + if args.Relentless { + log.Warn("Starting Node in 'relentless' mode...") + } else { + log.Info("Starting Node...") + } + + n, err := NewNode(nodeConfig) + if err != nil { + log.Fatal(err) + } + defer n.Close() + ctx, _ := signal.NotifyContext(context.Background(), os.Interrupt) + for { + var iface MeshIf + switch args.Interface { + case "kava": + iface = NewKavaConn(cfg.KavaModem.Address, 10*time.Second, n.cfg.Channels) + case "mqtt": + iface = NewMqttIf(cfg.MqttIf.Address, cfg.MqttIf.Username, cfg.MqttIf.Password, cfg.MqttIf.Root, cfg.MqttIf.ClientID, meshtastic.NodeID(nodeID), n.cfg.Channels) + default: + log.Fatal("invalid argument", "interface", args.Interface) + } + + if err := n.Run(ctx, iface); err != nil { + log.Error("!! Node.Run()", "err", err) + } + if err := ctx.Err(); err != nil { + log.Error("!! Caught interrupt!") + break + } + if !args.Relentless { + break + } + log.Warn("Reconnecting in 30 seconds...") + ticker := time.NewTicker(30 * time.Second) + select { + case <-ctx.Done(): + return + case <-ticker.C: + } + } +} |
