mirror of
https://github.com/dpup/meshstream.git
synced 2026-08-06 16:53:09 +02:00
Improve packet decoding with more robust type detection and debug information
This commit is contained in:
+109
-30
@@ -4,6 +4,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// PacketType represents the type of a Meshtastic packet
|
||||
@@ -31,8 +32,9 @@ type DecodedPacket struct {
|
||||
// DecodePacket attempts to decode a packet from MQTT
|
||||
func DecodePacket(topic string, payload []byte) (*DecodedPacket, error) {
|
||||
packet := &DecodedPacket{
|
||||
Topic: topic,
|
||||
RawData: payload,
|
||||
Topic: topic,
|
||||
RawData: payload,
|
||||
JSONData: make(map[string]interface{}),
|
||||
}
|
||||
|
||||
// Extract channel and other info from topic
|
||||
@@ -44,41 +46,94 @@ func DecodePacket(topic string, payload []byte) (*DecodedPacket, error) {
|
||||
// Set channel info (typically msh/REGION/STATE/NAME)
|
||||
packet.Channel = strings.Join(parts[1:4], "/")
|
||||
|
||||
// Determine packet type from topic
|
||||
if strings.Contains(topic, "/json/") {
|
||||
packet.Type = TypeJSON
|
||||
if err := json.Unmarshal(payload, &packet.JSONData); err != nil {
|
||||
return packet, fmt.Errorf("failed to parse JSON: %v", err)
|
||||
}
|
||||
// Try to determine type from topic structure
|
||||
if len(parts) >= 5 {
|
||||
typeIndicator := parts[4]
|
||||
|
||||
switch typeIndicator {
|
||||
case "json":
|
||||
packet.Type = TypeJSON
|
||||
if err := json.Unmarshal(payload, &packet.JSONData); err != nil {
|
||||
return packet, fmt.Errorf("failed to parse JSON: %v", err)
|
||||
}
|
||||
|
||||
// Extract common fields
|
||||
if from, ok := packet.JSONData["from"].(string); ok {
|
||||
packet.FromNode = from
|
||||
// Extract common fields
|
||||
if from, ok := packet.JSONData["from"].(string); ok {
|
||||
packet.FromNode = from
|
||||
}
|
||||
if to, ok := packet.JSONData["to"].(string); ok {
|
||||
packet.ToNode = to
|
||||
}
|
||||
if text, ok := packet.JSONData["payload"].(string); ok {
|
||||
packet.Text = text
|
||||
}
|
||||
if ts, ok := packet.JSONData["timestamp"].(string); ok {
|
||||
packet.Timestamp = ts
|
||||
}
|
||||
|
||||
case "binary":
|
||||
// Binary protobuf payload
|
||||
packet.Type = TypeBinary
|
||||
// Note: Actual protobuf decoding would be done here
|
||||
|
||||
case "text":
|
||||
// Plain text payload
|
||||
packet.Type = TypeText
|
||||
packet.Text = string(payload)
|
||||
|
||||
default:
|
||||
// Try to infer type from payload
|
||||
if len(payload) > 0 && payload[0] == '{' {
|
||||
// Looks like JSON
|
||||
packet.Type = TypeJSON
|
||||
if err := json.Unmarshal(payload, &packet.JSONData); err == nil {
|
||||
// Successfully parsed as JSON
|
||||
|
||||
// Extract common fields
|
||||
if from, ok := packet.JSONData["from"].(string); ok {
|
||||
packet.FromNode = from
|
||||
}
|
||||
if to, ok := packet.JSONData["to"].(string); ok {
|
||||
packet.ToNode = to
|
||||
}
|
||||
if text, ok := packet.JSONData["payload"].(string); ok {
|
||||
packet.Text = text
|
||||
}
|
||||
if ts, ok := packet.JSONData["timestamp"].(string); ok {
|
||||
packet.Timestamp = ts
|
||||
}
|
||||
}
|
||||
} else if utf8.Valid(payload) && !containsBinaryData(payload) {
|
||||
// Probably text
|
||||
packet.Type = TypeText
|
||||
packet.Text = string(payload)
|
||||
} else {
|
||||
// Probably binary
|
||||
packet.Type = TypeBinary
|
||||
}
|
||||
}
|
||||
if to, ok := packet.JSONData["to"].(string); ok {
|
||||
packet.ToNode = to
|
||||
}
|
||||
if text, ok := packet.JSONData["payload"].(string); ok {
|
||||
packet.Text = text
|
||||
}
|
||||
if ts, ok := packet.JSONData["timestamp"].(string); ok {
|
||||
packet.Timestamp = ts
|
||||
}
|
||||
} else if strings.Contains(topic, "/binary/") {
|
||||
// Binary protobuf payload
|
||||
packet.Type = TypeBinary
|
||||
// Note: Actual protobuf decoding would be done here using the
|
||||
// generated proto files, but it's a complex task since we need
|
||||
// to determine which message type to use.
|
||||
} else if strings.Contains(topic, "/text/") {
|
||||
// Plain text payload
|
||||
packet.Type = TypeText
|
||||
packet.Text = string(payload)
|
||||
}
|
||||
|
||||
return packet, nil
|
||||
}
|
||||
|
||||
// containsBinaryData does a simple check to see if a byte slice likely contains binary data
|
||||
// by checking for control characters that aren't common in text
|
||||
func containsBinaryData(data []byte) bool {
|
||||
for _, b := range data {
|
||||
// Skip common control characters
|
||||
if b == '\n' || b == '\r' || b == '\t' {
|
||||
continue
|
||||
}
|
||||
|
||||
// If we find a control character, it's probably binary data
|
||||
if b < 32 || b > 126 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// FormatPacket formats a decoded packet for display
|
||||
func FormatPacket(packet *DecodedPacket) string {
|
||||
var builder strings.Builder
|
||||
@@ -113,6 +168,30 @@ func FormatPacket(packet *DecodedPacket) string {
|
||||
case TypeText:
|
||||
builder.WriteString("Type: Text\n")
|
||||
builder.WriteString(fmt.Sprintf("Content: %s\n", packet.Text))
|
||||
|
||||
default:
|
||||
// Debug case for unknown packet types
|
||||
builder.WriteString(fmt.Sprintf("Type: UNKNOWN (%s)\n", packet.Type))
|
||||
builder.WriteString("---DEBUG INFO---\n")
|
||||
builder.WriteString(fmt.Sprintf("Raw Payload (%d bytes): %x\n", len(packet.RawData), packet.RawData))
|
||||
|
||||
// Try to show as string if possible
|
||||
if len(packet.RawData) > 0 {
|
||||
builder.WriteString(fmt.Sprintf("As String: %s\n", string(packet.RawData)))
|
||||
}
|
||||
|
||||
// Topic parts
|
||||
topicParts := strings.Split(packet.Topic, "/")
|
||||
builder.WriteString("Topic Parts:\n")
|
||||
for i, part := range topicParts {
|
||||
builder.WriteString(fmt.Sprintf(" [%d]: %s\n", i, part))
|
||||
}
|
||||
|
||||
// Show any JSON data if present
|
||||
if len(packet.JSONData) > 0 {
|
||||
jsonBytes, _ := json.MarshalIndent(packet.JSONData, "", " ")
|
||||
builder.WriteString(fmt.Sprintf("JSON Data: %s\n", jsonBytes))
|
||||
}
|
||||
}
|
||||
|
||||
return builder.String()
|
||||
|
||||
Reference in New Issue
Block a user