mirror of
https://github.com/dpup/meshstream.git
synced 2026-08-11 11:12:53 +02:00
Update decoder to handle ServiceEnvelope for encoded packets and improve format handling
This commit is contained in:
@@ -10,7 +10,7 @@ msh/REGION_PATH/2/e/CHANNELNAME/USERID
|
|||||||
- `msh`: Fixed prefix for all Meshtastic topics
|
- `msh`: Fixed prefix for all Meshtastic topics
|
||||||
- `REGION_PATH`: Geographic region path which can include multiple segments (e.g., `US/CA/Motherlode`, `EU`, etc.)
|
- `REGION_PATH`: Geographic region path which can include multiple segments (e.g., `US/CA/Motherlode`, `EU`, etc.)
|
||||||
- `2`: Protocol version
|
- `2`: Protocol version
|
||||||
- `e`: Encrypted channel indicator (versions before 2.3.0 used `/c/` instead)
|
- `e`: Encoded packet format (formerly used `c` for channel in versions before 2.3.0)
|
||||||
- `CHANNELNAME`: The channel name used in the Meshtastic network
|
- `CHANNELNAME`: The channel name used in the Meshtastic network
|
||||||
- `USERID`: Unique identifier for the device, formats include:
|
- `USERID`: Unique identifier for the device, formats include:
|
||||||
- `!` followed by hex characters for MAC address based IDs
|
- `!` followed by hex characters for MAC address based IDs
|
||||||
@@ -18,10 +18,13 @@ msh/REGION_PATH/2/e/CHANNELNAME/USERID
|
|||||||
|
|
||||||
## Message Types
|
## Message Types
|
||||||
|
|
||||||
### Protobuf Messages (Binary)
|
### Encoded Messages (ServiceEnvelope)
|
||||||
Topic pattern: `msh/REGION_PATH/2/e/CHANNELNAME/USERID`
|
Topic pattern: `msh/REGION_PATH/2/e/CHANNELNAME/USERID`
|
||||||
- Raw MeshPacket transmissions in protobuf format
|
- ServiceEnvelope protobuf messages
|
||||||
- Can be encrypted or unencrypted based on channel settings
|
- Contains:
|
||||||
|
- A MeshPacket (can be encrypted or unencrypted)
|
||||||
|
- channel_id: The global channel ID it was sent on
|
||||||
|
- gateway_id: Node ID of the gateway that relayed the message
|
||||||
|
|
||||||
### JSON Messages
|
### JSON Messages
|
||||||
Topic pattern: `msh/REGION_PATH/2/json/CHANNELNAME/USERID`
|
Topic pattern: `msh/REGION_PATH/2/json/CHANNELNAME/USERID`
|
||||||
|
|||||||
+92
-12
@@ -11,13 +11,14 @@ import (
|
|||||||
type PacketType string
|
type PacketType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TypeJSON PacketType = "json"
|
TypeJSON PacketType = "json"
|
||||||
TypeBinary PacketType = "binary"
|
TypeEncoded PacketType = "encoded"
|
||||||
TypeText PacketType = "text"
|
TypeText PacketType = "text"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DecodedPacket contains information about a decoded packet
|
// DecodedPacket contains information about a decoded packet
|
||||||
type DecodedPacket struct {
|
type DecodedPacket struct {
|
||||||
|
// Topic structure fields
|
||||||
Topic string
|
Topic string
|
||||||
RegionPath string
|
RegionPath string
|
||||||
Version string
|
Version string
|
||||||
@@ -25,12 +26,21 @@ type DecodedPacket struct {
|
|||||||
Channel string
|
Channel string
|
||||||
UserID string
|
UserID string
|
||||||
Type PacketType
|
Type PacketType
|
||||||
|
|
||||||
|
// JSON message fields
|
||||||
JSONData map[string]interface{}
|
JSONData map[string]interface{}
|
||||||
FromNode string
|
FromNode string
|
||||||
ToNode string
|
ToNode string
|
||||||
Text string
|
Text string
|
||||||
RawData []byte
|
|
||||||
Timestamp string
|
Timestamp string
|
||||||
|
|
||||||
|
// Encoded message fields
|
||||||
|
ChannelID string
|
||||||
|
GatewayID string
|
||||||
|
PacketID string
|
||||||
|
|
||||||
|
// Raw data
|
||||||
|
RawData []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecodePacket attempts to decode a packet from MQTT
|
// DecodePacket attempts to decode a packet from MQTT
|
||||||
@@ -90,9 +100,51 @@ func DecodePacket(topic string, payload []byte) (*DecodedPacket, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Process based on format type
|
// Process based on format type
|
||||||
if packet.Format == "e" || packet.Format == "c" {
|
if packet.Format == "e" {
|
||||||
// Binary protobuf packet
|
// Encoded protobuf packet (using ServiceEnvelope)
|
||||||
packet.Type = TypeBinary
|
packet.Type = TypeEncoded
|
||||||
|
|
||||||
|
// For encoded packets, try to parse if the payload looks like a JSON ServiceEnvelope
|
||||||
|
// (Some gateways present ServiceEnvelope in JSON format)
|
||||||
|
if len(payload) > 0 && payload[0] == '{' {
|
||||||
|
var serviceEnvelope map[string]interface{}
|
||||||
|
if err := json.Unmarshal(payload, &serviceEnvelope); err == nil {
|
||||||
|
// Successfully parsed as JSON ServiceEnvelope
|
||||||
|
packet.JSONData = serviceEnvelope
|
||||||
|
|
||||||
|
// Extract ServiceEnvelope metadata fields
|
||||||
|
if channelId, ok := serviceEnvelope["channel_id"].(string); ok {
|
||||||
|
packet.ChannelID = channelId
|
||||||
|
}
|
||||||
|
if gatewayId, ok := serviceEnvelope["gateway_id"].(string); ok {
|
||||||
|
packet.GatewayID = gatewayId
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to extract data from the packet field
|
||||||
|
if packetData, ok := serviceEnvelope["packet"].(map[string]interface{}); ok {
|
||||||
|
if id, ok := packetData["id"].(float64); ok {
|
||||||
|
packet.PacketID = fmt.Sprintf("%d", int(id))
|
||||||
|
}
|
||||||
|
if from, ok := packetData["from"].(float64); ok {
|
||||||
|
packet.FromNode = fmt.Sprintf("%d", int(from))
|
||||||
|
}
|
||||||
|
if to, ok := packetData["to"].(float64); ok {
|
||||||
|
packet.ToNode = fmt.Sprintf("%d", int(to))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to extract decoded payload if available
|
||||||
|
if decoded, ok := packetData["decoded"].(map[string]interface{}); ok {
|
||||||
|
if payload, ok := decoded["payload"].(string); ok {
|
||||||
|
packet.Text = payload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: For binary protocol buffer decoding we would need to use the generated protobuf code,
|
||||||
|
// but we'll defer that for now and just track that this is an encoded packet.
|
||||||
|
|
||||||
} else if packet.Format == "json" {
|
} else if packet.Format == "json" {
|
||||||
// JSON format
|
// JSON format
|
||||||
packet.Type = TypeJSON
|
packet.Type = TypeJSON
|
||||||
@@ -140,8 +192,8 @@ func DecodePacket(topic string, payload []byte) (*DecodedPacket, error) {
|
|||||||
packet.Type = TypeText
|
packet.Type = TypeText
|
||||||
packet.Text = string(payload)
|
packet.Text = string(payload)
|
||||||
} else {
|
} else {
|
||||||
// Probably binary
|
// Encoded but not in JSON format
|
||||||
packet.Type = TypeBinary
|
packet.Type = TypeEncoded
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,9 +258,37 @@ func FormatPacket(packet *DecodedPacket) string {
|
|||||||
jsonBytes, _ := json.MarshalIndent(packet.JSONData, "", " ")
|
jsonBytes, _ := json.MarshalIndent(packet.JSONData, "", " ")
|
||||||
builder.WriteString(fmt.Sprintf("Data: %s\n", jsonBytes))
|
builder.WriteString(fmt.Sprintf("Data: %s\n", jsonBytes))
|
||||||
|
|
||||||
case TypeBinary:
|
case TypeEncoded:
|
||||||
builder.WriteString("Type: Binary\n")
|
builder.WriteString("Type: Encoded (ServiceEnvelope)\n")
|
||||||
builder.WriteString(fmt.Sprintf("Hex: %x\n", packet.RawData))
|
|
||||||
|
// Display ServiceEnvelope metadata if available
|
||||||
|
if packet.ChannelID != "" {
|
||||||
|
builder.WriteString(fmt.Sprintf("Channel ID: %s\n", packet.ChannelID))
|
||||||
|
}
|
||||||
|
if packet.GatewayID != "" {
|
||||||
|
builder.WriteString(fmt.Sprintf("Gateway ID: %s\n", packet.GatewayID))
|
||||||
|
}
|
||||||
|
if packet.PacketID != "" {
|
||||||
|
builder.WriteString(fmt.Sprintf("Packet ID: %s\n", packet.PacketID))
|
||||||
|
}
|
||||||
|
if packet.FromNode != "" {
|
||||||
|
builder.WriteString(fmt.Sprintf("From Node: %s\n", packet.FromNode))
|
||||||
|
}
|
||||||
|
if packet.ToNode != "" {
|
||||||
|
builder.WriteString(fmt.Sprintf("To Node: %s\n", packet.ToNode))
|
||||||
|
}
|
||||||
|
if packet.Text != "" {
|
||||||
|
builder.WriteString(fmt.Sprintf("Payload: %s\n", packet.Text))
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we were able to parse as JSON, show the data
|
||||||
|
if len(packet.JSONData) > 0 {
|
||||||
|
jsonBytes, _ := json.MarshalIndent(packet.JSONData, "", " ")
|
||||||
|
builder.WriteString(fmt.Sprintf("Service Envelope: %s\n", jsonBytes))
|
||||||
|
} else {
|
||||||
|
// Show raw binary data
|
||||||
|
builder.WriteString(fmt.Sprintf("Raw Data (%d bytes): %x\n", len(packet.RawData), packet.RawData))
|
||||||
|
}
|
||||||
|
|
||||||
case TypeText:
|
case TypeText:
|
||||||
builder.WriteString("Type: Text\n")
|
builder.WriteString("Type: Text\n")
|
||||||
|
|||||||
Reference in New Issue
Block a user