summaryrefslogtreecommitdiff
path: root/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'main.go')
-rw-r--r--main.go133
1 files changed, 133 insertions, 0 deletions
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..710f195
--- /dev/null
+++ b/main.go
@@ -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:
+ }
+ }
+}