package main import ( "fmt" "os" "path/filepath" "time" "github.com/meshnet-gophers/meshtastic-go" pb "github.com/meshnet-gophers/meshtastic-go/meshtastic" ) type DataLogger struct { data *os.File text *os.File } func NewDataLogger(logsDir string) (*DataLogger, error) { var err error var d DataLogger d.data, err = os.OpenFile(filepath.Join(logsDir, "data.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { d.Close() return nil, err } d.text, err = os.OpenFile(filepath.Join(logsDir, "text.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644) if err != nil { d.Close() return nil, err } return &d, nil } func (d *DataLogger) Close() error { if d.data != nil { d.data.Close() } if d.text != nil { d.text.Close() } return nil } func formatNodeInfo(ni *pb.NodeInfo) string { var str string if ni != nil { if ni.User != nil && ni.User.Id != "" { str = fmt.Sprintf("%s (%s) %s", ni.User.Id, ni.User.ShortName, ni.User.LongName) } else { str = meshtastic.NodeID(ni.Num).String() } } else { str = "???" } return str } func (d *DataLogger) LogPacket(p *pb.MeshPacket, c *pb.ChannelSettings, src *pb.NodeInfo, dst *pb.NodeInfo, data *pb.Data, payload any) error { source := formatNodeInfo(src) destination := formatNodeInfo(dst) header := fmt.Sprintf("%s | #%d:%s '%s' >> '%s' [rssi:%d snr:%f hs:%d, hl:%d]", time.Unix(int64(p.RxTime), 0), c.ChannelNum, c.Name, source, destination, p.RxRssi, p.RxSnr, p.HopStart, p.HopLimit) var s fmt.Stringer var log string var logfile *os.File = d.data switch data.Portnum { case pb.PortNum_NODEINFO_APP: s, _ = payload.(*pb.User) case pb.PortNum_TELEMETRY_APP: s, _ = payload.(*pb.Telemetry) case pb.PortNum_POSITION_APP: s, _ = payload.(*pb.Position) case pb.PortNum_ROUTING_APP: s, _ = payload.(*pb.Routing) case pb.PortNum_TRACEROUTE_APP: s, _ = payload.(*pb.RouteDiscovery) case pb.PortNum_AUDIO_APP: log = fmt.Sprintf("Audio message (%dB, %.2fs@800bps)", len(data.Payload), (float32(len(data.Payload)) / 100.0)) case pb.PortNum_TEXT_MESSAGE_APP: log = string(data.Payload) logfile = d.text default: log = p.String() } if log == "" && s != nil { log = s.String() } if log != "" && logfile != nil { output := fmt.Sprintf("%s : [%s] %T{ %s }\n", header, data.Portnum, payload, log) if _, err := logfile.Write([]byte(output)); err != nil { return err } return logfile.Sync() } return nil }