diff --git a/bot_service.go b/bot_service.go index 7b340c4..c004ab2 100644 --- a/bot_service.go +++ b/bot_service.go @@ -270,6 +270,14 @@ func (s *botService) PublishNodeInfo(_ context.Context, bot botNodeRecord) error if err := s.server.Publish(topic, raw, false, 0); err != nil { return err } + if s.store != nil { + valid, _, record := mqtpp.MQTTPP(topic, raw, key, mqtpp.Options{AllowEncryptedForwarding: true}) + if valid && record["type"] == "nodeinfo" { + if err := s.store.UpsertNodeInfo(record); err != nil { + return err + } + } + } return s.store.UpdateBotNodeInfoBroadcastAt(bot.ID, time.Now()) } diff --git a/mqtpp/builder.go b/mqtpp/builder.go index 25f23ed..40c7dbe 100644 --- a/mqtpp/builder.go +++ b/mqtpp/builder.go @@ -70,12 +70,18 @@ func BuildNodeInfoServiceEnvelope(opts NodeInfoBuildOptions) ([]byte, error) { if opts.NodeID == "" { opts.NodeID = NodeNumToID(opts.FromNodeNum) } - if strings.TrimSpace(opts.LongName) == "" { + opts.NodeID = truncateUTF8Bytes(opts.NodeID, 16) + opts.LongName = truncateUTF8Bytes(strings.TrimSpace(opts.LongName), 40) + opts.ShortName = truncateUTF8Bytes(strings.TrimSpace(opts.ShortName), 5) + if opts.LongName == "" { return nil, fmt.Errorf("long name is required") } - if strings.TrimSpace(opts.ShortName) == "" { + if opts.ShortName == "" { return nil, fmt.Errorf("short name is required") } + if len(opts.PublicKey) > 32 { + opts.PublicKey = opts.PublicKey[:32] + } user := buildUserPacket(opts) data := buildDataPacket(nodeInfoApp, user) packet, err := buildMeshPacket(opts.PacketBuildOptions, data) @@ -89,6 +95,21 @@ func NodeNumToID(nodeNum uint32) string { return nodeNumToID(nodeNum) } +func truncateUTF8Bytes(value string, maxBytes int) string { + if maxBytes <= 0 || len(value) <= maxBytes { + return value + } + out := make([]byte, 0, maxBytes) + for _, r := range value { + part := string(r) + if len(out)+len(part) > maxBytes { + break + } + out = append(out, part...) + } + return string(out) +} + func ParseNodeID(nodeID string) (uint32, error) { value := strings.TrimSpace(nodeID) if value == "" { diff --git a/mqtpp/builder_test.go b/mqtpp/builder_test.go index ed6a1ad..bfc4c29 100644 --- a/mqtpp/builder_test.go +++ b/mqtpp/builder_test.go @@ -140,6 +140,33 @@ func TestBuildNodeInfoServiceEnvelopeRoundTrip(t *testing.T) { } } +func TestBuildNodeInfoTruncatesNanopbStrings(t *testing.T) { + key, err := ExpandPSK("AQ==") + if err != nil { + t.Fatalf("ExpandPSK() error = %v", err) + } + + raw, err := BuildNodeInfoServiceEnvelope(NodeInfoBuildOptions{ + PacketBuildOptions: PacketBuildOptions{FromNodeNum: 0x12345678, ToNodeNum: NodeNumBroadcast, PacketID: 0x33333333, ChannelID: "LongFast", GatewayID: "!12345678", PSK: key, Encrypt: true, ViaMQTT: true}, + NodeID: "!12345678", + LongName: "这是一个非常非常非常非常长的机器人节点名称", + ShortName: "机器人", + }) + if err != nil { + t.Fatalf("BuildNodeInfoServiceEnvelope() error = %v", err) + } + valid, _, record := MQTTPP("msh/2/e/LongFast/!12345678", raw, key, Options{}) + if !valid { + t.Fatalf("MQTTPP() valid = false, record = %#v", record) + } + if len([]byte(record["long_name"].(string))) > 40 { + t.Fatalf("long_name byte length = %d", len([]byte(record["long_name"].(string)))) + } + if len([]byte(record["short_name"].(string))) > 5 { + t.Fatalf("short_name byte length = %d", len([]byte(record["short_name"].(string)))) + } +} + func TestParseNodeID(t *testing.T) { num, err := ParseNodeID("!1234abcd") if err != nil {