mirror of
https://github.com/dpup/meshstream.git
synced 2026-08-07 01:03:10 +02:00
Another checkpoint moving to proto defined packets
This commit is contained in:
+35
-25
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/dpup/prefab/logging"
|
||||
|
||||
"meshstream/decoder"
|
||||
meshtreampb "meshstream/generated/meshstream"
|
||||
)
|
||||
|
||||
// TestBrokerSubscribeUnsubscribe tests the basic subscribe and unsubscribe functionality
|
||||
@@ -38,8 +38,10 @@ func TestBrokerSubscribeUnsubscribe(t *testing.T) {
|
||||
|
||||
// First packet with ID 1
|
||||
packet1 := &Packet{
|
||||
DecodedPacket: &decoder.DecodedPacket{ID: 1},
|
||||
TopicInfo: &decoder.TopicInfo{},
|
||||
Packet: &meshtreampb.Packet{
|
||||
Data: &meshtreampb.Data{Id: 1},
|
||||
Info: &meshtreampb.TopicInfo{},
|
||||
},
|
||||
}
|
||||
|
||||
// Send the packet
|
||||
@@ -48,8 +50,8 @@ func TestBrokerSubscribeUnsubscribe(t *testing.T) {
|
||||
// Both subscribers should receive the packet
|
||||
select {
|
||||
case received := <-subscriber1:
|
||||
if received.ID != 1 {
|
||||
t.Errorf("Expected subscriber1 to receive packet with ID 1, got %d", received.ID)
|
||||
if received.Data.Id != 1 {
|
||||
t.Errorf("Expected subscriber1 to receive packet with ID 1, got %d", received.Data.Id)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Error("subscriber1 didn't receive packet within timeout")
|
||||
@@ -57,8 +59,8 @@ func TestBrokerSubscribeUnsubscribe(t *testing.T) {
|
||||
|
||||
select {
|
||||
case received := <-subscriber2:
|
||||
if received.ID != 1 {
|
||||
t.Errorf("Expected subscriber2 to receive packet with ID 1, got %d", received.ID)
|
||||
if received.Data.Id != 1 {
|
||||
t.Errorf("Expected subscriber2 to receive packet with ID 1, got %d", received.Data.Id)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Error("subscriber2 didn't receive packet within timeout")
|
||||
@@ -78,8 +80,10 @@ func TestBrokerSubscribeUnsubscribe(t *testing.T) {
|
||||
|
||||
// Second packet with ID 2
|
||||
packet2 := &Packet{
|
||||
DecodedPacket: &decoder.DecodedPacket{ID: 2},
|
||||
TopicInfo: &decoder.TopicInfo{},
|
||||
Packet: &meshtreampb.Packet{
|
||||
Data: &meshtreampb.Data{Id: 2},
|
||||
Info: &meshtreampb.TopicInfo{},
|
||||
},
|
||||
}
|
||||
|
||||
// Send the second packet
|
||||
@@ -88,8 +92,8 @@ func TestBrokerSubscribeUnsubscribe(t *testing.T) {
|
||||
// The second subscriber should receive the packet
|
||||
select {
|
||||
case received := <-subscriber2:
|
||||
if received.ID != 2 {
|
||||
t.Errorf("Expected subscriber2 to receive packet with ID 2, got %d", received.ID)
|
||||
if received.Data.Id != 2 {
|
||||
t.Errorf("Expected subscriber2 to receive packet with ID 2, got %d", received.Data.Id)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Error("subscriber2 didn't receive second packet within timeout")
|
||||
@@ -115,8 +119,10 @@ func TestBrokerMultipleSubscribers(t *testing.T) {
|
||||
|
||||
// Send a test packet with ID 42
|
||||
testPacket := &Packet{
|
||||
DecodedPacket: &decoder.DecodedPacket{ID: 42},
|
||||
TopicInfo: &decoder.TopicInfo{},
|
||||
Packet: &meshtreampb.Packet{
|
||||
Data: &meshtreampb.Data{Id: 42},
|
||||
Info: &meshtreampb.TopicInfo{},
|
||||
},
|
||||
}
|
||||
sourceChan <- testPacket
|
||||
|
||||
@@ -129,8 +135,8 @@ func TestBrokerMultipleSubscribers(t *testing.T) {
|
||||
defer wg.Done()
|
||||
select {
|
||||
case received := <-ch:
|
||||
if received.ID != 42 {
|
||||
t.Errorf("subscriber %d expected packet ID 42, got %d", idx, received.ID)
|
||||
if received.Data.Id != 42 {
|
||||
t.Errorf("subscriber %d expected packet ID 42, got %d", idx, received.Data.Id)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Errorf("subscriber %d didn't receive packet within timeout", idx)
|
||||
@@ -169,12 +175,16 @@ func TestBrokerSlowSubscriber(t *testing.T) {
|
||||
|
||||
// Send two packets quickly to fill the slow subscriber's buffer
|
||||
testPacket1 := &Packet{
|
||||
DecodedPacket: &decoder.DecodedPacket{ID: 101},
|
||||
TopicInfo: &decoder.TopicInfo{},
|
||||
Packet: &meshtreampb.Packet{
|
||||
Data: &meshtreampb.Data{Id: 101},
|
||||
Info: &meshtreampb.TopicInfo{},
|
||||
},
|
||||
}
|
||||
testPacket2 := &Packet{
|
||||
DecodedPacket: &decoder.DecodedPacket{ID: 102},
|
||||
TopicInfo: &decoder.TopicInfo{},
|
||||
Packet: &meshtreampb.Packet{
|
||||
Data: &meshtreampb.Data{Id: 102},
|
||||
Info: &meshtreampb.TopicInfo{},
|
||||
},
|
||||
}
|
||||
|
||||
sourceChan <- testPacket1
|
||||
@@ -187,8 +197,8 @@ func TestBrokerSlowSubscriber(t *testing.T) {
|
||||
// The normal subscriber should receive both packets
|
||||
select {
|
||||
case received := <-normalSubscriber:
|
||||
if received.ID != 101 {
|
||||
t.Errorf("normalSubscriber expected packet ID 101, got %d", received.ID)
|
||||
if received.Data.Id != 101 {
|
||||
t.Errorf("normalSubscriber expected packet ID 101, got %d", received.Data.Id)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Error("normalSubscriber didn't receive first packet within timeout")
|
||||
@@ -196,8 +206,8 @@ func TestBrokerSlowSubscriber(t *testing.T) {
|
||||
|
||||
select {
|
||||
case received := <-normalSubscriber:
|
||||
if received.ID != 102 {
|
||||
t.Errorf("normalSubscriber expected packet ID 102, got %d", received.ID)
|
||||
if received.Data.Id != 102 {
|
||||
t.Errorf("normalSubscriber expected packet ID 102, got %d", received.Data.Id)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Error("normalSubscriber didn't receive second packet within timeout")
|
||||
@@ -206,8 +216,8 @@ func TestBrokerSlowSubscriber(t *testing.T) {
|
||||
// The slow subscriber should receive at least the first packet
|
||||
select {
|
||||
case received := <-slowSubscriber:
|
||||
if received.ID != 101 {
|
||||
t.Errorf("slowSubscriber expected packet ID 101, got %d", received.ID)
|
||||
if received.Data.Id != 101 {
|
||||
t.Errorf("slowSubscriber expected packet ID 101, got %d", received.Data.Id)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Error("slowSubscriber didn't receive first packet within timeout")
|
||||
|
||||
+3
-4
@@ -8,7 +8,6 @@ import (
|
||||
mqtt "github.com/eclipse/paho.mqtt.golang"
|
||||
|
||||
"meshstream/decoder"
|
||||
mesh "meshstream/proto/generated"
|
||||
)
|
||||
|
||||
// Config holds configuration for the MQTT client
|
||||
@@ -99,10 +98,10 @@ func (c *Client) messageHandler(client mqtt.Client, msg mqtt.Message) {
|
||||
switch topicInfo.Format {
|
||||
case "e", "c", "map":
|
||||
// Binary encoded protobuf message
|
||||
decodedPacket := decoder.DecodeMessage(msg.Payload(), topicInfo)
|
||||
data := decoder.DecodeMessage(msg.Payload(), topicInfo)
|
||||
|
||||
// Create packet with both the decoded packet and topic info
|
||||
packet := NewPacket(decodedPacket, topicInfo)
|
||||
// Create packet with both the data and topic info
|
||||
packet := NewPacket(data, topicInfo)
|
||||
|
||||
// Send the decoded message to the channel, but don't block if buffer is full
|
||||
select {
|
||||
|
||||
+23
-23
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
"github.com/dpup/prefab/logging"
|
||||
|
||||
pb "meshstream/proto/generated/meshtastic"
|
||||
pb "meshstream/generated/meshtastic"
|
||||
)
|
||||
|
||||
// MessageLogger logs messages using the provided logger
|
||||
@@ -44,23 +44,23 @@ func NewMessageLogger(broker *Broker, briefMode bool, logger logging.Logger) (*M
|
||||
func (ml *MessageLogger) getBriefSummary(packet *Packet) string {
|
||||
var summary string
|
||||
|
||||
if packet.DecodedPacket.DecodeError != nil {
|
||||
return fmt.Sprintf("Error decoding packet: %v", packet.DecodedPacket.DecodeError)
|
||||
if packet.Data.DecodeError != "" {
|
||||
return fmt.Sprintf("Error decoding packet: %v", packet.Data.DecodeError)
|
||||
}
|
||||
|
||||
// Create a basic summary based on the port type
|
||||
switch packet.PortNum {
|
||||
switch packet.Data.PortNum {
|
||||
case pb.PortNum_TEXT_MESSAGE_APP:
|
||||
// For text messages, include the text content
|
||||
if text, ok := packet.Payload.(string); ok {
|
||||
summary = fmt.Sprintf("Text message: %s", text)
|
||||
if packet.Data.GetTextMessage() != "" {
|
||||
summary = fmt.Sprintf("Text message: %s", packet.Data.GetTextMessage())
|
||||
} else {
|
||||
summary = "Text message (invalid format)"
|
||||
}
|
||||
|
||||
case pb.PortNum_POSITION_APP:
|
||||
// For position messages, include a compact location summary
|
||||
if pos, ok := packet.Payload.(*pb.Position); ok {
|
||||
if pos := packet.Data.GetPosition(); pos != nil {
|
||||
lat := float64(pos.GetLatitudeI()) / 10000000.0
|
||||
lon := float64(pos.GetLongitudeI()) / 10000000.0
|
||||
summary = fmt.Sprintf("Position: %.5f, %.5f", lat, lon)
|
||||
@@ -70,7 +70,7 @@ func (ml *MessageLogger) getBriefSummary(packet *Packet) string {
|
||||
|
||||
case pb.PortNum_TELEMETRY_APP:
|
||||
// For telemetry, give a short summary of what's included
|
||||
if telemetry, ok := packet.Payload.(*pb.Telemetry); ok {
|
||||
if telemetry := packet.Data.GetTelemetry(); telemetry != nil {
|
||||
parts := []string{}
|
||||
if telemetry.GetEnvironmentMetrics() != nil {
|
||||
parts = append(parts, "environment")
|
||||
@@ -88,7 +88,7 @@ func (ml *MessageLogger) getBriefSummary(packet *Packet) string {
|
||||
|
||||
default:
|
||||
// For other types, just mention the port type
|
||||
summary = fmt.Sprintf("Message type: %s", packet.PortNum.String())
|
||||
summary = fmt.Sprintf("Message type: %s", packet.Data.PortNum.String())
|
||||
}
|
||||
|
||||
return summary
|
||||
@@ -100,30 +100,30 @@ func (ml *MessageLogger) logMessage(packet *Packet) {
|
||||
briefSummary := ml.getBriefSummary(packet)
|
||||
|
||||
// Build the message prefix with type and GatewayID info for brief mode
|
||||
typePrefix := fmt.Sprintf("[%s]", packet.PortNum.String())
|
||||
if packet.GatewayID != "" {
|
||||
briefSummary = fmt.Sprintf("%s Gateway:%s %s", typePrefix, packet.GatewayID, briefSummary)
|
||||
typePrefix := fmt.Sprintf("[%s]", packet.Data.PortNum.String())
|
||||
if packet.Data.GatewayId != "" {
|
||||
briefSummary = fmt.Sprintf("%s Gateway:%s %s", typePrefix, packet.Data.GatewayId, briefSummary)
|
||||
} else {
|
||||
briefSummary = fmt.Sprintf("%s %s", typePrefix, briefSummary)
|
||||
}
|
||||
|
||||
if ml.briefMode {
|
||||
fields := []interface{}{
|
||||
"portNum", packet.PortNum.String(),
|
||||
"from", packet.From,
|
||||
"to", packet.To,
|
||||
"gateway", packet.GatewayID,
|
||||
"channel", packet.TopicInfo.Channel,
|
||||
"region", packet.TopicInfo.RegionPath,
|
||||
"hopLimit", packet.HopLimit,
|
||||
"id", packet.ID,
|
||||
"portNum", packet.Data.PortNum.String(),
|
||||
"from", packet.Data.From,
|
||||
"to", packet.Data.To,
|
||||
"gateway", packet.Data.GatewayId,
|
||||
"channel", packet.Info.Channel,
|
||||
"region", packet.Info.RegionPath,
|
||||
"hopLimit", packet.Data.HopLimit,
|
||||
"id", packet.Data.Id,
|
||||
}
|
||||
if packet.DecodedPacket.DecodeError != nil {
|
||||
fields = append(fields, "error", packet.DecodedPacket.DecodeError.Error())
|
||||
if packet.Data.DecodeError != "" {
|
||||
fields = append(fields, "error", packet.Data.DecodeError)
|
||||
}
|
||||
ml.logger.Infow(briefSummary, fields...)
|
||||
} else {
|
||||
ml.logger.Infow(briefSummary, "packet", packet)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+11
-145
@@ -1,151 +1,17 @@
|
||||
package mqtt
|
||||
|
||||
import (
|
||||
mesh "meshstream/proto/generated"
|
||||
meshtreampb "meshstream/generated/meshstream"
|
||||
)
|
||||
|
||||
// Packet extends the DecodedPacket with MQTT topic information
|
||||
type Packet struct {
|
||||
*mesh.Packet
|
||||
// Type alias for proto packet.
|
||||
type Packet meshtreampb.Packet
|
||||
|
||||
// NewPacket creates a Packet from a data packet and topic info
|
||||
func NewPacket(data *meshtreampb.Data, topicInfo *meshtreampb.TopicInfo) *Packet {
|
||||
p := Packet(meshtreampb.Packet{
|
||||
Data: data,
|
||||
Info: topicInfo,
|
||||
})
|
||||
return &p
|
||||
}
|
||||
|
||||
// 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 ""
|
||||
}
|
||||
+4
-4
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
"github.com/dpup/prefab/logging"
|
||||
|
||||
pb "meshstream/proto/generated/meshtastic"
|
||||
pb "meshstream/generated/meshtastic"
|
||||
)
|
||||
|
||||
// MessageStats tracks statistics about received messages
|
||||
@@ -71,10 +71,10 @@ func (s *MessageStats) recordMessage(packet *Packet) {
|
||||
s.TotalMessages++
|
||||
|
||||
// Count by source node
|
||||
s.ByNode[packet.From]++
|
||||
s.ByNode[packet.Data.From]++
|
||||
|
||||
// Count by port type
|
||||
s.ByPortType[packet.PortNum]++
|
||||
s.ByPortType[packet.Data.PortNum]++
|
||||
}
|
||||
|
||||
// PrintStats logs current statistics using the structured logger
|
||||
@@ -122,4 +122,4 @@ func (s *MessageStats) PrintStats() {
|
||||
s.ByNode = make(map[uint32]int)
|
||||
s.ByPortType = make(map[pb.PortNum]int)
|
||||
s.LastStatsPrinted = now
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user