From 86380cccf9ebddf75455bb8dbd9280c9b5a64cde Mon Sep 17 00:00:00 2001 From: Daniel Pupius Date: Mon, 21 Apr 2025 15:40:10 -0700 Subject: [PATCH] Refactor protos --- .gitignore | 2 +- .vscode/settings.json | 5 +- Makefile | 14 +- decoder/decoder.go | 226 ++-- decoder/formatter.go | 1026 +---------------- generated/meshstream/meshstream.pb.go | 1016 ++++++++++++++++ .../meshtastic/admin.pb.go | 6 +- .../meshtastic/apponly.pb.go | 6 +- .../meshtastic/atak.pb.go | 6 +- .../meshtastic/cannedmessages.pb.go | 6 +- .../meshtastic/channel.pb.go | 6 +- .../meshtastic/clientonly.pb.go | 6 +- .../meshtastic/config.pb.go | 6 +- .../meshtastic/connection_status.pb.go | 6 +- .../meshtastic/device_ui.pb.go | 6 +- .../meshtastic/deviceonly.pb.go | 6 +- .../meshtastic/interdevice.pb.go | 6 +- .../meshtastic/localonly.pb.go | 6 +- .../meshtastic/mesh.pb.go | 6 +- .../meshtastic/module_config.pb.go | 6 +- .../meshtastic/mqtt.pb.go | 6 +- .../meshtastic/nanopb.pb.go | 6 +- .../meshtastic/paxcount.pb.go | 6 +- .../meshtastic/portnums.pb.go | 6 +- .../meshtastic/powermon.pb.go | 6 +- .../meshtastic/remote_hardware.pb.go | 6 +- .../meshtastic/rtttl.pb.go | 6 +- .../meshtastic/storeforward.pb.go | 6 +- .../meshtastic/telemetry.pb.go | 6 +- .../meshtastic/xmodem.pb.go | 6 +- go.mod | 2 + mqtt/client.go | 12 +- mqtt/packet.go | 146 ++- proto/meshstream/meshstream.proto | 94 ++ proto/meshtastic/admin.proto | 2 +- proto/meshtastic/apponly.proto | 2 +- proto/meshtastic/atak.proto | 2 +- proto/meshtastic/cannedmessages.proto | 2 +- proto/meshtastic/channel.proto | 2 +- proto/meshtastic/clientonly.proto | 2 +- proto/meshtastic/config.proto | 2 +- proto/meshtastic/connection_status.proto | 2 +- proto/meshtastic/device_ui.proto | 2 +- proto/meshtastic/deviceonly.proto | 2 +- proto/meshtastic/interdevice.proto | 2 +- proto/meshtastic/localonly.proto | 2 +- proto/meshtastic/mesh.proto | 2 +- proto/meshtastic/module_config.proto | 2 +- proto/meshtastic/mqtt.proto | 2 +- proto/meshtastic/nanopb.proto | 2 +- proto/meshtastic/paxcount.proto | 2 +- proto/meshtastic/portnums.proto | 2 +- proto/meshtastic/powermon.proto | 2 +- proto/meshtastic/remote_hardware.proto | 2 +- proto/meshtastic/rtttl.proto | 2 +- proto/meshtastic/storeforward.proto | 2 +- proto/meshtastic/telemetry.proto | 2 +- proto/meshtastic/xmodem.proto | 2 +- server/server.go | 25 +- 59 files changed, 1477 insertions(+), 1283 deletions(-) create mode 100644 generated/meshstream/meshstream.pb.go rename {proto/generated => generated}/meshtastic/admin.pb.go (99%) rename {proto/generated => generated}/meshtastic/apponly.pb.go (96%) rename {proto/generated => generated}/meshtastic/atak.pb.go (99%) rename {proto/generated => generated}/meshtastic/cannedmessages.pb.go (95%) rename {proto/generated => generated}/meshtastic/channel.pb.go (98%) rename {proto/generated => generated}/meshtastic/clientonly.pb.go (97%) rename {proto/generated => generated}/meshtastic/config.pb.go (99%) rename {proto/generated => generated}/meshtastic/connection_status.pb.go (98%) rename {proto/generated => generated}/meshtastic/device_ui.pb.go (99%) rename {proto/generated => generated}/meshtastic/deviceonly.pb.go (99%) rename {proto/generated => generated}/meshtastic/interdevice.pb.go (98%) rename {proto/generated => generated}/meshtastic/localonly.pb.go (98%) rename {proto/generated => generated}/meshtastic/mesh.pb.go (99%) rename {proto/generated => generated}/meshtastic/module_config.pb.go (99%) rename {proto/generated => generated}/meshtastic/mqtt.pb.go (98%) rename {proto/generated => generated}/meshtastic/nanopb.pb.go (99%) rename {proto/generated => generated}/meshtastic/paxcount.pb.go (95%) rename {proto/generated => generated}/meshtastic/portnums.pb.go (98%) rename {proto/generated => generated}/meshtastic/powermon.pb.go (98%) rename {proto/generated => generated}/meshtastic/remote_hardware.pb.go (97%) rename {proto/generated => generated}/meshtastic/rtttl.pb.go (94%) rename {proto/generated => generated}/meshtastic/storeforward.pb.go (99%) rename {proto/generated => generated}/meshtastic/telemetry.pb.go (99%) rename {proto/generated => generated}/meshtastic/xmodem.pb.go (97%) create mode 100644 proto/meshstream/meshstream.proto diff --git a/.gitignore b/.gitignore index 549c745..ce67153 100644 --- a/.gitignore +++ b/.gitignore @@ -72,4 +72,4 @@ temp/ # Binary output type -meshstream \ No newline at end of file +#meshstream \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 4ca04cc..980488a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,6 @@ { - "cSpell.words": ["meshstream", "Motherlode", "mqtt"] + "cSpell.words": ["meshstream", "Motherlode", "mqtt"], + "protoc": { + "options": ["-Iproto"] + } } diff --git a/Makefile b/Makefile index a51bd9f..ce3de83 100644 --- a/Makefile +++ b/Makefile @@ -1,11 +1,14 @@ .PHONY: build run gen-proto clean tools +ROOT_DIR := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) + # Build directories BIN_DIR := bin TOOLS_DIR := $(BIN_DIR)/tools -# Tool commands +# Proto compilation PROTOC_GEN_GO := $(TOOLS_DIR)/protoc-gen-go +PROTO_FILES := $(shell find $(ROOT_DIR) -name "*.proto" | sed 's|$(ROOT_DIR)/||' ) # Build the application build: @@ -18,12 +21,13 @@ run: build # Generate Go code from Protocol Buffers gen-proto: tools - mkdir -p proto/generated + @mkdir -p $(ROOT_DIR)/generated PATH="$(TOOLS_DIR):$$PATH" protoc \ - -I./proto \ - --go_out=./proto/generated \ + -Iproto/ \ + --go_out=generated/ \ --go_opt=paths=source_relative \ - ./proto/meshtastic/*.proto + $(PROTO_FILES) + @echo "Generated Go code from Protocol Buffers" # Clean generated files clean: diff --git a/decoder/decoder.go b/decoder/decoder.go index a3964c7..1ff8ff9 100644 --- a/decoder/decoder.go +++ b/decoder/decoder.go @@ -1,62 +1,18 @@ package decoder import ( - "encoding/json" "fmt" "strings" - + "google.golang.org/protobuf/proto" - + + mesh "meshstream/proto/generated" pb "meshstream/proto/generated/meshtastic" ) -// DecodedPacket provides a simplified structure for decoded Meshtastic packets -type DecodedPacket struct { - // From Service Envelope - ChannelID string - GatewayID string - - // From Mesh Packet - ID uint32 - From uint32 - To uint32 - HopLimit uint32 - HopStart uint32 - WantACK bool - Priority string - ViaMQTT bool - NextHop uint32 - RelayNode uint32 - - // From Data - PortNum pb.PortNum - Payload interface{} - - // Additional Data fields - RequestID uint32 - ReplyID uint32 - Emoji uint32 - Dest uint32 - Source uint32 - WantResponse bool - - // Error tracking - DecodeError error -} - -// TopicInfo contains parsed information about a Meshtastic MQTT topic -type TopicInfo struct { - FullTopic string - RegionPath string - Version string - Format string - Channel string - UserID string -} - // ParseTopic parses a Meshtastic MQTT topic into its components -func ParseTopic(topic string) (*TopicInfo, error) { - info := &TopicInfo{ +func ParseTopic(topic string) (*mesh.TopicInfo, error) { + info := &mesh.TopicInfo{ FullTopic: topic, } @@ -71,7 +27,7 @@ func ParseTopic(topic string) (*TopicInfo, error) { // Find protocol version and format indices by looking for "2" followed by "e" or "json" versionIndex := -1 formatIndex := -1 - + for i := 1; i < len(parts)-1; i++ { if parts[i] == "2" { // Found the version @@ -80,33 +36,33 @@ func ParseTopic(topic string) (*TopicInfo, error) { break } } - + if versionIndex == -1 || formatIndex >= len(parts) { // Could not find proper version/format markers return info, fmt.Errorf("invalid topic format, missing version/format: %s", topic) } - + // Extract region path (all segments between "msh" and version) if versionIndex > 1 { info.RegionPath = strings.Join(parts[1:versionIndex], "/") } - + // Extract version and format info.Version = parts[versionIndex] info.Format = parts[formatIndex] - + // Extract channel and user ID channelIndex := formatIndex + 1 userIdIndex := channelIndex + 1 - + if channelIndex < len(parts) { info.Channel = parts[channelIndex] } - + if userIdIndex < len(parts) { - info.UserID = parts[userIdIndex] + info.UserId = parts[userIdIndex] } - + return info, nil } @@ -120,43 +76,39 @@ func DecodeEncodedMessage(payload []byte) (*pb.ServiceEnvelope, error) { } // DecodeMessage creates a DecodedPacket from a binary encoded message -func DecodeMessage(payload []byte, topicInfo *TopicInfo) *DecodedPacket { - decoded := &DecodedPacket{} - +func DecodeMessage(payload []byte, topicInfo *mesh.TopicInfo) *mesh.DecodedPacket { + decoded := &mesh.DecodedPacket{} + // First decode the envelope envelope, err := DecodeEncodedMessage(payload) if err != nil { - decoded.DecodeError = err + decoded.DecodeError = err.Error() return decoded } - - // Extract envelope fields without storing raw envelope - + // Extract envelope fields - decoded.ChannelID = envelope.GetChannelId() - decoded.GatewayID = envelope.GetGatewayId() - + decoded.ChannelId = envelope.GetChannelId() + decoded.GatewayId = envelope.GetGatewayId() + // Extract mesh packet fields if available packet := envelope.GetPacket() if packet == nil { - decoded.DecodeError = fmt.Errorf("no mesh packet in envelope") + decoded.DecodeError = "no mesh packet in envelope" return decoded } - - // Extract mesh packet fields without storing raw packet - + // Extract mesh packet fields - decoded.ID = packet.GetId() + decoded.Id = packet.GetId() decoded.From = packet.GetFrom() decoded.To = packet.GetTo() decoded.HopLimit = packet.GetHopLimit() decoded.HopStart = packet.GetHopStart() - decoded.WantACK = packet.GetWantAck() + decoded.WantAck = packet.GetWantAck() decoded.Priority = packet.GetPriority().String() - decoded.ViaMQTT = packet.GetViaMqtt() + decoded.ViaMqtt = packet.GetViaMqtt() decoded.NextHop = packet.GetNextHop() decoded.RelayNode = packet.GetRelayNode() - + // Process the payload if packet.GetDecoded() != nil { // Packet has already been decoded @@ -165,132 +117,153 @@ func DecodeMessage(payload []byte, topicInfo *TopicInfo) *DecodedPacket { // Packet is encrypted, try to decrypt it decodeEncryptedPayload(decoded, packet.GetEncrypted(), envelope.GetChannelId(), packet.GetId(), packet.GetFrom()) } else { - decoded.DecodeError = fmt.Errorf("packet has no payload") + decoded.DecodeError = "packet has no payload" } - + return decoded } // decodeDataPayload extracts information from a Data message -func decodeDataPayload(decoded *DecodedPacket, data *pb.Data) { - // Extract data fields without storing raw data - +func decodeDataPayload(decoded *mesh.DecodedPacket, data *pb.Data) { // Extract data fields decoded.PortNum = data.GetPortnum() - decoded.RequestID = data.GetRequestId() - decoded.ReplyID = data.GetReplyId() + decoded.RequestId = data.GetRequestId() + decoded.ReplyId = data.GetReplyId() decoded.Emoji = data.GetEmoji() decoded.Dest = data.GetDest() decoded.Source = data.GetSource() decoded.WantResponse = data.GetWantResponse() - + // Process the payload based on port type payload := data.GetPayload() - + switch data.GetPortnum() { case pb.PortNum_TEXT_MESSAGE_APP: - // Text message - just use the string - decoded.Payload = string(payload) - + // Text message - store as string + decoded.Payload = &mesh.DecodedPacket_TextMessage{ + TextMessage: string(payload), + } + case pb.PortNum_TEXT_MESSAGE_COMPRESSED_APP: - // Compressed text - just store the raw bytes for now - // TODO: Add decompression support - decoded.Payload = payload - + // Compressed text - store the raw bytes + decoded.Payload = &mesh.DecodedPacket_CompressedText{ + CompressedText: payload, + } + case pb.PortNum_POSITION_APP: // Position data var position pb.Position if err := proto.Unmarshal(payload, &position); err != nil { - decoded.DecodeError = fmt.Errorf("failed to unmarshal Position data: %v", err) + decoded.DecodeError = fmt.Sprintf("failed to unmarshal Position data: %v", err) } else { - decoded.Payload = &position + decoded.Payload = &mesh.DecodedPacket_Position{ + Position: &position, + } } - + case pb.PortNum_NODEINFO_APP: // Node information var user pb.User if err := proto.Unmarshal(payload, &user); err != nil { - decoded.DecodeError = fmt.Errorf("failed to unmarshal User data: %v", err) + decoded.DecodeError = fmt.Sprintf("failed to unmarshal User data: %v", err) } else { - decoded.Payload = &user + decoded.Payload = &mesh.DecodedPacket_NodeInfo{ + NodeInfo: &user, + } } - + case pb.PortNum_TELEMETRY_APP: // Telemetry data var telemetry pb.Telemetry if err := proto.Unmarshal(payload, &telemetry); err != nil { - decoded.DecodeError = fmt.Errorf("failed to unmarshal Telemetry data: %v", err) + decoded.DecodeError = fmt.Sprintf("failed to unmarshal Telemetry data: %v", err) } else { - decoded.Payload = &telemetry + decoded.Payload = &mesh.DecodedPacket_Telemetry{ + Telemetry: &telemetry, + } } - + case pb.PortNum_WAYPOINT_APP: // Waypoint data var waypoint pb.Waypoint if err := proto.Unmarshal(payload, &waypoint); err != nil { - decoded.DecodeError = fmt.Errorf("failed to unmarshal Waypoint data: %v", err) + decoded.DecodeError = fmt.Sprintf("failed to unmarshal Waypoint data: %v", err) } else { - decoded.Payload = &waypoint + decoded.Payload = &mesh.DecodedPacket_Waypoint{ + Waypoint: &waypoint, + } } - + case pb.PortNum_MAP_REPORT_APP: // Map report data var mapReport pb.MapReport if err := proto.Unmarshal(payload, &mapReport); err != nil { - decoded.DecodeError = fmt.Errorf("failed to unmarshal MapReport data: %v", err) + decoded.DecodeError = fmt.Sprintf("failed to unmarshal MapReport data: %v", err) } else { - decoded.Payload = &mapReport + decoded.Payload = &mesh.DecodedPacket_MapReport{ + MapReport: &mapReport, + } } - + case pb.PortNum_TRACEROUTE_APP: // Traceroute data var routeDiscovery pb.RouteDiscovery if err := proto.Unmarshal(payload, &routeDiscovery); err != nil { - decoded.DecodeError = fmt.Errorf("failed to unmarshal RouteDiscovery data: %v", err) + decoded.DecodeError = fmt.Sprintf("failed to unmarshal RouteDiscovery data: %v", err) } else { - decoded.Payload = &routeDiscovery + decoded.Payload = &mesh.DecodedPacket_RouteDiscovery{ + RouteDiscovery: &routeDiscovery, + } } - + case pb.PortNum_NEIGHBORINFO_APP: // Neighbor information data var neighborInfo pb.NeighborInfo if err := proto.Unmarshal(payload, &neighborInfo); err != nil { - decoded.DecodeError = fmt.Errorf("failed to unmarshal NeighborInfo data: %v", err) + decoded.DecodeError = fmt.Sprintf("failed to unmarshal NeighborInfo data: %v", err) } else { - decoded.Payload = &neighborInfo + decoded.Payload = &mesh.DecodedPacket_NeighborInfo{ + NeighborInfo: &neighborInfo, + } } - + default: // For other types, just store the raw bytes - decoded.Payload = payload + decoded.Payload = &mesh.DecodedPacket_BinaryData{ + BinaryData: payload, + } } } // decodeEncryptedPayload tries to decrypt and decode encrypted payloads -func decodeEncryptedPayload(decoded *DecodedPacket, encrypted []byte, channelId string, packetId, fromNode uint32) { +func decodeEncryptedPayload(decoded *mesh.DecodedPacket, encrypted []byte, channelId string, packetId, fromNode uint32) { // Attempt to decrypt the payload using the channel key if channelId == "" { - decoded.DecodeError = fmt.Errorf("encrypted packet has no channel ID") + decoded.DecodeError = "encrypted packet has no channel ID" return } - + channelKey := GetChannelKey(channelId) decrypted, err := XOR(encrypted, channelKey, packetId, fromNode) if err != nil { - decoded.DecodeError = fmt.Errorf("failed to decrypt payload: %v", err) + decoded.DecodeError = fmt.Sprintf("failed to decrypt payload: %v", err) return } - + // Try to parse as a Data message var data pb.Data if err := proto.Unmarshal(decrypted, &data); err != nil { // If we can't parse as Data, check if it's ASCII text if IsASCII(decrypted) { decoded.PortNum = pb.PortNum_TEXT_MESSAGE_APP - decoded.Payload = string(decrypted) + decoded.Payload = &mesh.DecodedPacket_TextMessage{ + TextMessage: string(decrypted), + } } else { - decoded.DecodeError = fmt.Errorf("failed to parse decrypted data: %v", err) - decoded.Payload = decrypted // Store raw bytes anyway + decoded.DecodeError = fmt.Sprintf("failed to parse decrypted data: %v", err) + decoded.Payload = &mesh.DecodedPacket_BinaryData{ + BinaryData: decrypted, + } } } else { // Successfully decoded the payload @@ -298,15 +271,6 @@ func decodeEncryptedPayload(decoded *DecodedPacket, encrypted []byte, channelId } } -// DecodeJSONMessage decodes a JSON message (format "json") -func DecodeJSONMessage(payload []byte) (map[string]interface{}, error) { - var jsonData map[string]interface{} - if err := json.Unmarshal(payload, &jsonData); err != nil { - return nil, fmt.Errorf("failed to parse JSON: %v", err) - } - return jsonData, nil -} - // IsASCII checks if the given byte array contains only ASCII characters func IsASCII(data []byte) bool { for _, b := range data { diff --git a/decoder/formatter.go b/decoder/formatter.go index f850b7a..5653817 100644 --- a/decoder/formatter.go +++ b/decoder/formatter.go @@ -1,1025 +1,5 @@ package decoder -import ( - "fmt" - "strings" - "time" - - "google.golang.org/protobuf/proto" - - pb "meshstream/proto/generated/meshtastic" -) - -// FormatTelemetryMessage formats a Telemetry message -func FormatTelemetryMessage(telemetry *pb.Telemetry) string { - var builder strings.Builder - - if telemetry == nil { - return "Error: nil telemetry data" - } - - builder.WriteString("Telemetry Data:\n") - - if telemetry.GetTime() != 0 { - tm := time.Unix(int64(telemetry.GetTime()), 0) - builder.WriteString(fmt.Sprintf(" Time: %s\n", tm.Format(time.RFC3339))) - } - - // Check which telemetry type we have - if env := telemetry.GetEnvironmentMetrics(); env != nil { - builder.WriteString(" Environment Telemetry:\n") - - temp := env.GetTemperature() - if temp != 0 { - builder.WriteString(fmt.Sprintf(" Temperature: %.2f °C\n", temp)) - } - - humidity := env.GetRelativeHumidity() - if humidity != 0 { - builder.WriteString(fmt.Sprintf(" Humidity: %.2f %%\n", humidity)) - } - - pressure := env.GetBarometricPressure() - if pressure != 0 { - builder.WriteString(fmt.Sprintf(" Pressure: %.2f hPa\n", pressure)) - } - - gasRes := env.GetGasResistance() - if gasRes != 0 { - builder.WriteString(fmt.Sprintf(" Gas Resistance: %.2f MΩ\n", gasRes)) - } - - iaq := env.GetIaq() - if iaq != 0 { - builder.WriteString(fmt.Sprintf(" Air Quality (IAQ): %d\n", iaq)) - } - - distance := env.GetDistance() - if distance != 0 { - builder.WriteString(fmt.Sprintf(" Distance: %.1f mm\n", distance)) - } - - lux := env.GetLux() - if lux != 0 { - builder.WriteString(fmt.Sprintf(" Light: %.1f lux\n", lux)) - } - - windDir := env.GetWindDirection() - if windDir != 0 { - directions := []string{"N", "NE", "E", "SE", "S", "SW", "W", "NW"} - dirIndex := int(windDir/45) % 8 - builder.WriteString(fmt.Sprintf(" Wind Direction: %d° (%s)\n", windDir, directions[dirIndex])) - } - - windSpeed := env.GetWindSpeed() - if windSpeed != 0 { - builder.WriteString(fmt.Sprintf(" Wind Speed: %.1f m/s\n", windSpeed)) - } - - windGust := env.GetWindGust() - if windGust != 0 { - builder.WriteString(fmt.Sprintf(" Wind Gust: %.1f m/s\n", windGust)) - } - } - - if power := telemetry.GetPowerMetrics(); power != nil { - builder.WriteString(" Power Telemetry:\n") - - ch1Volt := power.GetCh1Voltage() - if ch1Volt != 0 { - builder.WriteString(fmt.Sprintf(" Channel 1 Voltage: %.2f V\n", ch1Volt)) - } - - ch1Curr := power.GetCh1Current() - if ch1Curr != 0 { - builder.WriteString(fmt.Sprintf(" Channel 1 Current: %.2f mA\n", ch1Curr)) - } - - ch2Volt := power.GetCh2Voltage() - if ch2Volt != 0 { - builder.WriteString(fmt.Sprintf(" Channel 2 Voltage: %.2f V\n", ch2Volt)) - } - - ch2Curr := power.GetCh2Current() - if ch2Curr != 0 { - builder.WriteString(fmt.Sprintf(" Channel 2 Current: %.2f mA\n", ch2Curr)) - } - - ch3Volt := power.GetCh3Voltage() - if ch3Volt != 0 { - builder.WriteString(fmt.Sprintf(" Channel 3 Voltage: %.2f V\n", ch3Volt)) - } - - ch3Curr := power.GetCh3Current() - if ch3Curr != 0 { - builder.WriteString(fmt.Sprintf(" Channel 3 Current: %.2f mA\n", ch3Curr)) - } - } - - if air := telemetry.GetAirQualityMetrics(); air != nil { - builder.WriteString(" Air Quality Telemetry:\n") - - pm10 := air.GetPm10Standard() - if pm10 != 0 { - builder.WriteString(fmt.Sprintf(" PM 1.0: %d µg/m³\n", pm10)) - } - - pm25 := air.GetPm25Standard() - if pm25 != 0 { - builder.WriteString(fmt.Sprintf(" PM 2.5: %d µg/m³\n", pm25)) - } - - pm100 := air.GetPm100Standard() - if pm100 != 0 { - builder.WriteString(fmt.Sprintf(" PM 10.0: %d µg/m³\n", pm100)) - } - - co2 := air.GetCo2() - if co2 != 0 { - builder.WriteString(fmt.Sprintf(" CO2: %d ppm\n", co2)) - } - - // VOC field not available in this version of the proto - } - - // Device metrics - if device := telemetry.GetDeviceMetrics(); device != nil { - builder.WriteString(" Device Metrics:\n") - - batLevel := device.GetBatteryLevel() - if batLevel != 0 { - builder.WriteString(fmt.Sprintf(" Battery Level: %d%%\n", batLevel)) - } - - voltage := device.GetVoltage() - if voltage != 0 { - builder.WriteString(fmt.Sprintf(" Voltage: %.2f V\n", voltage)) - } - - chanUtil := device.GetChannelUtilization() - if chanUtil != 0 { - builder.WriteString(fmt.Sprintf(" Channel Utilization: %.2f%%\n", chanUtil)) - } - - airUtil := device.GetAirUtilTx() - if airUtil != 0 { - builder.WriteString(fmt.Sprintf(" Air Utilization TX: %.2f%%\n", airUtil)) - } - - uptime := device.GetUptimeSeconds() - if uptime != 0 { - uptimeDur := time.Duration(uptime) * time.Second - builder.WriteString(fmt.Sprintf(" Uptime: %s\n", uptimeDur)) - } - } - - // Local stats - if stats := telemetry.GetLocalStats(); stats != nil { - builder.WriteString(" Local Statistics:\n") - if stats.GetUptimeSeconds() != 0 { - uptime := time.Duration(stats.GetUptimeSeconds()) * time.Second - builder.WriteString(fmt.Sprintf(" Uptime: %s\n", uptime)) - } - if stats.GetChannelUtilization() != 0 { - builder.WriteString(fmt.Sprintf(" Channel Utilization: %.2f%%\n", stats.GetChannelUtilization())) - } - if stats.GetAirUtilTx() != 0 { - builder.WriteString(fmt.Sprintf(" Air Utilization TX: %.2f%%\n", stats.GetAirUtilTx())) - } - if stats.GetNumPacketsTx() != 0 { - builder.WriteString(fmt.Sprintf(" Packets Transmitted: %d\n", stats.GetNumPacketsTx())) - } - if stats.GetNumPacketsRx() != 0 { - builder.WriteString(fmt.Sprintf(" Packets Received: %d\n", stats.GetNumPacketsRx())) - } - if stats.GetNumPacketsRxBad() != 0 { - builder.WriteString(fmt.Sprintf(" Bad Packets Received: %d\n", stats.GetNumPacketsRxBad())) - } - if stats.GetNumOnlineNodes() != 0 { - builder.WriteString(fmt.Sprintf(" Online Nodes: %d\n", stats.GetNumOnlineNodes())) - } - if stats.GetNumTotalNodes() != 0 { - builder.WriteString(fmt.Sprintf(" Total Nodes: %d\n", stats.GetNumTotalNodes())) - } - } - - // Health metrics - if health := telemetry.GetHealthMetrics(); health != nil { - builder.WriteString(" Health Metrics:\n") - - heartBpm := health.GetHeartBpm() - if heartBpm != 0 { - builder.WriteString(fmt.Sprintf(" Heart Rate: %d bpm\n", heartBpm)) - } - - spo2 := health.GetSpO2() - if spo2 != 0 { - builder.WriteString(fmt.Sprintf(" SpO2: %d%%\n", spo2)) - } - - temp := health.GetTemperature() - if temp != 0 { - builder.WriteString(fmt.Sprintf(" Body Temperature: %.1f °C\n", temp)) - } - } - - - return builder.String() -} - -// FormatPositionMessage formats a Position message -func FormatPositionMessage(position *pb.Position) string { - var builder strings.Builder - - if position == nil { - return "Error: nil position data" - } - - builder.WriteString("Position Data:\n") - - // Check if we have valid position data - if position.GetLatitudeI() != 0 && position.GetLongitudeI() != 0 { - // Convert the integer coordinates to floating-point degrees - // Meshtastic uses a format where the values are stored as integers - // representing the position multiplied by 1e7 (10 million) - lat := float64(position.GetLatitudeI()) / 10000000.0 - lon := float64(position.GetLongitudeI()) / 10000000.0 - - builder.WriteString(fmt.Sprintf(" Latitude: %.7f\n", lat)) - builder.WriteString(fmt.Sprintf(" Longitude: %.7f\n", lon)) - - // Google Maps link for convenience - builder.WriteString(fmt.Sprintf(" Google Maps: https://maps.google.com/?q=%.7f,%.7f\n", lat, lon)) - } else { - builder.WriteString(" No valid latitude/longitude data\n") - } - - // Add altitude if available - if position.GetAltitude() != 0 { - builder.WriteString(fmt.Sprintf(" Altitude: %d meters\n", position.GetAltitude())) - } - - // Add time information - if position.GetTime() != 0 { - builder.WriteString(fmt.Sprintf(" Time: %d\n", position.GetTime())) - } - - if position.GetTimestamp() != 0 { - // Convert UNIX timestamp to readable time - tm := time.Unix(int64(position.GetTimestamp()), 0) - builder.WriteString(fmt.Sprintf(" Timestamp: %s\n", tm.Format(time.RFC3339))) - - if position.GetTimestampMillisAdjust() != 0 { - builder.WriteString(fmt.Sprintf(" Millis adjustment: %d\n", position.GetTimestampMillisAdjust())) - } - } - - // Source info - if position.GetLocationSource() != pb.Position_LOC_UNSET { - builder.WriteString(fmt.Sprintf(" Location Source: %s\n", position.GetLocationSource())) - } - - if position.GetAltitudeSource() != pb.Position_ALT_UNSET { - builder.WriteString(fmt.Sprintf(" Altitude Source: %s\n", position.GetAltitudeSource())) - } - - // GPS quality information if available - if position.GetPDOP() != 0 { - builder.WriteString(fmt.Sprintf(" PDOP: %.1f\n", float64(position.GetPDOP())/10)) - } - if position.GetHDOP() != 0 { - builder.WriteString(fmt.Sprintf(" HDOP: %.1f\n", float64(position.GetHDOP())/10)) - } - if position.GetVDOP() != 0 { - builder.WriteString(fmt.Sprintf(" VDOP: %.1f\n", float64(position.GetVDOP())/10)) - } - if position.GetGpsAccuracy() != 0 { - builder.WriteString(fmt.Sprintf(" GPS Accuracy: %d meters\n", position.GetGpsAccuracy())) - } - if position.GetGroundSpeed() != 0 { - builder.WriteString(fmt.Sprintf(" Ground Speed: %.1f m/s\n", float64(position.GetGroundSpeed())/100)) - } - if position.GetGroundTrack() != 0 { - builder.WriteString(fmt.Sprintf(" Ground Track: %d°\n", position.GetGroundTrack())) - } - if position.GetSatsInView() != 0 { - builder.WriteString(fmt.Sprintf(" Satellites in view: %d\n", position.GetSatsInView())) - } - - - return builder.String() -} - -// FormatNodeInfoMessage formats a User message (used by the NODEINFO_APP port) -func FormatNodeInfoMessage(user *pb.User) string { - var builder strings.Builder - - if user == nil { - return "Error: nil user data" - } - - builder.WriteString("Node Information:\n") - - if user.GetId() != "" { - builder.WriteString(fmt.Sprintf(" ID: %s\n", user.GetId())) - } - - if user.GetLongName() != "" { - builder.WriteString(fmt.Sprintf(" Name: %s\n", user.GetLongName())) - } - - if user.GetShortName() != "" { - builder.WriteString(fmt.Sprintf(" Short Name: %s\n", user.GetShortName())) - } - - if user.GetHwModel() != pb.HardwareModel_UNSET { - builder.WriteString(fmt.Sprintf(" Hardware: %s\n", user.GetHwModel())) - } - - if user.GetIsLicensed() { - builder.WriteString(" Licensed HAM operator\n") - } - - if user.GetRole() != 0 { - builder.WriteString(fmt.Sprintf(" Role: %s\n", user.GetRole())) - } - - if len(user.GetPublicKey()) > 0 { - builder.WriteString(fmt.Sprintf(" Public Key: %x\n", user.GetPublicKey())) - } - - - return builder.String() -} - -// FormatRouteDiscoveryMessage formats a RouteDiscovery message -func FormatRouteDiscoveryMessage(routeDiscovery *pb.RouteDiscovery) string { - var builder strings.Builder - - if routeDiscovery == nil { - return "Error: nil route discovery data" - } - - builder.WriteString("Route Discovery Data:\n") - - // Format route information - route := routeDiscovery.GetRoute() - if len(route) > 0 { - builder.WriteString(" Route Towards Destination:\n") - - for i, nodeId := range route { - snrText := "" - if i < len(routeDiscovery.GetSnrTowards()) { - // SNR values are scaled by 4 - snrValue := float32(routeDiscovery.GetSnrTowards()[i]) / 4.0 - snrText = fmt.Sprintf(" (SNR: %.1f dB)", snrValue) - } - builder.WriteString(fmt.Sprintf(" Hop %d: Node %d%s\n", i+1, nodeId, snrText)) - } - } else { - builder.WriteString(" No route towards destination recorded\n") - } - - routeBack := routeDiscovery.GetRouteBack() - if len(routeBack) > 0 { - builder.WriteString(" Route Back from Destination:\n") - - for i, nodeId := range routeBack { - snrText := "" - if i < len(routeDiscovery.GetSnrBack()) { - // SNR values are scaled by 4 - snrValue := float32(routeDiscovery.GetSnrBack()[i]) / 4.0 - snrText = fmt.Sprintf(" (SNR: %.1f dB)", snrValue) - } - builder.WriteString(fmt.Sprintf(" Hop %d: Node %d%s\n", i+1, nodeId, snrText)) - } - } else { - builder.WriteString(" No return route recorded\n") - } - - return builder.String() -} - -// FormatNeighborInfoMessage formats a NeighborInfo message -func FormatNeighborInfoMessage(neighborInfo *pb.NeighborInfo) string { - var builder strings.Builder - - if neighborInfo == nil { - return "Error: nil neighbor info data" - } - - builder.WriteString("Neighbor Info Data:\n") - - // Node information - builder.WriteString(fmt.Sprintf(" Node ID: %d\n", neighborInfo.GetNodeId())) - - if neighborInfo.GetLastSentById() != 0 { - builder.WriteString(fmt.Sprintf(" Last Sent By ID: %d\n", neighborInfo.GetLastSentById())) - } - - if neighborInfo.GetNodeBroadcastIntervalSecs() != 0 { - builder.WriteString(fmt.Sprintf(" Broadcast Interval: %d seconds\n", neighborInfo.GetNodeBroadcastIntervalSecs())) - } - - // Format neighbors - neighbors := neighborInfo.GetNeighbors() - if len(neighbors) > 0 { - builder.WriteString(" Neighbors:\n") - - for i, neighbor := range neighbors { - builder.WriteString(fmt.Sprintf(" Neighbor %d:\n", i+1)) - builder.WriteString(fmt.Sprintf(" Node ID: %d\n", neighbor.GetNodeId())) - builder.WriteString(fmt.Sprintf(" SNR: %.1f dB\n", neighbor.GetSnr())) - - if neighbor.GetLastRxTime() != 0 { - // Convert UNIX timestamp to readable time - rxTime := time.Unix(int64(neighbor.GetLastRxTime()), 0) - builder.WriteString(fmt.Sprintf(" Last Received: %s\n", rxTime.Format(time.RFC3339))) - } - - if neighbor.GetNodeBroadcastIntervalSecs() != 0 { - builder.WriteString(fmt.Sprintf(" Broadcast Interval: %d seconds\n", neighbor.GetNodeBroadcastIntervalSecs())) - } - } - } else { - builder.WriteString(" No neighbors recorded\n") - } - - return builder.String() -} - -// FormatWaypointMessage formats a Waypoint message -func FormatWaypointMessage(waypoint *pb.Waypoint) string { - var builder strings.Builder - - if waypoint == nil { - return "Error: nil waypoint data" - } - - builder.WriteString("Waypoint:\n") - - if waypoint.GetId() != 0 { - builder.WriteString(fmt.Sprintf(" ID: %d\n", waypoint.GetId())) - } - - if waypoint.GetName() != "" { - builder.WriteString(fmt.Sprintf(" Name: %s\n", waypoint.GetName())) - } - - if waypoint.GetDescription() != "" { - builder.WriteString(fmt.Sprintf(" Description: %s\n", waypoint.GetDescription())) - } - - if waypoint.GetLatitudeI() != 0 && waypoint.GetLongitudeI() != 0 { - // Convert the integer coordinates to floating-point degrees - lat := float64(waypoint.GetLatitudeI()) / 10000000.0 - lon := float64(waypoint.GetLongitudeI()) / 10000000.0 - - builder.WriteString(fmt.Sprintf(" Latitude: %.7f\n", lat)) - builder.WriteString(fmt.Sprintf(" Longitude: %.7f\n", lon)) - - // Google Maps link for convenience - builder.WriteString(fmt.Sprintf(" Google Maps: https://maps.google.com/?q=%.7f,%.7f\n", lat, lon)) - } - - if waypoint.GetIcon() != 0 { - builder.WriteString(fmt.Sprintf(" Icon: %d\n", waypoint.GetIcon())) - } - - if waypoint.GetExpire() != 0 { - // Convert UNIX timestamp to readable time - tm := time.Unix(int64(waypoint.GetExpire()), 0) - builder.WriteString(fmt.Sprintf(" Expires: %s\n", tm.Format(time.RFC3339))) - } - - if waypoint.GetLockedTo() != 0 { - builder.WriteString(fmt.Sprintf(" Locked to node: %d\n", waypoint.GetLockedTo())) - } - - - return builder.String() -} - -// FormatDataMessage formats a Data message -func FormatDataMessage(data *pb.Data) string { - if data == nil { - return "Error: nil data" - } - - var builder strings.Builder - builder.WriteString(fmt.Sprintf("Data (Port: %s):\n", data.GetPortnum())) - - // Format payload based on port type - payload := data.GetPayload() - switch data.GetPortnum() { - case pb.PortNum_TEXT_MESSAGE_APP: - builder.WriteString(fmt.Sprintf(" Text Message: %s\n", string(payload))) - - case pb.PortNum_TEXT_MESSAGE_COMPRESSED_APP: - builder.WriteString(fmt.Sprintf(" Compressed Text Message (%d bytes): %x\n", len(payload), payload)) - - case pb.PortNum_TELEMETRY_APP: - var telemetry pb.Telemetry - if err := proto.Unmarshal(payload, &telemetry); err == nil { - builder.WriteString(FormatTelemetryMessage(&telemetry)) - } else { - builder.WriteString(fmt.Sprintf(" Failed to parse telemetry: %v\n", err)) - builder.WriteString(fmt.Sprintf(" Raw bytes (%d): %x\n", len(payload), payload)) - } - - case pb.PortNum_POSITION_APP: - var position pb.Position - if err := proto.Unmarshal(payload, &position); err == nil { - builder.WriteString(FormatPositionMessage(&position)) - } else { - builder.WriteString(fmt.Sprintf(" Failed to parse position: %v\n", err)) - builder.WriteString(fmt.Sprintf(" Raw bytes (%d): %x\n", len(payload), payload)) - } - - case pb.PortNum_NODEINFO_APP: - var user pb.User - if err := proto.Unmarshal(payload, &user); err == nil { - builder.WriteString(FormatNodeInfoMessage(&user)) - } else { - builder.WriteString(fmt.Sprintf(" Failed to parse node info: %v\n", err)) - builder.WriteString(fmt.Sprintf(" Raw bytes (%d): %x\n", len(payload), payload)) - } - - case pb.PortNum_WAYPOINT_APP: - var waypoint pb.Waypoint - if err := proto.Unmarshal(payload, &waypoint); err == nil { - builder.WriteString(FormatWaypointMessage(&waypoint)) - } else { - builder.WriteString(fmt.Sprintf(" Failed to parse waypoint: %v\n", err)) - builder.WriteString(fmt.Sprintf(" Raw bytes (%d): %x\n", len(payload), payload)) - } - - default: - // For unknown types, show raw binary data - builder.WriteString(fmt.Sprintf(" Binary data (%d bytes): %x\n", len(payload), payload)) - // If it looks like ASCII text, also show as text - if IsASCII(payload) { - builder.WriteString(fmt.Sprintf(" As Text: %s\n", string(payload))) - } - } - - // Show additional Data fields - if data.GetRequestId() != 0 { - builder.WriteString(fmt.Sprintf(" Request ID: %d\n", data.GetRequestId())) - } - if data.GetReplyId() != 0 { - builder.WriteString(fmt.Sprintf(" Reply ID: %d\n", data.GetReplyId())) - } - if data.GetEmoji() != 0 { - builder.WriteString(fmt.Sprintf(" Emoji: %d\n", data.GetEmoji())) - } - if data.GetDest() != 0 { - builder.WriteString(fmt.Sprintf(" Destination Node: %d\n", data.GetDest())) - } - if data.GetSource() != 0 { - builder.WriteString(fmt.Sprintf(" Source Node: %d\n", data.GetSource())) - } - if data.GetWantResponse() { - builder.WriteString(" Wants Response: Yes\n") - } - - return builder.String() -} - -// FormatMapReportMessage formats a MapReport message -func FormatMapReportMessage(mapReport *pb.MapReport) string { - var builder strings.Builder - - if mapReport == nil { - return "Error: nil map report data" - } - - builder.WriteString("Map Report Data:\n") - - // Node information - if mapReport.GetLongName() != "" { - builder.WriteString(fmt.Sprintf(" Long Name: %s\n", mapReport.GetLongName())) - } - - if mapReport.GetShortName() != "" { - builder.WriteString(fmt.Sprintf(" Short Name: %s\n", mapReport.GetShortName())) - } - - if mapReport.GetRole() != 0 { - builder.WriteString(fmt.Sprintf(" Role: %s\n", mapReport.GetRole().String())) - } - - if mapReport.GetHwModel() != pb.HardwareModel_UNSET { - builder.WriteString(fmt.Sprintf(" Hardware: %s\n", mapReport.GetHwModel().String())) - } - - if mapReport.GetFirmwareVersion() != "" { - builder.WriteString(fmt.Sprintf(" Firmware: %s\n", mapReport.GetFirmwareVersion())) - } - - if mapReport.GetRegion() != 0 { - builder.WriteString(fmt.Sprintf(" Region: %s\n", mapReport.GetRegion().String())) - } - - if mapReport.GetModemPreset() != 0 { - builder.WriteString(fmt.Sprintf(" Modem Preset: %s\n", mapReport.GetModemPreset().String())) - } - - builder.WriteString(fmt.Sprintf(" Default Channel: %v\n", mapReport.GetHasDefaultChannel())) - - // Position information - if mapReport.GetLatitudeI() != 0 && mapReport.GetLongitudeI() != 0 { - // Convert the integer coordinates to floating-point degrees - // Meshtastic uses a format where the values are stored as integers - // representing the position multiplied by 1e7 (10 million) - lat := float64(mapReport.GetLatitudeI()) / 10000000.0 - lon := float64(mapReport.GetLongitudeI()) / 10000000.0 - - builder.WriteString(fmt.Sprintf(" Latitude: %.7f\n", lat)) - builder.WriteString(fmt.Sprintf(" Longitude: %.7f\n", lon)) - builder.WriteString(fmt.Sprintf(" Position Precision: %d bits\n", mapReport.GetPositionPrecision())) - - // Google Maps link for convenience - builder.WriteString(fmt.Sprintf(" Google Maps: https://maps.google.com/?q=%.7f,%.7f\n", lat, lon)) - } - - if mapReport.GetAltitude() != 0 { - builder.WriteString(fmt.Sprintf(" Altitude: %d meters\n", mapReport.GetAltitude())) - } - - if mapReport.GetNumOnlineLocalNodes() != 0 { - builder.WriteString(fmt.Sprintf(" Online Local Nodes: %d\n", mapReport.GetNumOnlineLocalNodes())) - } - - - return builder.String() -} - -// FormatPayload formats a payload based on its type and port number -func FormatPayload(payload interface{}, portNum pb.PortNum) string { - if payload == nil { - return " No payload data\n" - } - - switch portNum { - case pb.PortNum_TEXT_MESSAGE_APP: - // Text message - if text, ok := payload.(string); ok { - return fmt.Sprintf(" Text Message: %s\n", text) - } - - case pb.PortNum_TEXT_MESSAGE_COMPRESSED_APP: - // Compressed text - if data, ok := payload.([]byte); ok { - return fmt.Sprintf(" Compressed Text Message (%d bytes): %x\n", len(data), data) - // TODO: Add decompression support - } - - case pb.PortNum_TELEMETRY_APP: - // Telemetry data - if telemetry, ok := payload.(*pb.Telemetry); ok { - return FormatTelemetryMessage(telemetry) - } - - case pb.PortNum_POSITION_APP: - // Position data - if position, ok := payload.(*pb.Position); ok { - return FormatPositionMessage(position) - } - - case pb.PortNum_NODEINFO_APP: - // Node information - if user, ok := payload.(*pb.User); ok { - return FormatNodeInfoMessage(user) - } - - case pb.PortNum_WAYPOINT_APP: - // Waypoint data - if waypoint, ok := payload.(*pb.Waypoint); ok { - return FormatWaypointMessage(waypoint) - } - - case pb.PortNum_MAP_REPORT_APP: - // Map data - if mapReport, ok := payload.(*pb.MapReport); ok { - return FormatMapReportMessage(mapReport) - } - - case pb.PortNum_TRACEROUTE_APP: - // Traceroute data - if routeDiscovery, ok := payload.(*pb.RouteDiscovery); ok { - return FormatRouteDiscoveryMessage(routeDiscovery) - } - - case pb.PortNum_NEIGHBORINFO_APP: - // Neighbor info data - if neighborInfo, ok := payload.(*pb.NeighborInfo); ok { - return FormatNeighborInfoMessage(neighborInfo) - } - } - - // Default formatting for unknown types - switch v := payload.(type) { - case string: - return fmt.Sprintf(" Text: %s\n", v) - case []byte: - result := fmt.Sprintf(" Binary (%d bytes): %x\n", len(v), v) - if IsASCII(v) { - result += fmt.Sprintf(" As text: %s\n", string(v)) - } - return result - default: - return fmt.Sprintf(" Payload of type %T\n", payload) - } -} - -// FormatDecodedPacket formats a DecodedPacket into a human-readable string -func FormatDecodedPacket(packet *DecodedPacket) string { - var builder strings.Builder - - if packet == nil { - return "Error: nil packet" - } - - if packet.DecodeError != nil { - builder.WriteString(fmt.Sprintf("Error decoding packet: %v\n", packet.DecodeError)) - - // Show raw data in different formats for debugging - if packet.Payload != nil { - // If we have a payload but an error occurred during decoding - if data, ok := packet.Payload.([]byte); ok { - builder.WriteString(fmt.Sprintf("Raw payload (%d bytes):\n", len(data))) - builder.WriteString(fmt.Sprintf(" Hex: %x\n", data)) - - // Show as text if it might be displayable - if IsASCII(data) { - builder.WriteString(fmt.Sprintf(" Text: %s\n", string(data))) - } - } - } - - return builder.String() - } - - // Envelope info - builder.WriteString("Packet:\n") - builder.WriteString(fmt.Sprintf(" Channel ID: %s\n", packet.ChannelID)) - if packet.GatewayID != "" { - builder.WriteString(fmt.Sprintf(" Gateway ID: %s\n", packet.GatewayID)) - } - - // Mesh packet info - builder.WriteString(fmt.Sprintf(" ID: %d\n", packet.ID)) - builder.WriteString(fmt.Sprintf(" From: %d\n", packet.From)) - builder.WriteString(fmt.Sprintf(" To: %d\n", packet.To)) - - // Additional fields that might be interesting - builder.WriteString(fmt.Sprintf(" Port: %s\n", packet.PortNum)) - - if packet.HopLimit != 0 { - builder.WriteString(fmt.Sprintf(" Hop Limit: %d\n", packet.HopLimit)) - } - if packet.HopStart != 0 { - builder.WriteString(fmt.Sprintf(" Hop Start: %d\n", packet.HopStart)) - } - if packet.WantACK { - builder.WriteString(" Wants ACK: Yes\n") - } - if packet.ViaMQTT { - builder.WriteString(" Via MQTT: Yes\n") - } - if packet.NextHop != 0 { - builder.WriteString(fmt.Sprintf(" Next Hop: %d\n", packet.NextHop)) - } - if packet.RelayNode != 0 { - builder.WriteString(fmt.Sprintf(" Relay Node: %d\n", packet.RelayNode)) - } - - // Additional data fields - if packet.RequestID != 0 { - builder.WriteString(fmt.Sprintf(" Request ID: %d\n", packet.RequestID)) - } - if packet.ReplyID != 0 { - builder.WriteString(fmt.Sprintf(" Reply ID: %d\n", packet.ReplyID)) - } - if packet.Emoji != 0 { - builder.WriteString(fmt.Sprintf(" Emoji: %d\n", packet.Emoji)) - } - if packet.Dest != 0 { - builder.WriteString(fmt.Sprintf(" Destination Node: %d\n", packet.Dest)) - } - if packet.Source != 0 { - builder.WriteString(fmt.Sprintf(" Source Node: %d\n", packet.Source)) - } - if packet.WantResponse { - builder.WriteString(" Wants Response: Yes\n") - } - - // Format the payload - builder.WriteString("\n") - builder.WriteString(FormatPayload(packet.Payload, packet.PortNum)) - - return builder.String() -} - -// FormatServiceEnvelope formats a ServiceEnvelope message into a human-readable string -func FormatServiceEnvelope(envelope *pb.ServiceEnvelope) string { - var builder strings.Builder - - builder.WriteString("ServiceEnvelope:\n") - - // Print basic envelope info - builder.WriteString(fmt.Sprintf(" Channel ID: %s\n", envelope.GetChannelId())) - builder.WriteString(fmt.Sprintf(" Gateway ID: %s\n", envelope.GetGatewayId())) - - // Print MeshPacket info if available - if packet := envelope.GetPacket(); packet != nil { - builder.WriteString("\nMeshPacket:\n") - builder.WriteString(fmt.Sprintf(" ID: %d\n", packet.GetId())) - builder.WriteString(fmt.Sprintf(" From: %d\n", packet.GetFrom())) - builder.WriteString(fmt.Sprintf(" To: %d\n", packet.GetTo())) - - // Output routing and hop information - builder.WriteString(fmt.Sprintf(" Hop Limit: %d\n", packet.GetHopLimit())) - builder.WriteString(fmt.Sprintf(" Hop Start: %d\n", packet.GetHopStart())) - builder.WriteString(fmt.Sprintf(" Want ACK: %v\n", packet.GetWantAck())) - builder.WriteString(fmt.Sprintf(" Priority: %s\n", packet.GetPriority())) - - // Output if the packet was delivered via MQTT - if packet.GetViaMqtt() { - builder.WriteString(" Via MQTT: Yes\n") - } - - // Relay and next hop info - if packet.GetNextHop() != 0 { - builder.WriteString(fmt.Sprintf(" Next Hop: %d\n", packet.GetNextHop())) - } - if packet.GetRelayNode() != 0 { - builder.WriteString(fmt.Sprintf(" Relay Node: %d\n", packet.GetRelayNode())) - } - - // Show public key information if available (for PKI-encrypted packets) - if len(packet.GetPublicKey()) > 0 { - builder.WriteString(fmt.Sprintf(" Public Key: %x\n", packet.GetPublicKey())) - builder.WriteString(fmt.Sprintf(" PKI Encrypted: %v\n", packet.GetPkiEncrypted())) - } - - // Determine payload type - if packet.GetDecoded() != nil { - // For already decoded packets, use our specialized data formatter - builder.WriteString("\n") - builder.WriteString(FormatDataMessage(packet.GetDecoded())) - - } else if packet.GetEncrypted() != nil { - // Encrypted payload information - builder.WriteString("\n Encrypted Payload:\n") - builder.WriteString(fmt.Sprintf(" Size: %d bytes\n", len(packet.GetEncrypted()))) - builder.WriteString(fmt.Sprintf(" Channel: %d\n", packet.GetChannel())) - - // Print the first few bytes of the encrypted payload for identification - if len(packet.GetEncrypted()) > 0 { - displayLen := len(packet.GetEncrypted()) - if displayLen > 16 { - displayLen = 16 - } - builder.WriteString(fmt.Sprintf(" First %d bytes: %x\n", displayLen, packet.GetEncrypted()[:displayLen])) - } - - // If the packet has channel ID, it's using channel-based encryption - channelId := envelope.GetChannelId() - if channelId != "" { - builder.WriteString(fmt.Sprintf(" Encryption: Channel-based (Channel ID: %s)\n", channelId)) - - // Attempt to decrypt the payload using the channel key - channelKey := GetChannelKey(channelId) - builder.WriteString(fmt.Sprintf(" Using key (%d bytes): %x\n", len(channelKey), channelKey)) - - // Try to decrypt - decrypted, err := XOR(packet.GetEncrypted(), channelKey, packet.GetId(), packet.GetFrom()) - if err != nil { - builder.WriteString(fmt.Sprintf(" Decryption error: %v\n", err)) - } else { - builder.WriteString(fmt.Sprintf(" Decrypted (%d bytes): %x\n", len(decrypted), decrypted)) - - // Try to parse the decrypted payload as a Data message - var data pb.Data - if err := proto.Unmarshal(decrypted, &data); err == nil { - // Successfully decoded the decrypted payload into a Data message - // Use our specialized data formatter to show the message details - builder.WriteString("\n") - builder.WriteString(indent(FormatDataMessage(&data), " ")) - } else { - // If we couldn't parse as Data, try to interpret as text - if IsASCII(decrypted) { - builder.WriteString(fmt.Sprintf(" Decrypted as text: %s\n", string(decrypted))) - } else { - builder.WriteString(fmt.Sprintf(" Failed to parse decrypted data as pb.Data: %v\n", err)) - } - } - } - } - } - } - - - return builder.String() -} - -// indent adds indentation to each line of a string -func indent(s, prefix string) string { - lines := strings.Split(s, "\n") - for i, line := range lines { - if line != "" { - lines[i] = prefix + line - } - } - return strings.Join(lines, "\n") -} - -// FormatJSONMessage formats a JSON message into a human-readable string -func FormatJSONMessage(jsonData map[string]interface{}) string { - var builder strings.Builder - - builder.WriteString("JSON Message:\n") - - // Extract and display common fields - if from, ok := jsonData["from"].(string); ok { - builder.WriteString(fmt.Sprintf(" From: %s\n", from)) - } - if to, ok := jsonData["to"].(string); ok { - builder.WriteString(fmt.Sprintf(" To: %s\n", to)) - } - if message, ok := jsonData["payload"].(string); ok { - builder.WriteString(fmt.Sprintf(" Message: %s\n", message)) - } - if timestamp, ok := jsonData["timestamp"].(string); ok { - builder.WriteString(fmt.Sprintf(" Timestamp: %s\n", timestamp)) - } - - - return builder.String() -} - -// FormatTopicAndPacket formats both topic information and a decoded packet -func FormatTopicAndPacket(topicInfo *TopicInfo, decodedPacket *DecodedPacket) string { - var builder strings.Builder - - // Display topic information - builder.WriteString(fmt.Sprintf("Topic: %s\n", topicInfo.FullTopic)) - builder.WriteString(fmt.Sprintf("Region Path: %s\n", topicInfo.RegionPath)) - builder.WriteString(fmt.Sprintf("Version: %s\n", topicInfo.Version)) - builder.WriteString(fmt.Sprintf("Format: %s\n", topicInfo.Format)) - builder.WriteString(fmt.Sprintf("Channel: %s\n", topicInfo.Channel)) - if topicInfo.UserID != "" { - builder.WriteString(fmt.Sprintf("User ID: %s\n", topicInfo.UserID)) - } - builder.WriteString("\n") - - // Format the decoded packet - builder.WriteString(FormatDecodedPacket(decodedPacket)) - - return builder.String() -} - -// FormatTopicAndJSONData formats both topic information and decoded JSON data -func FormatTopicAndJSONData(topicInfo *TopicInfo, jsonData map[string]interface{}) string { - var builder strings.Builder - - // Display topic information - builder.WriteString(fmt.Sprintf("Topic: %s\n", topicInfo.FullTopic)) - builder.WriteString(fmt.Sprintf("Region Path: %s\n", topicInfo.RegionPath)) - builder.WriteString(fmt.Sprintf("Version: %s\n", topicInfo.Version)) - builder.WriteString(fmt.Sprintf("Format: %s\n", topicInfo.Format)) - builder.WriteString(fmt.Sprintf("Channel: %s\n", topicInfo.Channel)) - if topicInfo.UserID != "" { - builder.WriteString(fmt.Sprintf("User ID: %s\n", topicInfo.UserID)) - } - builder.WriteString("\n") - - // Format the JSON data - builder.WriteString(FormatJSONMessage(jsonData)) - - return builder.String() -} - -// FormatTopicAndRawData formats topic information and raw data for unsupported formats -func FormatTopicAndRawData(topicInfo *TopicInfo, payload []byte) string { - var builder strings.Builder - - // Display topic information - builder.WriteString(fmt.Sprintf("Topic: %s\n", topicInfo.FullTopic)) - builder.WriteString(fmt.Sprintf("Region Path: %s\n", topicInfo.RegionPath)) - builder.WriteString(fmt.Sprintf("Version: %s\n", topicInfo.Version)) - builder.WriteString(fmt.Sprintf("Format: %s\n", topicInfo.Format)) - builder.WriteString(fmt.Sprintf("Channel: %s\n", topicInfo.Channel)) - if topicInfo.UserID != "" { - builder.WriteString(fmt.Sprintf("User ID: %s\n", topicInfo.UserID)) - } - builder.WriteString("\n") - - // Display raw data - builder.WriteString(fmt.Sprintf("Unsupported format: %s\n", topicInfo.Format)) - builder.WriteString(fmt.Sprintf("Raw Data (%d bytes): %x\n", len(payload), payload)) - - return builder.String() -} \ No newline at end of file +// This file has been intentionally left empty. +// Removed formatter functions as they are no longer needed. +// We now use protobuf serialization via protojson for formatting. \ No newline at end of file diff --git a/generated/meshstream/meshstream.pb.go b/generated/meshstream/meshstream.pb.go new file mode 100644 index 0000000..99a3adb --- /dev/null +++ b/generated/meshstream/meshstream.pb.go @@ -0,0 +1,1016 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.36.6 +// protoc v5.29.3 +// source: meshstream/meshstream.proto + +package meshtreampb + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + meshtastic "meshstream/generated/meshtastic" + reflect "reflect" + sync "sync" + unsafe "unsafe" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// Packet represents a complete decoded MQTT message +type Packet struct { + state protoimpl.MessageState `protogen:"open.v1"` + Info *TopicInfo `protobuf:"bytes,2,opt,name=info,proto3" json:"info,omitempty"` + Data *Data `protobuf:"bytes,1,opt,name=data,proto3" json:"data,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Packet) Reset() { + *x = Packet{} + mi := &file_meshstream_meshstream_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Packet) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Packet) ProtoMessage() {} + +func (x *Packet) ProtoReflect() protoreflect.Message { + mi := &file_meshstream_meshstream_proto_msgTypes[0] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Packet.ProtoReflect.Descriptor instead. +func (*Packet) Descriptor() ([]byte, []int) { + return file_meshstream_meshstream_proto_rawDescGZIP(), []int{0} +} + +func (x *Packet) GetInfo() *TopicInfo { + if x != nil { + return x.Info + } + return nil +} + +func (x *Packet) GetData() *Data { + if x != nil { + return x.Data + } + return nil +} + +// TopicInfo contains parsed information about a Meshtastic MQTT topic +type TopicInfo struct { + state protoimpl.MessageState `protogen:"open.v1"` + FullTopic string `protobuf:"bytes,1,opt,name=full_topic,json=fullTopic,proto3" json:"full_topic,omitempty"` + RegionPath string `protobuf:"bytes,2,opt,name=region_path,json=regionPath,proto3" json:"region_path,omitempty"` + Version string `protobuf:"bytes,3,opt,name=version,proto3" json:"version,omitempty"` + Format string `protobuf:"bytes,4,opt,name=format,proto3" json:"format,omitempty"` + Channel string `protobuf:"bytes,5,opt,name=channel,proto3" json:"channel,omitempty"` + UserId string `protobuf:"bytes,6,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *TopicInfo) Reset() { + *x = TopicInfo{} + mi := &file_meshstream_meshstream_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *TopicInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopicInfo) ProtoMessage() {} + +func (x *TopicInfo) ProtoReflect() protoreflect.Message { + mi := &file_meshstream_meshstream_proto_msgTypes[1] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopicInfo.ProtoReflect.Descriptor instead. +func (*TopicInfo) Descriptor() ([]byte, []int) { + return file_meshstream_meshstream_proto_rawDescGZIP(), []int{1} +} + +func (x *TopicInfo) GetFullTopic() string { + if x != nil { + return x.FullTopic + } + return "" +} + +func (x *TopicInfo) GetRegionPath() string { + if x != nil { + return x.RegionPath + } + return "" +} + +func (x *TopicInfo) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *TopicInfo) GetFormat() string { + if x != nil { + return x.Format + } + return "" +} + +func (x *TopicInfo) GetChannel() string { + if x != nil { + return x.Channel + } + return "" +} + +func (x *TopicInfo) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +// Data provides a flattened structure for decoded Meshtastic packets +type Data struct { + state protoimpl.MessageState `protogen:"open.v1"` + // From Service Envelope + ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"` + GatewayId string `protobuf:"bytes,2,opt,name=gateway_id,json=gatewayId,proto3" json:"gateway_id,omitempty"` + // From Mesh Packet + Id uint32 `protobuf:"varint,3,opt,name=id,proto3" json:"id,omitempty"` + From uint32 `protobuf:"varint,4,opt,name=from,proto3" json:"from,omitempty"` + To uint32 `protobuf:"varint,5,opt,name=to,proto3" json:"to,omitempty"` + HopLimit uint32 `protobuf:"varint,6,opt,name=hop_limit,json=hopLimit,proto3" json:"hop_limit,omitempty"` + HopStart uint32 `protobuf:"varint,7,opt,name=hop_start,json=hopStart,proto3" json:"hop_start,omitempty"` + WantAck bool `protobuf:"varint,8,opt,name=want_ack,json=wantAck,proto3" json:"want_ack,omitempty"` + Priority string `protobuf:"bytes,9,opt,name=priority,proto3" json:"priority,omitempty"` + ViaMqtt bool `protobuf:"varint,10,opt,name=via_mqtt,json=viaMqtt,proto3" json:"via_mqtt,omitempty"` + NextHop uint32 `protobuf:"varint,11,opt,name=next_hop,json=nextHop,proto3" json:"next_hop,omitempty"` + RelayNode uint32 `protobuf:"varint,12,opt,name=relay_node,json=relayNode,proto3" json:"relay_node,omitempty"` + // From Data + PortNum meshtastic.PortNum `protobuf:"varint,13,opt,name=port_num,json=portNum,proto3,enum=meshtastic.PortNum" json:"port_num,omitempty"` + // Payload is one of these types, depending on port_num + // + // Types that are valid to be assigned to Payload: + // + // *Data_TextMessage + // *Data_BinaryData + // *Data_Position + // *Data_NodeInfo + // *Data_Telemetry + // *Data_Waypoint + // *Data_RouteDiscovery + // *Data_NeighborInfo + // *Data_CompressedText + // *Data_MapReport + // *Data_RemoteHardware + // *Data_Routing + // *Data_Admin + // *Data_AudioData + // *Data_Alert + // *Data_Reply + // *Data_IpTunnel + // *Data_Paxcounter + // *Data_SerialApp + // *Data_StoreForward + // *Data_RangeTest + // *Data_ZpsApp + // *Data_Simulator + // *Data_AtakPlugin + // *Data_Powerstress + // *Data_ReticulumTunnel + // *Data_PrivateApp + // *Data_DetectionSensor + Payload isData_Payload `protobuf_oneof:"payload"` + // Additional Data fields + RequestId uint32 `protobuf:"varint,50,opt,name=request_id,json=requestId,proto3" json:"request_id,omitempty"` + ReplyId uint32 `protobuf:"varint,51,opt,name=reply_id,json=replyId,proto3" json:"reply_id,omitempty"` + Emoji uint32 `protobuf:"varint,52,opt,name=emoji,proto3" json:"emoji,omitempty"` + Dest uint32 `protobuf:"varint,53,opt,name=dest,proto3" json:"dest,omitempty"` + Source uint32 `protobuf:"varint,54,opt,name=source,proto3" json:"source,omitempty"` + WantResponse bool `protobuf:"varint,55,opt,name=want_response,json=wantResponse,proto3" json:"want_response,omitempty"` + // Error tracking + DecodeError string `protobuf:"bytes,60,opt,name=decode_error,json=decodeError,proto3" json:"decode_error,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *Data) Reset() { + *x = Data{} + mi := &file_meshstream_meshstream_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *Data) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Data) ProtoMessage() {} + +func (x *Data) ProtoReflect() protoreflect.Message { + mi := &file_meshstream_meshstream_proto_msgTypes[2] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Data.ProtoReflect.Descriptor instead. +func (*Data) Descriptor() ([]byte, []int) { + return file_meshstream_meshstream_proto_rawDescGZIP(), []int{2} +} + +func (x *Data) GetChannelId() string { + if x != nil { + return x.ChannelId + } + return "" +} + +func (x *Data) GetGatewayId() string { + if x != nil { + return x.GatewayId + } + return "" +} + +func (x *Data) GetId() uint32 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Data) GetFrom() uint32 { + if x != nil { + return x.From + } + return 0 +} + +func (x *Data) GetTo() uint32 { + if x != nil { + return x.To + } + return 0 +} + +func (x *Data) GetHopLimit() uint32 { + if x != nil { + return x.HopLimit + } + return 0 +} + +func (x *Data) GetHopStart() uint32 { + if x != nil { + return x.HopStart + } + return 0 +} + +func (x *Data) GetWantAck() bool { + if x != nil { + return x.WantAck + } + return false +} + +func (x *Data) GetPriority() string { + if x != nil { + return x.Priority + } + return "" +} + +func (x *Data) GetViaMqtt() bool { + if x != nil { + return x.ViaMqtt + } + return false +} + +func (x *Data) GetNextHop() uint32 { + if x != nil { + return x.NextHop + } + return 0 +} + +func (x *Data) GetRelayNode() uint32 { + if x != nil { + return x.RelayNode + } + return 0 +} + +func (x *Data) GetPortNum() meshtastic.PortNum { + if x != nil { + return x.PortNum + } + return meshtastic.PortNum(0) +} + +func (x *Data) GetPayload() isData_Payload { + if x != nil { + return x.Payload + } + return nil +} + +func (x *Data) GetTextMessage() string { + if x != nil { + if x, ok := x.Payload.(*Data_TextMessage); ok { + return x.TextMessage + } + } + return "" +} + +func (x *Data) GetBinaryData() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_BinaryData); ok { + return x.BinaryData + } + } + return nil +} + +func (x *Data) GetPosition() *meshtastic.Position { + if x != nil { + if x, ok := x.Payload.(*Data_Position); ok { + return x.Position + } + } + return nil +} + +func (x *Data) GetNodeInfo() *meshtastic.User { + if x != nil { + if x, ok := x.Payload.(*Data_NodeInfo); ok { + return x.NodeInfo + } + } + return nil +} + +func (x *Data) GetTelemetry() *meshtastic.Telemetry { + if x != nil { + if x, ok := x.Payload.(*Data_Telemetry); ok { + return x.Telemetry + } + } + return nil +} + +func (x *Data) GetWaypoint() *meshtastic.Waypoint { + if x != nil { + if x, ok := x.Payload.(*Data_Waypoint); ok { + return x.Waypoint + } + } + return nil +} + +func (x *Data) GetRouteDiscovery() *meshtastic.RouteDiscovery { + if x != nil { + if x, ok := x.Payload.(*Data_RouteDiscovery); ok { + return x.RouteDiscovery + } + } + return nil +} + +func (x *Data) GetNeighborInfo() *meshtastic.NeighborInfo { + if x != nil { + if x, ok := x.Payload.(*Data_NeighborInfo); ok { + return x.NeighborInfo + } + } + return nil +} + +func (x *Data) GetCompressedText() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_CompressedText); ok { + return x.CompressedText + } + } + return nil +} + +func (x *Data) GetMapReport() *meshtastic.MapReport { + if x != nil { + if x, ok := x.Payload.(*Data_MapReport); ok { + return x.MapReport + } + } + return nil +} + +func (x *Data) GetRemoteHardware() *meshtastic.HardwareMessage { + if x != nil { + if x, ok := x.Payload.(*Data_RemoteHardware); ok { + return x.RemoteHardware + } + } + return nil +} + +func (x *Data) GetRouting() *meshtastic.Routing { + if x != nil { + if x, ok := x.Payload.(*Data_Routing); ok { + return x.Routing + } + } + return nil +} + +func (x *Data) GetAdmin() *meshtastic.AdminMessage { + if x != nil { + if x, ok := x.Payload.(*Data_Admin); ok { + return x.Admin + } + } + return nil +} + +func (x *Data) GetAudioData() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_AudioData); ok { + return x.AudioData + } + } + return nil +} + +func (x *Data) GetAlert() string { + if x != nil { + if x, ok := x.Payload.(*Data_Alert); ok { + return x.Alert + } + } + return "" +} + +func (x *Data) GetReply() string { + if x != nil { + if x, ok := x.Payload.(*Data_Reply); ok { + return x.Reply + } + } + return "" +} + +func (x *Data) GetIpTunnel() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_IpTunnel); ok { + return x.IpTunnel + } + } + return nil +} + +func (x *Data) GetPaxcounter() *meshtastic.Paxcount { + if x != nil { + if x, ok := x.Payload.(*Data_Paxcounter); ok { + return x.Paxcounter + } + } + return nil +} + +func (x *Data) GetSerialApp() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_SerialApp); ok { + return x.SerialApp + } + } + return nil +} + +func (x *Data) GetStoreForward() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_StoreForward); ok { + return x.StoreForward + } + } + return nil +} + +func (x *Data) GetRangeTest() string { + if x != nil { + if x, ok := x.Payload.(*Data_RangeTest); ok { + return x.RangeTest + } + } + return "" +} + +func (x *Data) GetZpsApp() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_ZpsApp); ok { + return x.ZpsApp + } + } + return nil +} + +func (x *Data) GetSimulator() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_Simulator); ok { + return x.Simulator + } + } + return nil +} + +func (x *Data) GetAtakPlugin() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_AtakPlugin); ok { + return x.AtakPlugin + } + } + return nil +} + +func (x *Data) GetPowerstress() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_Powerstress); ok { + return x.Powerstress + } + } + return nil +} + +func (x *Data) GetReticulumTunnel() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_ReticulumTunnel); ok { + return x.ReticulumTunnel + } + } + return nil +} + +func (x *Data) GetPrivateApp() []byte { + if x != nil { + if x, ok := x.Payload.(*Data_PrivateApp); ok { + return x.PrivateApp + } + } + return nil +} + +func (x *Data) GetDetectionSensor() string { + if x != nil { + if x, ok := x.Payload.(*Data_DetectionSensor); ok { + return x.DetectionSensor + } + } + return "" +} + +func (x *Data) GetRequestId() uint32 { + if x != nil { + return x.RequestId + } + return 0 +} + +func (x *Data) GetReplyId() uint32 { + if x != nil { + return x.ReplyId + } + return 0 +} + +func (x *Data) GetEmoji() uint32 { + if x != nil { + return x.Emoji + } + return 0 +} + +func (x *Data) GetDest() uint32 { + if x != nil { + return x.Dest + } + return 0 +} + +func (x *Data) GetSource() uint32 { + if x != nil { + return x.Source + } + return 0 +} + +func (x *Data) GetWantResponse() bool { + if x != nil { + return x.WantResponse + } + return false +} + +func (x *Data) GetDecodeError() string { + if x != nil { + return x.DecodeError + } + return "" +} + +type isData_Payload interface { + isData_Payload() +} + +type Data_TextMessage struct { + TextMessage string `protobuf:"bytes,14,opt,name=text_message,json=textMessage,proto3,oneof"` // TEXT_MESSAGE_APP +} + +type Data_BinaryData struct { + BinaryData []byte `protobuf:"bytes,15,opt,name=binary_data,json=binaryData,proto3,oneof"` // Generic binary data for other port types +} + +type Data_Position struct { + Position *meshtastic.Position `protobuf:"bytes,16,opt,name=position,proto3,oneof"` // POSITION_APP +} + +type Data_NodeInfo struct { + NodeInfo *meshtastic.User `protobuf:"bytes,17,opt,name=node_info,json=nodeInfo,proto3,oneof"` // NODEINFO_APP +} + +type Data_Telemetry struct { + Telemetry *meshtastic.Telemetry `protobuf:"bytes,18,opt,name=telemetry,proto3,oneof"` // TELEMETRY_APP +} + +type Data_Waypoint struct { + Waypoint *meshtastic.Waypoint `protobuf:"bytes,19,opt,name=waypoint,proto3,oneof"` // WAYPOINT_APP +} + +type Data_RouteDiscovery struct { + RouteDiscovery *meshtastic.RouteDiscovery `protobuf:"bytes,20,opt,name=route_discovery,json=routeDiscovery,proto3,oneof"` // TRACEROUTE_APP +} + +type Data_NeighborInfo struct { + NeighborInfo *meshtastic.NeighborInfo `protobuf:"bytes,21,opt,name=neighbor_info,json=neighborInfo,proto3,oneof"` // NEIGHBORINFO_APP +} + +type Data_CompressedText struct { + CompressedText []byte `protobuf:"bytes,22,opt,name=compressed_text,json=compressedText,proto3,oneof"` // TEXT_MESSAGE_COMPRESSED_APP +} + +type Data_MapReport struct { + MapReport *meshtastic.MapReport `protobuf:"bytes,23,opt,name=map_report,json=mapReport,proto3,oneof"` // MAP_REPORT_APP +} + +type Data_RemoteHardware struct { + RemoteHardware *meshtastic.HardwareMessage `protobuf:"bytes,24,opt,name=remote_hardware,json=remoteHardware,proto3,oneof"` // REMOTE_HARDWARE_APP +} + +type Data_Routing struct { + Routing *meshtastic.Routing `protobuf:"bytes,25,opt,name=routing,proto3,oneof"` // ROUTING_APP +} + +type Data_Admin struct { + Admin *meshtastic.AdminMessage `protobuf:"bytes,26,opt,name=admin,proto3,oneof"` // ADMIN_APP +} + +type Data_AudioData struct { + AudioData []byte `protobuf:"bytes,27,opt,name=audio_data,json=audioData,proto3,oneof"` // AUDIO_APP +} + +type Data_Alert struct { + Alert string `protobuf:"bytes,28,opt,name=alert,proto3,oneof"` // ALERT_APP +} + +type Data_Reply struct { + Reply string `protobuf:"bytes,29,opt,name=reply,proto3,oneof"` // REPLY_APP +} + +type Data_IpTunnel struct { + IpTunnel []byte `protobuf:"bytes,30,opt,name=ip_tunnel,json=ipTunnel,proto3,oneof"` // IP_TUNNEL_APP +} + +type Data_Paxcounter struct { + Paxcounter *meshtastic.Paxcount `protobuf:"bytes,31,opt,name=paxcounter,proto3,oneof"` // PAXCOUNTER_APP +} + +type Data_SerialApp struct { + SerialApp []byte `protobuf:"bytes,32,opt,name=serial_app,json=serialApp,proto3,oneof"` // SERIAL_APP +} + +type Data_StoreForward struct { + StoreForward []byte `protobuf:"bytes,33,opt,name=store_forward,json=storeForward,proto3,oneof"` // STORE_FORWARD_APP +} + +type Data_RangeTest struct { + RangeTest string `protobuf:"bytes,34,opt,name=range_test,json=rangeTest,proto3,oneof"` // RANGE_TEST_APP +} + +type Data_ZpsApp struct { + ZpsApp []byte `protobuf:"bytes,35,opt,name=zps_app,json=zpsApp,proto3,oneof"` // ZPS_APP +} + +type Data_Simulator struct { + Simulator []byte `protobuf:"bytes,36,opt,name=simulator,proto3,oneof"` // SIMULATOR_APP +} + +type Data_AtakPlugin struct { + AtakPlugin []byte `protobuf:"bytes,37,opt,name=atak_plugin,json=atakPlugin,proto3,oneof"` // ATAK_PLUGIN +} + +type Data_Powerstress struct { + Powerstress []byte `protobuf:"bytes,38,opt,name=powerstress,proto3,oneof"` // POWERSTRESS_APP +} + +type Data_ReticulumTunnel struct { + ReticulumTunnel []byte `protobuf:"bytes,39,opt,name=reticulum_tunnel,json=reticulumTunnel,proto3,oneof"` // RETICULUM_TUNNEL_APP +} + +type Data_PrivateApp struct { + PrivateApp []byte `protobuf:"bytes,40,opt,name=private_app,json=privateApp,proto3,oneof"` // PRIVATE_APP, ATAK_FORWARDER +} + +type Data_DetectionSensor struct { + DetectionSensor string `protobuf:"bytes,41,opt,name=detection_sensor,json=detectionSensor,proto3,oneof"` // DETECTION_SENSOR_APP +} + +func (*Data_TextMessage) isData_Payload() {} + +func (*Data_BinaryData) isData_Payload() {} + +func (*Data_Position) isData_Payload() {} + +func (*Data_NodeInfo) isData_Payload() {} + +func (*Data_Telemetry) isData_Payload() {} + +func (*Data_Waypoint) isData_Payload() {} + +func (*Data_RouteDiscovery) isData_Payload() {} + +func (*Data_NeighborInfo) isData_Payload() {} + +func (*Data_CompressedText) isData_Payload() {} + +func (*Data_MapReport) isData_Payload() {} + +func (*Data_RemoteHardware) isData_Payload() {} + +func (*Data_Routing) isData_Payload() {} + +func (*Data_Admin) isData_Payload() {} + +func (*Data_AudioData) isData_Payload() {} + +func (*Data_Alert) isData_Payload() {} + +func (*Data_Reply) isData_Payload() {} + +func (*Data_IpTunnel) isData_Payload() {} + +func (*Data_Paxcounter) isData_Payload() {} + +func (*Data_SerialApp) isData_Payload() {} + +func (*Data_StoreForward) isData_Payload() {} + +func (*Data_RangeTest) isData_Payload() {} + +func (*Data_ZpsApp) isData_Payload() {} + +func (*Data_Simulator) isData_Payload() {} + +func (*Data_AtakPlugin) isData_Payload() {} + +func (*Data_Powerstress) isData_Payload() {} + +func (*Data_ReticulumTunnel) isData_Payload() {} + +func (*Data_PrivateApp) isData_Payload() {} + +func (*Data_DetectionSensor) isData_Payload() {} + +var File_meshstream_meshstream_proto protoreflect.FileDescriptor + +const file_meshstream_meshstream_proto_rawDesc = "" + + "\n" + + "\x1bmeshstream/meshstream.proto\x12\n" + + "meshstream\x1a\x15meshtastic/mesh.proto\x1a\x19meshtastic/portnums.proto\x1a\x1ameshtastic/telemetry.proto\x1a\x15meshtastic/mqtt.proto\x1a meshtastic/remote_hardware.proto\x1a\x16meshtastic/admin.proto\x1a\x19meshtastic/paxcount.proto\"Y\n" + + "\x06Packet\x12)\n" + + "\x04info\x18\x02 \x01(\v2\x15.meshstream.TopicInfoR\x04info\x12$\n" + + "\x04data\x18\x01 \x01(\v2\x10.meshstream.DataR\x04data\"\xb0\x01\n" + + "\tTopicInfo\x12\x1d\n" + + "\n" + + "full_topic\x18\x01 \x01(\tR\tfullTopic\x12\x1f\n" + + "\vregion_path\x18\x02 \x01(\tR\n" + + "regionPath\x12\x18\n" + + "\aversion\x18\x03 \x01(\tR\aversion\x12\x16\n" + + "\x06format\x18\x04 \x01(\tR\x06format\x12\x18\n" + + "\achannel\x18\x05 \x01(\tR\achannel\x12\x17\n" + + "\auser_id\x18\x06 \x01(\tR\x06userId\"\xfb\r\n" + + "\x04Data\x12\x1d\n" + + "\n" + + "channel_id\x18\x01 \x01(\tR\tchannelId\x12\x1d\n" + + "\n" + + "gateway_id\x18\x02 \x01(\tR\tgatewayId\x12\x0e\n" + + "\x02id\x18\x03 \x01(\rR\x02id\x12\x12\n" + + "\x04from\x18\x04 \x01(\rR\x04from\x12\x0e\n" + + "\x02to\x18\x05 \x01(\rR\x02to\x12\x1b\n" + + "\thop_limit\x18\x06 \x01(\rR\bhopLimit\x12\x1b\n" + + "\thop_start\x18\a \x01(\rR\bhopStart\x12\x19\n" + + "\bwant_ack\x18\b \x01(\bR\awantAck\x12\x1a\n" + + "\bpriority\x18\t \x01(\tR\bpriority\x12\x19\n" + + "\bvia_mqtt\x18\n" + + " \x01(\bR\aviaMqtt\x12\x19\n" + + "\bnext_hop\x18\v \x01(\rR\anextHop\x12\x1d\n" + + "\n" + + "relay_node\x18\f \x01(\rR\trelayNode\x12.\n" + + "\bport_num\x18\r \x01(\x0e2\x13.meshtastic.PortNumR\aportNum\x12#\n" + + "\ftext_message\x18\x0e \x01(\tH\x00R\vtextMessage\x12!\n" + + "\vbinary_data\x18\x0f \x01(\fH\x00R\n" + + "binaryData\x122\n" + + "\bposition\x18\x10 \x01(\v2\x14.meshtastic.PositionH\x00R\bposition\x12/\n" + + "\tnode_info\x18\x11 \x01(\v2\x10.meshtastic.UserH\x00R\bnodeInfo\x125\n" + + "\ttelemetry\x18\x12 \x01(\v2\x15.meshtastic.TelemetryH\x00R\ttelemetry\x122\n" + + "\bwaypoint\x18\x13 \x01(\v2\x14.meshtastic.WaypointH\x00R\bwaypoint\x12E\n" + + "\x0froute_discovery\x18\x14 \x01(\v2\x1a.meshtastic.RouteDiscoveryH\x00R\x0erouteDiscovery\x12?\n" + + "\rneighbor_info\x18\x15 \x01(\v2\x18.meshtastic.NeighborInfoH\x00R\fneighborInfo\x12)\n" + + "\x0fcompressed_text\x18\x16 \x01(\fH\x00R\x0ecompressedText\x126\n" + + "\n" + + "map_report\x18\x17 \x01(\v2\x15.meshtastic.MapReportH\x00R\tmapReport\x12F\n" + + "\x0fremote_hardware\x18\x18 \x01(\v2\x1b.meshtastic.HardwareMessageH\x00R\x0eremoteHardware\x12/\n" + + "\arouting\x18\x19 \x01(\v2\x13.meshtastic.RoutingH\x00R\arouting\x120\n" + + "\x05admin\x18\x1a \x01(\v2\x18.meshtastic.AdminMessageH\x00R\x05admin\x12\x1f\n" + + "\n" + + "audio_data\x18\x1b \x01(\fH\x00R\taudioData\x12\x16\n" + + "\x05alert\x18\x1c \x01(\tH\x00R\x05alert\x12\x16\n" + + "\x05reply\x18\x1d \x01(\tH\x00R\x05reply\x12\x1d\n" + + "\tip_tunnel\x18\x1e \x01(\fH\x00R\bipTunnel\x126\n" + + "\n" + + "paxcounter\x18\x1f \x01(\v2\x14.meshtastic.PaxcountH\x00R\n" + + "paxcounter\x12\x1f\n" + + "\n" + + "serial_app\x18 \x01(\fH\x00R\tserialApp\x12%\n" + + "\rstore_forward\x18! \x01(\fH\x00R\fstoreForward\x12\x1f\n" + + "\n" + + "range_test\x18\" \x01(\tH\x00R\trangeTest\x12\x19\n" + + "\azps_app\x18# \x01(\fH\x00R\x06zpsApp\x12\x1e\n" + + "\tsimulator\x18$ \x01(\fH\x00R\tsimulator\x12!\n" + + "\vatak_plugin\x18% \x01(\fH\x00R\n" + + "atakPlugin\x12\"\n" + + "\vpowerstress\x18& \x01(\fH\x00R\vpowerstress\x12+\n" + + "\x10reticulum_tunnel\x18' \x01(\fH\x00R\x0freticulumTunnel\x12!\n" + + "\vprivate_app\x18( \x01(\fH\x00R\n" + + "privateApp\x12+\n" + + "\x10detection_sensor\x18) \x01(\tH\x00R\x0fdetectionSensor\x12\x1d\n" + + "\n" + + "request_id\x182 \x01(\rR\trequestId\x12\x19\n" + + "\breply_id\x183 \x01(\rR\areplyId\x12\x14\n" + + "\x05emoji\x184 \x01(\rR\x05emoji\x12\x12\n" + + "\x04dest\x185 \x01(\rR\x04dest\x12\x16\n" + + "\x06source\x186 \x01(\rR\x06source\x12#\n" + + "\rwant_response\x187 \x01(\bR\fwantResponse\x12!\n" + + "\fdecode_error\x18< \x01(\tR\vdecodeErrorB\t\n" + + "\apayloadB(Z&proto/generated/meshstream;meshtreampbb\x06proto3" + +var ( + file_meshstream_meshstream_proto_rawDescOnce sync.Once + file_meshstream_meshstream_proto_rawDescData []byte +) + +func file_meshstream_meshstream_proto_rawDescGZIP() []byte { + file_meshstream_meshstream_proto_rawDescOnce.Do(func() { + file_meshstream_meshstream_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_meshstream_meshstream_proto_rawDesc), len(file_meshstream_meshstream_proto_rawDesc))) + }) + return file_meshstream_meshstream_proto_rawDescData +} + +var file_meshstream_meshstream_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_meshstream_meshstream_proto_goTypes = []any{ + (*Packet)(nil), // 0: meshstream.Packet + (*TopicInfo)(nil), // 1: meshstream.TopicInfo + (*Data)(nil), // 2: meshstream.Data + (meshtastic.PortNum)(0), // 3: meshtastic.PortNum + (*meshtastic.Position)(nil), // 4: meshtastic.Position + (*meshtastic.User)(nil), // 5: meshtastic.User + (*meshtastic.Telemetry)(nil), // 6: meshtastic.Telemetry + (*meshtastic.Waypoint)(nil), // 7: meshtastic.Waypoint + (*meshtastic.RouteDiscovery)(nil), // 8: meshtastic.RouteDiscovery + (*meshtastic.NeighborInfo)(nil), // 9: meshtastic.NeighborInfo + (*meshtastic.MapReport)(nil), // 10: meshtastic.MapReport + (*meshtastic.HardwareMessage)(nil), // 11: meshtastic.HardwareMessage + (*meshtastic.Routing)(nil), // 12: meshtastic.Routing + (*meshtastic.AdminMessage)(nil), // 13: meshtastic.AdminMessage + (*meshtastic.Paxcount)(nil), // 14: meshtastic.Paxcount +} +var file_meshstream_meshstream_proto_depIdxs = []int32{ + 1, // 0: meshstream.Packet.info:type_name -> meshstream.TopicInfo + 2, // 1: meshstream.Packet.data:type_name -> meshstream.Data + 3, // 2: meshstream.Data.port_num:type_name -> meshtastic.PortNum + 4, // 3: meshstream.Data.position:type_name -> meshtastic.Position + 5, // 4: meshstream.Data.node_info:type_name -> meshtastic.User + 6, // 5: meshstream.Data.telemetry:type_name -> meshtastic.Telemetry + 7, // 6: meshstream.Data.waypoint:type_name -> meshtastic.Waypoint + 8, // 7: meshstream.Data.route_discovery:type_name -> meshtastic.RouteDiscovery + 9, // 8: meshstream.Data.neighbor_info:type_name -> meshtastic.NeighborInfo + 10, // 9: meshstream.Data.map_report:type_name -> meshtastic.MapReport + 11, // 10: meshstream.Data.remote_hardware:type_name -> meshtastic.HardwareMessage + 12, // 11: meshstream.Data.routing:type_name -> meshtastic.Routing + 13, // 12: meshstream.Data.admin:type_name -> meshtastic.AdminMessage + 14, // 13: meshstream.Data.paxcounter:type_name -> meshtastic.Paxcount + 14, // [14:14] is the sub-list for method output_type + 14, // [14:14] is the sub-list for method input_type + 14, // [14:14] is the sub-list for extension type_name + 14, // [14:14] is the sub-list for extension extendee + 0, // [0:14] is the sub-list for field type_name +} + +func init() { file_meshstream_meshstream_proto_init() } +func file_meshstream_meshstream_proto_init() { + if File_meshstream_meshstream_proto != nil { + return + } + file_meshstream_meshstream_proto_msgTypes[2].OneofWrappers = []any{ + (*Data_TextMessage)(nil), + (*Data_BinaryData)(nil), + (*Data_Position)(nil), + (*Data_NodeInfo)(nil), + (*Data_Telemetry)(nil), + (*Data_Waypoint)(nil), + (*Data_RouteDiscovery)(nil), + (*Data_NeighborInfo)(nil), + (*Data_CompressedText)(nil), + (*Data_MapReport)(nil), + (*Data_RemoteHardware)(nil), + (*Data_Routing)(nil), + (*Data_Admin)(nil), + (*Data_AudioData)(nil), + (*Data_Alert)(nil), + (*Data_Reply)(nil), + (*Data_IpTunnel)(nil), + (*Data_Paxcounter)(nil), + (*Data_SerialApp)(nil), + (*Data_StoreForward)(nil), + (*Data_RangeTest)(nil), + (*Data_ZpsApp)(nil), + (*Data_Simulator)(nil), + (*Data_AtakPlugin)(nil), + (*Data_Powerstress)(nil), + (*Data_ReticulumTunnel)(nil), + (*Data_PrivateApp)(nil), + (*Data_DetectionSensor)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: unsafe.Slice(unsafe.StringData(file_meshstream_meshstream_proto_rawDesc), len(file_meshstream_meshstream_proto_rawDesc)), + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_meshstream_meshstream_proto_goTypes, + DependencyIndexes: file_meshstream_meshstream_proto_depIdxs, + MessageInfos: file_meshstream_meshstream_proto_msgTypes, + }.Build() + File_meshstream_meshstream_proto = out.File + file_meshstream_meshstream_proto_goTypes = nil + file_meshstream_meshstream_proto_depIdxs = nil +} diff --git a/proto/generated/meshtastic/admin.pb.go b/generated/meshtastic/admin.pb.go similarity index 99% rename from proto/generated/meshtastic/admin.pb.go rename to generated/meshtastic/admin.pb.go index 2930c37..f322f00 100644 --- a/proto/generated/meshtastic/admin.pb.go +++ b/generated/meshtastic/admin.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/admin.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -1408,8 +1408,8 @@ const file_meshtastic_admin_proto_rawDesc = "" + "\n" + "short_name\x18\x04 \x01(\tR\tshortName\"~\n" + "\x1eNodeRemoteHardwarePinsResponse\x12\\\n" + - "\x19node_remote_hardware_pins\x18\x01 \x03(\v2!.meshtastic.NodeRemoteHardwarePinR\x16nodeRemoteHardwarePinsB`\n" + - "\x13com.geeksville.meshB\vAdminProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\x19node_remote_hardware_pins\x18\x01 \x03(\v2!.meshtastic.NodeRemoteHardwarePinR\x16nodeRemoteHardwarePinsB]\n" + + "\x13com.geeksville.meshB\vAdminProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_admin_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/apponly.pb.go b/generated/meshtastic/apponly.pb.go similarity index 96% rename from proto/generated/meshtastic/apponly.pb.go rename to generated/meshtastic/apponly.pb.go index 88979b0..27c8497 100644 --- a/proto/generated/meshtastic/apponly.pb.go +++ b/generated/meshtastic/apponly.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/apponly.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -90,8 +90,8 @@ const file_meshtastic_apponly_proto_rawDesc = "" + "ChannelSet\x127\n" + "\bsettings\x18\x01 \x03(\v2\x1b.meshtastic.ChannelSettingsR\bsettings\x12>\n" + "\vlora_config\x18\x02 \x01(\v2\x1d.meshtastic.Config.LoRaConfigR\n" + - "loraConfigBb\n" + - "\x13com.geeksville.meshB\rAppOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "loraConfigB_\n" + + "\x13com.geeksville.meshB\rAppOnlyProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_apponly_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/atak.pb.go b/generated/meshtastic/atak.pb.go similarity index 99% rename from proto/generated/meshtastic/atak.pb.go rename to generated/meshtastic/atak.pb.go index fe14c35..181f995 100644 --- a/proto/generated/meshtastic/atak.pb.go +++ b/generated/meshtastic/atak.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/atak.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -720,9 +720,9 @@ const file_meshtastic_atak_proto_rawDesc = "" + "\x05Medic\x10\x05\x12\x13\n" + "\x0fForwardObserver\x10\x06\x12\a\n" + "\x03RTO\x10\a\x12\x06\n" + - "\x02K9\x10\bB_\n" + + "\x02K9\x10\bB\\\n" + "\x13com.geeksville.meshB\n" + - "ATAKProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "ATAKProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_atak_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/cannedmessages.pb.go b/generated/meshtastic/cannedmessages.pb.go similarity index 95% rename from proto/generated/meshtastic/cannedmessages.pb.go rename to generated/meshtastic/cannedmessages.pb.go index c40f0ba..d72a607 100644 --- a/proto/generated/meshtastic/cannedmessages.pb.go +++ b/generated/meshtastic/cannedmessages.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/cannedmessages.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -74,8 +74,8 @@ const file_meshtastic_cannedmessages_proto_rawDesc = "" + "\x1fmeshtastic/cannedmessages.proto\x12\n" + "meshtastic\"7\n" + "\x19CannedMessageModuleConfig\x12\x1a\n" + - "\bmessages\x18\x01 \x01(\tR\bmessagesBn\n" + - "\x13com.geeksville.meshB\x19CannedMessageConfigProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\bmessages\x18\x01 \x01(\tR\bmessagesBk\n" + + "\x13com.geeksville.meshB\x19CannedMessageConfigProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_cannedmessages_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/channel.pb.go b/generated/meshtastic/channel.pb.go similarity index 98% rename from proto/generated/meshtastic/channel.pb.go rename to generated/meshtastic/channel.pb.go index 6a611bb..8867bac 100644 --- a/proto/generated/meshtastic/channel.pb.go +++ b/generated/meshtastic/channel.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/channel.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -373,8 +373,8 @@ const file_meshtastic_channel_proto_rawDesc = "" + "\x04Role\x12\f\n" + "\bDISABLED\x10\x00\x12\v\n" + "\aPRIMARY\x10\x01\x12\r\n" + - "\tSECONDARY\x10\x02Bb\n" + - "\x13com.geeksville.meshB\rChannelProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\tSECONDARY\x10\x02B_\n" + + "\x13com.geeksville.meshB\rChannelProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_channel_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/clientonly.pb.go b/generated/meshtastic/clientonly.pb.go similarity index 97% rename from proto/generated/meshtastic/clientonly.pb.go rename to generated/meshtastic/clientonly.pb.go index 2a4d429..d19a6f5 100644 --- a/proto/generated/meshtastic/clientonly.pb.go +++ b/generated/meshtastic/clientonly.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/clientonly.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -156,8 +156,8 @@ const file_meshtastic_clientonly_proto_rawDesc = "" + "\x0e_module_configB\x11\n" + "\x0f_fixed_positionB\v\n" + "\t_ringtoneB\x12\n" + - "\x10_canned_messagesBe\n" + - "\x13com.geeksville.meshB\x10ClientOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\x10_canned_messagesBb\n" + + "\x13com.geeksville.meshB\x10ClientOnlyProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_clientonly_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/config.pb.go b/generated/meshtastic/config.pb.go similarity index 99% rename from proto/generated/meshtastic/config.pb.go rename to generated/meshtastic/config.pb.go index a98ccdd..034d982 100644 --- a/proto/generated/meshtastic/config.pb.go +++ b/generated/meshtastic/config.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/config.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -2742,8 +2742,8 @@ const file_meshtastic_config_proto_rawDesc = "" + "\x15debug_log_api_enabled\x18\x06 \x01(\bR\x12debugLogApiEnabled\x122\n" + "\x15admin_channel_enabled\x18\b \x01(\bR\x13adminChannelEnabled\x1a\x12\n" + "\x10SessionkeyConfigB\x11\n" + - "\x0fpayload_variantBa\n" + - "\x13com.geeksville.meshB\fConfigProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\x0fpayload_variantB^\n" + + "\x13com.geeksville.meshB\fConfigProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_config_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/connection_status.pb.go b/generated/meshtastic/connection_status.pb.go similarity index 98% rename from proto/generated/meshtastic/connection_status.pb.go rename to generated/meshtastic/connection_status.pb.go index 531d7a6..7856595 100644 --- a/proto/generated/meshtastic/connection_status.pb.go +++ b/generated/meshtastic/connection_status.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/connection_status.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -429,8 +429,8 @@ const file_meshtastic_connection_status_proto_rawDesc = "" + "\fis_connected\x18\x03 \x01(\bR\visConnected\"O\n" + "\x16SerialConnectionStatus\x12\x12\n" + "\x04baud\x18\x01 \x01(\rR\x04baud\x12!\n" + - "\fis_connected\x18\x02 \x01(\bR\visConnectedBe\n" + - "\x13com.geeksville.meshB\x10ConnStatusProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\fis_connected\x18\x02 \x01(\bR\visConnectedBb\n" + + "\x13com.geeksville.meshB\x10ConnStatusProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_connection_status_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/device_ui.pb.go b/generated/meshtastic/device_ui.pb.go similarity index 99% rename from proto/generated/meshtastic/device_ui.pb.go rename to generated/meshtastic/device_ui.pb.go index 21f8da7..d40040f 100644 --- a/proto/generated/meshtastic/device_ui.pb.go +++ b/generated/meshtastic/device_ui.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/device_ui.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -743,8 +743,8 @@ const file_meshtastic_device_ui_proto_rawDesc = "" + "\tSLOVENIAN\x10\x0f\x12\r\n" + "\tUKRAINIAN\x10\x10\x12\x16\n" + "\x12SIMPLIFIED_CHINESE\x10\x1e\x12\x17\n" + - "\x13TRADITIONAL_CHINESE\x10\x1fBc\n" + - "\x13com.geeksville.meshB\x0eDeviceUIProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\x13TRADITIONAL_CHINESE\x10\x1fB`\n" + + "\x13com.geeksville.meshB\x0eDeviceUIProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_device_ui_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/deviceonly.pb.go b/generated/meshtastic/deviceonly.pb.go similarity index 99% rename from proto/generated/meshtastic/deviceonly.pb.go rename to generated/meshtastic/deviceonly.pb.go index 50f873c..17548c6 100644 --- a/proto/generated/meshtastic/deviceonly.pb.go +++ b/generated/meshtastic/deviceonly.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/deviceonly.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -773,9 +773,9 @@ const file_meshtastic_deviceonly_proto_rawDesc = "" + "\x06config\x18\x03 \x01(\v2\x17.meshtastic.LocalConfigR\x06config\x12B\n" + "\rmodule_config\x18\x04 \x01(\v2\x1d.meshtastic.LocalModuleConfigR\fmoduleConfig\x123\n" + "\bchannels\x18\x05 \x01(\v2\x17.meshtastic.ChannelFileR\bchannels\x12&\n" + - "\x05owner\x18\x06 \x01(\v2\x10.meshtastic.UserR\x05ownerBm\x92?\v\xc2\x01\b\n" + + "\x05owner\x18\x06 \x01(\v2\x10.meshtastic.UserR\x05ownerBj\x92?\v\xc2\x01\b\n" + "\x13com.geeksville.meshB\n" + - "DeviceOnlyZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "DeviceOnlyZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_deviceonly_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/interdevice.pb.go b/generated/meshtastic/interdevice.pb.go similarity index 98% rename from proto/generated/meshtastic/interdevice.pb.go rename to generated/meshtastic/interdevice.pb.go index 46e15e5..db8f3c3 100644 --- a/proto/generated/meshtastic/interdevice.pb.go +++ b/generated/meshtastic/interdevice.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/interdevice.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -306,8 +306,8 @@ const file_meshtastic_interdevice_proto_rawDesc = "" + "AHT20_TEMP\x10\xb3\x01\x12\x13\n" + "\x0eAHT20_HUMIDITY\x10\xb4\x01\x12\x0f\n" + "\n" + - "TVOC_INDEX\x10\xb5\x01Bf\n" + - "\x13com.geeksville.meshB\x11InterdeviceProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "TVOC_INDEX\x10\xb5\x01Bc\n" + + "\x13com.geeksville.meshB\x11InterdeviceProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_interdevice_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/localonly.pb.go b/generated/meshtastic/localonly.pb.go similarity index 98% rename from proto/generated/meshtastic/localonly.pb.go rename to generated/meshtastic/localonly.pb.go index 7a53027..7a1335e 100644 --- a/proto/generated/meshtastic/localonly.pb.go +++ b/generated/meshtastic/localonly.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/localonly.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -338,8 +338,8 @@ const file_meshtastic_localonly_proto_rawDesc = "" + "\n" + "paxcounter\x18\x0e \x01(\v2).meshtastic.ModuleConfig.PaxcounterConfigR\n" + "paxcounter\x12\x18\n" + - "\aversion\x18\b \x01(\rR\aversionBd\n" + - "\x13com.geeksville.meshB\x0fLocalOnlyProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\aversion\x18\b \x01(\rR\aversionBa\n" + + "\x13com.geeksville.meshB\x0fLocalOnlyProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_localonly_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/mesh.pb.go b/generated/meshtastic/mesh.pb.go similarity index 99% rename from proto/generated/meshtastic/mesh.pb.go rename to generated/meshtastic/mesh.pb.go index ef65b85..0544259 100644 --- a/proto/generated/meshtastic/mesh.pb.go +++ b/generated/meshtastic/mesh.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/mesh.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -4589,9 +4589,9 @@ const file_meshtastic_mesh_proto_rawDesc = "" + "\x16DETECTIONSENSOR_CONFIG\x10\x80\x10\x12\x16\n" + "\x11PAXCOUNTER_CONFIG\x10\x80 \x12\x15\n" + "\x10BLUETOOTH_CONFIG\x10\x80@\x12\x14\n" + - "\x0eNETWORK_CONFIG\x10\x80\x80\x01B_\n" + + "\x0eNETWORK_CONFIG\x10\x80\x80\x01B\\\n" + "\x13com.geeksville.meshB\n" + - "MeshProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "MeshProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_mesh_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/module_config.pb.go b/generated/meshtastic/module_config.pb.go similarity index 99% rename from proto/generated/meshtastic/module_config.pb.go rename to generated/meshtastic/module_config.pb.go index c0257c4..470881c 100644 --- a/proto/generated/meshtastic/module_config.pb.go +++ b/generated/meshtastic/module_config.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/module_config.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -2439,8 +2439,8 @@ const file_meshtastic_module_config_proto_rawDesc = "" + "\x15RemoteHardwarePinType\x12\v\n" + "\aUNKNOWN\x10\x00\x12\x10\n" + "\fDIGITAL_READ\x10\x01\x12\x11\n" + - "\rDIGITAL_WRITE\x10\x02Bg\n" + - "\x13com.geeksville.meshB\x12ModuleConfigProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\rDIGITAL_WRITE\x10\x02Bd\n" + + "\x13com.geeksville.meshB\x12ModuleConfigProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_module_config_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/mqtt.pb.go b/generated/meshtastic/mqtt.pb.go similarity index 98% rename from proto/generated/meshtastic/mqtt.pb.go rename to generated/meshtastic/mqtt.pb.go index 42103a6..747021f 100644 --- a/proto/generated/meshtastic/mqtt.pb.go +++ b/generated/meshtastic/mqtt.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/mqtt.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -272,9 +272,9 @@ const file_meshtastic_mqtt_proto_rawDesc = "" + "longitudeI\x12\x1a\n" + "\baltitude\x18\v \x01(\x05R\baltitude\x12-\n" + "\x12position_precision\x18\f \x01(\rR\x11positionPrecision\x123\n" + - "\x16num_online_local_nodes\x18\r \x01(\rR\x13numOnlineLocalNodesB_\n" + + "\x16num_online_local_nodes\x18\r \x01(\rR\x13numOnlineLocalNodesB\\\n" + "\x13com.geeksville.meshB\n" + - "MQTTProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "MQTTProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_mqtt_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/nanopb.pb.go b/generated/meshtastic/nanopb.pb.go similarity index 99% rename from proto/generated/meshtastic/nanopb.pb.go rename to generated/meshtastic/nanopb.pb.go index 3be4a14..8f921f0 100644 --- a/proto/generated/meshtastic/nanopb.pb.go +++ b/generated/meshtastic/nanopb.pb.go @@ -11,7 +11,7 @@ // protoc v5.29.3 // source: meshtastic/nanopb.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -771,8 +771,8 @@ const file_meshtastic_nanopb_proto_rawDesc = "" + "\x0enanopb_fileopt\x12\x1c.google.protobuf.FileOptions\x18\xf2\a \x01(\v2\x0e.NanoPBOptionsR\rnanopbFileopt:U\n" + "\rnanopb_msgopt\x12\x1f.google.protobuf.MessageOptions\x18\xf2\a \x01(\v2\x0e.NanoPBOptionsR\fnanopbMsgopt:T\n" + "\x0enanopb_enumopt\x12\x1c.google.protobuf.EnumOptions\x18\xf2\a \x01(\v2\x0e.NanoPBOptionsR\rnanopbEnumopt:F\n" + - "\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\a \x01(\v2\x0e.NanoPBOptionsR\x06nanopbB>\n" + - "\x18fi.kapsi.koti.jpa.nanopbZ\"github.com/meshtastic/go/generated" + "\x06nanopb\x12\x1d.google.protobuf.FieldOptions\x18\xf2\a \x01(\v2\x0e.NanoPBOptionsR\x06nanopbB;\n" + + "\x18fi.kapsi.koti.jpa.nanopbZ\x1fmeshstream/generated/meshtastic" var ( file_meshtastic_nanopb_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/paxcount.pb.go b/generated/meshtastic/paxcount.pb.go similarity index 95% rename from proto/generated/meshtastic/paxcount.pb.go rename to generated/meshtastic/paxcount.pb.go index 4cfb585..aebcb6b 100644 --- a/proto/generated/meshtastic/paxcount.pb.go +++ b/generated/meshtastic/paxcount.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/paxcount.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -94,8 +94,8 @@ const file_meshtastic_paxcount_proto_rawDesc = "" + "\bPaxcount\x12\x12\n" + "\x04wifi\x18\x01 \x01(\rR\x04wifi\x12\x10\n" + "\x03ble\x18\x02 \x01(\rR\x03ble\x12\x16\n" + - "\x06uptime\x18\x03 \x01(\rR\x06uptimeBc\n" + - "\x13com.geeksville.meshB\x0ePaxcountProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\x06uptime\x18\x03 \x01(\rR\x06uptimeB`\n" + + "\x13com.geeksville.meshB\x0ePaxcountProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_paxcount_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/portnums.pb.go b/generated/meshtastic/portnums.pb.go similarity index 98% rename from proto/generated/meshtastic/portnums.pb.go rename to generated/meshtastic/portnums.pb.go index 7cf4372..384e0f8 100644 --- a/proto/generated/meshtastic/portnums.pb.go +++ b/generated/meshtastic/portnums.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/portnums.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -288,8 +288,8 @@ const file_meshtastic_portnums_proto_rawDesc = "" + "\x14RETICULUM_TUNNEL_APP\x10L\x12\x10\n" + "\vPRIVATE_APP\x10\x80\x02\x12\x13\n" + "\x0eATAK_FORWARDER\x10\x81\x02\x12\b\n" + - "\x03MAX\x10\xff\x03B]\n" + - "\x13com.geeksville.meshB\bPortnumsZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\x03MAX\x10\xff\x03BZ\n" + + "\x13com.geeksville.meshB\bPortnumsZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_portnums_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/powermon.pb.go b/generated/meshtastic/powermon.pb.go similarity index 98% rename from proto/generated/meshtastic/powermon.pb.go rename to generated/meshtastic/powermon.pb.go index 0d87400..a0111ce 100644 --- a/proto/generated/meshtastic/powermon.pb.go +++ b/generated/meshtastic/powermon.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/powermon.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -360,8 +360,8 @@ const file_meshtastic_powermon_proto_rawDesc = "" + "\aWIFI_ON\x10a\x12\v\n" + "\aGPS_OFF\x10p\x12\n" + "\n" + - "\x06GPS_ON\x10qBc\n" + - "\x13com.geeksville.meshB\x0ePowerMonProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\x06GPS_ON\x10qB`\n" + + "\x13com.geeksville.meshB\x0ePowerMonProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_powermon_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/remote_hardware.pb.go b/generated/meshtastic/remote_hardware.pb.go similarity index 97% rename from proto/generated/meshtastic/remote_hardware.pb.go rename to generated/meshtastic/remote_hardware.pb.go index fb0691d..f2529da 100644 --- a/proto/generated/meshtastic/remote_hardware.pb.go +++ b/generated/meshtastic/remote_hardware.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/remote_hardware.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -179,8 +179,8 @@ const file_meshtastic_remote_hardware_proto_rawDesc = "" + "\rGPIOS_CHANGED\x10\x03\x12\x0e\n" + "\n" + "READ_GPIOS\x10\x04\x12\x14\n" + - "\x10READ_GPIOS_REPLY\x10\x05Bc\n" + - "\x13com.geeksville.meshB\x0eRemoteHardwareZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\x10READ_GPIOS_REPLY\x10\x05B`\n" + + "\x13com.geeksville.meshB\x0eRemoteHardwareZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_remote_hardware_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/rtttl.pb.go b/generated/meshtastic/rtttl.pb.go similarity index 94% rename from proto/generated/meshtastic/rtttl.pb.go rename to generated/meshtastic/rtttl.pb.go index a5446e8..fe46359 100644 --- a/proto/generated/meshtastic/rtttl.pb.go +++ b/generated/meshtastic/rtttl.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/rtttl.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -74,8 +74,8 @@ const file_meshtastic_rtttl_proto_rawDesc = "" + "\x16meshtastic/rtttl.proto\x12\n" + "meshtastic\")\n" + "\vRTTTLConfig\x12\x1a\n" + - "\bringtone\x18\x01 \x01(\tR\bringtoneBf\n" + - "\x13com.geeksville.meshB\x11RTTTLConfigProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\bringtone\x18\x01 \x01(\tR\bringtoneBc\n" + + "\x13com.geeksville.meshB\x11RTTTLConfigProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_rtttl_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/storeforward.pb.go b/generated/meshtastic/storeforward.pb.go similarity index 99% rename from proto/generated/meshtastic/storeforward.pb.go rename to generated/meshtastic/storeforward.pb.go index 7adf89f..45e355c 100644 --- a/proto/generated/meshtastic/storeforward.pb.go +++ b/generated/meshtastic/storeforward.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/storeforward.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -545,8 +545,8 @@ const file_meshtastic_storeforward_proto_rawDesc = "" + "\vCLIENT_PING\x10C\x12\x0f\n" + "\vCLIENT_PONG\x10D\x12\x10\n" + "\fCLIENT_ABORT\x10jB\t\n" + - "\avariantBj\n" + - "\x13com.geeksville.meshB\x15StoreAndForwardProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\avariantBg\n" + + "\x13com.geeksville.meshB\x15StoreAndForwardProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_storeforward_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/telemetry.pb.go b/generated/meshtastic/telemetry.pb.go similarity index 99% rename from proto/generated/meshtastic/telemetry.pb.go rename to generated/meshtastic/telemetry.pb.go index d4d3d3a..3e1c7d6 100644 --- a/proto/generated/meshtastic/telemetry.pb.go +++ b/generated/meshtastic/telemetry.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/telemetry.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -1405,8 +1405,8 @@ const file_meshtastic_telemetry_proto_rawDesc = "" + "\fDFROBOT_RAIN\x10#\x12\n" + "\n" + "\x06DPS310\x10$\x12\f\n" + - "\bRAK12035\x10%Bd\n" + - "\x13com.geeksville.meshB\x0fTelemetryProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\bRAK12035\x10%Ba\n" + + "\x13com.geeksville.meshB\x0fTelemetryProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_telemetry_proto_rawDescOnce sync.Once diff --git a/proto/generated/meshtastic/xmodem.pb.go b/generated/meshtastic/xmodem.pb.go similarity index 97% rename from proto/generated/meshtastic/xmodem.pb.go rename to generated/meshtastic/xmodem.pb.go index d9781c1..2ca88c6 100644 --- a/proto/generated/meshtastic/xmodem.pb.go +++ b/generated/meshtastic/xmodem.pb.go @@ -4,7 +4,7 @@ // protoc v5.29.3 // source: meshtastic/xmodem.proto -package generated +package meshtastic import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -172,8 +172,8 @@ const file_meshtastic_xmodem_proto_rawDesc = "" + "\x03ACK\x10\x06\x12\a\n" + "\x03NAK\x10\x15\x12\a\n" + "\x03CAN\x10\x18\x12\t\n" + - "\x05CTRLZ\x10\x1aBa\n" + - "\x13com.geeksville.meshB\fXmodemProtosZ\"github.com/meshtastic/go/generated\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" + "\x05CTRLZ\x10\x1aB^\n" + + "\x13com.geeksville.meshB\fXmodemProtosZ\x1fmeshstream/generated/meshtastic\xaa\x02\x14Meshtastic.Protobufs\xba\x02\x00b\x06proto3" var ( file_meshtastic_xmodem_proto_rawDescOnce sync.Once diff --git a/go.mod b/go.mod index 09fb040..7d3162a 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,8 @@ go 1.24.1 tool github.com/dpup/logista +replace github.com/meshtastic/go/ => ./generated/ + require ( github.com/dpup/prefab v0.2.0 github.com/eclipse/paho.mqtt.golang v1.5.0 diff --git a/mqtt/client.go b/mqtt/client.go index db46f77..85bce47 100644 --- a/mqtt/client.go +++ b/mqtt/client.go @@ -8,6 +8,7 @@ import ( mqtt "github.com/eclipse/paho.mqtt.golang" "meshstream/decoder" + mesh "meshstream/proto/generated" ) // Config holds configuration for the MQTT client @@ -32,7 +33,7 @@ type Client struct { func NewClient(config Config, logger logging.Logger) *Client { return &Client{ config: config, - decodedMessages: make(chan *Packet, 100), // Buffer up to 100 messages + decodedMessages: make(chan *Packet, 100), done: make(chan struct{}), logger: logger.Named("mqtt.client"), } @@ -79,8 +80,6 @@ func (c *Client) Messages() <-chan *Packet { return c.decodedMessages } -// These are intentionally left empty as we'll use the instance methods below - // messageHandler processes incoming MQTT messages func (c *Client) messageHandler(client mqtt.Client, msg mqtt.Message) { c.logger.Debugf("Received message from topic: %s", msg.Topic()) @@ -103,10 +102,7 @@ func (c *Client) messageHandler(client mqtt.Client, msg mqtt.Message) { decodedPacket := decoder.DecodeMessage(msg.Payload(), topicInfo) // Create packet with both the decoded packet and topic info - packet := &Packet{ - DecodedPacket: decodedPacket, - TopicInfo: topicInfo, - } + packet := NewPacket(decodedPacket, topicInfo) // Send the decoded message to the channel, but don't block if buffer is full select { @@ -138,4 +134,4 @@ func (c *Client) connectHandler(client mqtt.Client) { // connectionLostHandler is called when the client loses connection func (c *Client) connectionLostHandler(client mqtt.Client, err error) { c.logger.Errorw("Connection lost", "error", err) -} +} \ No newline at end of file diff --git a/mqtt/packet.go b/mqtt/packet.go index 251a342..6ad0598 100644 --- a/mqtt/packet.go +++ b/mqtt/packet.go @@ -1,11 +1,151 @@ package mqtt import ( - "meshstream/decoder" + mesh "meshstream/proto/generated" ) // Packet extends the DecodedPacket with MQTT topic information type Packet struct { - *decoder.DecodedPacket - *decoder.TopicInfo + *mesh.Packet +} + +// NewPacket creates a Packet from a decoded packet and topic info +func NewPacket(decoded *mesh.DecodedPacket, topicInfo *mesh.TopicInfo) *Packet { + return &Packet{ + Packet: &mesh.Packet{ + DecodedPacket: decoded, + TopicInfo: topicInfo, + }, + } +} + +// Helper accessors to maintain backward compatibility with existing code +func (p *Packet) GetChannelID() string { + if p.DecodedPacket != nil { + return p.DecodedPacket.ChannelId + } + return "" +} + +func (p *Packet) GetGatewayID() string { + if p.DecodedPacket != nil { + return p.DecodedPacket.GatewayId + } + return "" +} + +func (p *Packet) GetID() uint32 { + if p.DecodedPacket != nil { + return p.DecodedPacket.Id + } + return 0 +} + +func (p *Packet) GetFrom() uint32 { + if p.DecodedPacket != nil { + return p.DecodedPacket.From + } + return 0 +} + +func (p *Packet) GetTo() uint32 { + if p.DecodedPacket != nil { + return p.DecodedPacket.To + } + return 0 +} + +func (p *Packet) GetPortNum() int32 { + if p.DecodedPacket != nil { + return int32(p.DecodedPacket.PortNum) + } + return 0 +} + +func (p *Packet) GetPortNumString() string { + if p.DecodedPacket != nil { + return p.DecodedPacket.PortNum.String() + } + return "UNKNOWN" +} + +func (p *Packet) GetPayload() interface{} { + if p.DecodedPacket == nil { + return nil + } + + // Depending on the payload type, return the appropriate value + switch x := p.DecodedPacket.Payload.(type) { + case *mesh.DecodedPacket_TextMessage: + return x.TextMessage + case *mesh.DecodedPacket_BinaryData: + return x.BinaryData + case *mesh.DecodedPacket_Position: + return x.Position + case *mesh.DecodedPacket_NodeInfo: + return x.NodeInfo + case *mesh.DecodedPacket_Telemetry: + return x.Telemetry + case *mesh.DecodedPacket_Waypoint: + return x.Waypoint + case *mesh.DecodedPacket_RouteDiscovery: + return x.RouteDiscovery + case *mesh.DecodedPacket_NeighborInfo: + return x.NeighborInfo + case *mesh.DecodedPacket_CompressedText: + return x.CompressedText + case *mesh.DecodedPacket_MapReport: + return x.MapReport + default: + return nil + } +} + +func (p *Packet) GetHopLimit() uint32 { + if p.DecodedPacket != nil { + return p.DecodedPacket.HopLimit + } + return 0 +} + +func (p *Packet) GetHopStart() uint32 { + if p.DecodedPacket != nil { + return p.DecodedPacket.HopStart + } + return 0 +} + +func (p *Packet) HasDecodeError() bool { + return p.DecodedPacket != nil && p.DecodedPacket.DecodeError != "" +} + +func (p *Packet) GetDecodeError() string { + if p.DecodedPacket != nil { + return p.DecodedPacket.DecodeError + } + return "" +} + +// GetFullTopic returns the MQTT topic this packet was received on +func (p *Packet) GetFullTopic() string { + if p.TopicInfo != nil { + return p.TopicInfo.FullTopic + } + return "" +} + +// GetRegionPath returns the region path from the topic +func (p *Packet) GetRegionPath() string { + if p.TopicInfo != nil { + return p.TopicInfo.RegionPath + } + return "" +} + +// GetChannel returns the channel name from the topic +func (p *Packet) GetChannel() string { + if p.TopicInfo != nil { + return p.TopicInfo.Channel + } + return "" } \ No newline at end of file diff --git a/proto/meshstream/meshstream.proto b/proto/meshstream/meshstream.proto new file mode 100644 index 0000000..8d7cc9e --- /dev/null +++ b/proto/meshstream/meshstream.proto @@ -0,0 +1,94 @@ +syntax = "proto3"; + +package meshstream; + +import "meshtastic/mesh.proto"; +import "meshtastic/portnums.proto"; +import "meshtastic/telemetry.proto"; +import "meshtastic/mqtt.proto"; +import "meshtastic/remote_hardware.proto"; +import "meshtastic/admin.proto"; +import "meshtastic/paxcount.proto"; + +option go_package = "proto/generated/meshstream;meshtreampb"; + +// Packet represents a complete decoded MQTT message +message Packet { + TopicInfo info = 2; + Data data = 1; +} + +// TopicInfo contains parsed information about a Meshtastic MQTT topic +message TopicInfo { + string full_topic = 1; + string region_path = 2; + string version = 3; + string format = 4; + string channel = 5; + string user_id = 6; +} + +// Data provides a flattened structure for decoded Meshtastic packets +message Data { + // From Service Envelope + string channel_id = 1; + string gateway_id = 2; + + // From Mesh Packet + uint32 id = 3; + uint32 from = 4; + uint32 to = 5; + uint32 hop_limit = 6; + uint32 hop_start = 7; + bool want_ack = 8; + string priority = 9; + bool via_mqtt = 10; + uint32 next_hop = 11; + uint32 relay_node = 12; + + // From Data + meshtastic.PortNum port_num = 13; + + // Payload is one of these types, depending on port_num + oneof payload { + string text_message = 14; // TEXT_MESSAGE_APP + bytes binary_data = 15; // Generic binary data for other port types + meshtastic.Position position = 16; // POSITION_APP + meshtastic.User node_info = 17; // NODEINFO_APP + meshtastic.Telemetry telemetry = 18; // TELEMETRY_APP + meshtastic.Waypoint waypoint = 19; // WAYPOINT_APP + meshtastic.RouteDiscovery route_discovery = 20; // TRACEROUTE_APP + meshtastic.NeighborInfo neighbor_info = 21; // NEIGHBORINFO_APP + bytes compressed_text = 22; // TEXT_MESSAGE_COMPRESSED_APP + meshtastic.MapReport map_report = 23; // MAP_REPORT_APP + meshtastic.HardwareMessage remote_hardware = 24; // REMOTE_HARDWARE_APP + meshtastic.Routing routing = 25; // ROUTING_APP + meshtastic.AdminMessage admin = 26; // ADMIN_APP + bytes audio_data = 27; // AUDIO_APP + string alert = 28; // ALERT_APP + string reply = 29; // REPLY_APP + bytes ip_tunnel = 30; // IP_TUNNEL_APP + meshtastic.Paxcount paxcounter = 31; // PAXCOUNTER_APP + bytes serial_app = 32; // SERIAL_APP + bytes store_forward = 33; // STORE_FORWARD_APP + string range_test = 34; // RANGE_TEST_APP + bytes zps_app = 35; // ZPS_APP + bytes simulator = 36; // SIMULATOR_APP + bytes atak_plugin = 37; // ATAK_PLUGIN + bytes powerstress = 38; // POWERSTRESS_APP + bytes reticulum_tunnel = 39; // RETICULUM_TUNNEL_APP + bytes private_app = 40; // PRIVATE_APP, ATAK_FORWARDER + string detection_sensor = 41; // DETECTION_SENSOR_APP + } + + // Additional Data fields + uint32 request_id = 50; + uint32 reply_id = 51; + uint32 emoji = 52; + uint32 dest = 53; + uint32 source = 54; + bool want_response = 55; + + // Error tracking + string decode_error = 60; +} \ No newline at end of file diff --git a/proto/meshtastic/admin.proto b/proto/meshtastic/admin.proto index f4718c1..a75c056 100644 --- a/proto/meshtastic/admin.proto +++ b/proto/meshtastic/admin.proto @@ -10,7 +10,7 @@ import "meshtastic/module_config.proto"; import "meshtastic/device_ui.proto"; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "AdminProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/apponly.proto b/proto/meshtastic/apponly.proto index 100833f..b9d66a0 100644 --- a/proto/meshtastic/apponly.proto +++ b/proto/meshtastic/apponly.proto @@ -6,7 +6,7 @@ import "meshtastic/channel.proto"; import "meshtastic/config.proto"; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "AppOnlyProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/atak.proto b/proto/meshtastic/atak.proto index 5dc08c9..9a26796 100644 --- a/proto/meshtastic/atak.proto +++ b/proto/meshtastic/atak.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "ATAKProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/cannedmessages.proto b/proto/meshtastic/cannedmessages.proto index baa5134..9d24445 100644 --- a/proto/meshtastic/cannedmessages.proto +++ b/proto/meshtastic/cannedmessages.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "CannedMessageConfigProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/channel.proto b/proto/meshtastic/channel.proto index 16c8c19..0c1578e 100644 --- a/proto/meshtastic/channel.proto +++ b/proto/meshtastic/channel.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "ChannelProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/clientonly.proto b/proto/meshtastic/clientonly.proto index 2b919ef..be07285 100644 --- a/proto/meshtastic/clientonly.proto +++ b/proto/meshtastic/clientonly.proto @@ -6,7 +6,7 @@ import "meshtastic/localonly.proto"; import "meshtastic/mesh.proto"; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "ClientOnlyProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/config.proto b/proto/meshtastic/config.proto index 0e51cdd..659bf97 100644 --- a/proto/meshtastic/config.proto +++ b/proto/meshtastic/config.proto @@ -5,7 +5,7 @@ package meshtastic; import "meshtastic/device_ui.proto"; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "ConfigProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/connection_status.proto b/proto/meshtastic/connection_status.proto index 7551596..f3b95b1 100644 --- a/proto/meshtastic/connection_status.proto +++ b/proto/meshtastic/connection_status.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "ConnStatusProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/device_ui.proto b/proto/meshtastic/device_ui.proto index 138f5e8..d57b331 100644 --- a/proto/meshtastic/device_ui.proto +++ b/proto/meshtastic/device_ui.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "DeviceUIProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/deviceonly.proto b/proto/meshtastic/deviceonly.proto index 9fe85be..8f8b0e5 100644 --- a/proto/meshtastic/deviceonly.proto +++ b/proto/meshtastic/deviceonly.proto @@ -10,7 +10,7 @@ import "meshtastic/localonly.proto"; import "meshtastic/nanopb.proto"; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "DeviceOnly"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/interdevice.proto b/proto/meshtastic/interdevice.proto index 54e950f..9bfa2fc 100644 --- a/proto/meshtastic/interdevice.proto +++ b/proto/meshtastic/interdevice.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "InterdeviceProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/localonly.proto b/proto/meshtastic/localonly.proto index bcb2796..b927b5f 100644 --- a/proto/meshtastic/localonly.proto +++ b/proto/meshtastic/localonly.proto @@ -6,7 +6,7 @@ import "meshtastic/config.proto"; import "meshtastic/module_config.proto"; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "LocalOnlyProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/mesh.proto b/proto/meshtastic/mesh.proto index 2af5d98..b5f92c2 100644 --- a/proto/meshtastic/mesh.proto +++ b/proto/meshtastic/mesh.proto @@ -11,7 +11,7 @@ import "meshtastic/xmodem.proto"; import "meshtastic/device_ui.proto"; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "MeshProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/module_config.proto b/proto/meshtastic/module_config.proto index 4f18d5f..3da98b4 100644 --- a/proto/meshtastic/module_config.proto +++ b/proto/meshtastic/module_config.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "ModuleConfigProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/mqtt.proto b/proto/meshtastic/mqtt.proto index 2dbc820..e42c45d 100644 --- a/proto/meshtastic/mqtt.proto +++ b/proto/meshtastic/mqtt.proto @@ -6,7 +6,7 @@ import "meshtastic/config.proto"; import "meshtastic/mesh.proto"; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "MQTTProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/nanopb.proto b/proto/meshtastic/nanopb.proto index 1c107c1..f1850f1 100644 --- a/proto/meshtastic/nanopb.proto +++ b/proto/meshtastic/nanopb.proto @@ -9,7 +9,7 @@ syntax = "proto2"; import "google/protobuf/descriptor.proto"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_package = "fi.kapsi.koti.jpa.nanopb"; enum FieldType { diff --git a/proto/meshtastic/paxcount.proto b/proto/meshtastic/paxcount.proto index 47b2639..185caac 100644 --- a/proto/meshtastic/paxcount.proto +++ b/proto/meshtastic/paxcount.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "PaxcountProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/portnums.proto b/proto/meshtastic/portnums.proto index 76df5db..e8f1c77 100644 --- a/proto/meshtastic/portnums.proto +++ b/proto/meshtastic/portnums.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "Portnums"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/powermon.proto b/proto/meshtastic/powermon.proto index dbb89b9..ff06ccd 100644 --- a/proto/meshtastic/powermon.proto +++ b/proto/meshtastic/powermon.proto @@ -1,7 +1,7 @@ syntax = "proto3"; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "PowerMonProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/remote_hardware.proto b/proto/meshtastic/remote_hardware.proto index ba4a693..db67685 100644 --- a/proto/meshtastic/remote_hardware.proto +++ b/proto/meshtastic/remote_hardware.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "RemoteHardware"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/rtttl.proto b/proto/meshtastic/rtttl.proto index 11c8b92..5809b2c 100644 --- a/proto/meshtastic/rtttl.proto +++ b/proto/meshtastic/rtttl.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "RTTTLConfigProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/storeforward.proto b/proto/meshtastic/storeforward.proto index 651eae5..ccc6b2f 100644 --- a/proto/meshtastic/storeforward.proto +++ b/proto/meshtastic/storeforward.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "StoreAndForwardProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/telemetry.proto b/proto/meshtastic/telemetry.proto index 3ca7d07..0539025 100644 --- a/proto/meshtastic/telemetry.proto +++ b/proto/meshtastic/telemetry.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "TelemetryProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/proto/meshtastic/xmodem.proto b/proto/meshtastic/xmodem.proto index 732780a..9244a77 100644 --- a/proto/meshtastic/xmodem.proto +++ b/proto/meshtastic/xmodem.proto @@ -3,7 +3,7 @@ syntax = "proto3"; package meshtastic; option csharp_namespace = "Meshtastic.Protobufs"; -option go_package = "github.com/meshtastic/go/generated"; +option go_package = "meshstream/generated/meshtastic"; option java_outer_classname = "XmodemProtos"; option java_package = "com.geeksville.mesh"; option swift_prefix = ""; diff --git a/server/server.go b/server/server.go index 4a5d34a..0a97719 100644 --- a/server/server.go +++ b/server/server.go @@ -6,10 +6,10 @@ import ( "net/http" "strconv" "sync/atomic" - "time" "github.com/dpup/prefab" "github.com/dpup/prefab/logging" + "google.golang.org/protobuf/encoding/protojson" "meshstream/mqtt" ) @@ -174,24 +174,19 @@ func (s *Server) handleStream(w http.ResponseWriter, r *http.Request) { continue } - // Create a serializable wrapper for the packet - // That includes both the entire packet and some extra fields for convenience - packetWrapper := struct { - *mqtt.Packet - ReceivedAt int64 `json:"received_at"` - PortString string `json:"port_string"` - }{ - Packet: packet, - ReceivedAt: time.Now().Unix(), - PortString: packet.PortNum.String(), + // Use protojson Marshaler for the protobuf parts of the packet + // Create a marshaler with pretty printing enabled + marshaler := protojson.MarshalOptions{ + EmitUnpopulated: true, + Indent: " ", + UseProtoNames: false, // Use camelCase names } - // Convert the entire packet to JSON - data, err := json.Marshal(packetWrapper) - + data, err := marshaler.Marshal(packet) if err != nil { logger.Errorw("Error marshaling packet to JSON", "error", err) - continue + http.Error(w, "Error marshaling packet", http.StatusInternalServerError) + return } // Send the event