From cecc71cd81a8fb913a564af3e324d568112ea8ba Mon Sep 17 00:00:00 2001 From: fiatjaf <fiatjaf@gmail.com> Date: Wed, 12 Mar 2025 00:17:01 -0300 Subject: [PATCH] fix and improve envelope stuff again, deal with messages as strings on all envelope parsing steps. --- envelopes.go | 104 +++++++++++++++++------------------- envelopes_benchmark_test.go | 11 ++-- envelopes_default.go | 36 +++++++------ envelopes_sonic.go | 4 +- envelopes_test.go | 44 +++++++-------- helpers.go | 25 +++++---- helpers_test.go | 6 +-- nip77/envelopes.go | 36 +++++++------ nip77/idsonly.go | 2 +- nip77/nip77.go | 2 +- relay.go | 21 ++++---- 11 files changed, 151 insertions(+), 140 deletions(-) diff --git a/envelopes.go b/envelopes.go index c75402c..c2a52c9 100644 --- a/envelopes.go +++ b/envelopes.go @@ -1,81 +1,75 @@ package nostr import ( - "bytes" "encoding/hex" "errors" "fmt" "strconv" + "strings" + "unsafe" "github.com/mailru/easyjson" jwriter "github.com/mailru/easyjson/jwriter" "github.com/tidwall/gjson" ) -var ( - labelEvent = []byte("EVENT") - labelReq = []byte("REQ") - labelCount = []byte("COUNT") - labelNotice = []byte("NOTICE") - labelEose = []byte("EOSE") - labelOk = []byte("OK") - labelAuth = []byte("AUTH") - labelClosed = []byte("CLOSED") - labelClose = []byte("CLOSE") - - UnknownLabel = errors.New("unknown envelope label") -) +var UnknownLabel = errors.New("unknown envelope label") type MessageParser interface { // ParseMessage parses a message into an Envelope. - ParseMessage([]byte) (Envelope, error) + ParseMessage(string) (Envelope, error) } // Deprecated: use NewMessageParser instead -func ParseMessage(message []byte) Envelope { - firstComma := bytes.Index(message, []byte{','}) - if firstComma == -1 { +func ParseMessage(message string) Envelope { + firstQuote := strings.IndexRune(message, '"') + if firstQuote == -1 { return nil } - label := message[0:firstComma] + secondQuote := strings.IndexRune(message[firstQuote+1:], '"') + if secondQuote == -1 { + return nil + } + label := message[firstQuote+1 : firstQuote+1+secondQuote] var v Envelope - switch { - case bytes.Contains(label, labelEvent): + switch label { + case "EVENT": v = &EventEnvelope{} - case bytes.Contains(label, labelReq): + case "REQ": v = &ReqEnvelope{} - case bytes.Contains(label, labelCount): + case "COUNT": v = &CountEnvelope{} - case bytes.Contains(label, labelNotice): + case "NOTICE": x := NoticeEnvelope("") v = &x - case bytes.Contains(label, labelEose): + case "EOSE": x := EOSEEnvelope("") v = &x - case bytes.Contains(label, labelOk): + case "OK": v = &OKEnvelope{} - case bytes.Contains(label, labelAuth): + case "AUTH": v = &AuthEnvelope{} - case bytes.Contains(label, labelClosed): + case "CLOSED": v = &ClosedEnvelope{} - case bytes.Contains(label, labelClose): + case "CLOSE": x := CloseEnvelope("") v = &x default: return nil } - if err := v.UnmarshalJSON(message); err != nil { + if err := v.FromJSON(message); err != nil { return nil } + return v } // Envelope is the interface for all nostr message envelopes. type Envelope interface { Label() string - UnmarshalJSON([]byte) error + FromJSON(string) error MarshalJSON() ([]byte, error) String() string } @@ -99,15 +93,15 @@ type EventEnvelope struct { func (_ EventEnvelope) Label() string { return "EVENT" } -func (v *EventEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *EventEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() switch len(arr) { case 2: - return easyjson.Unmarshal([]byte(arr[1].Raw), &v.Event) + return easyjson.Unmarshal(unsafe.Slice(unsafe.StringData(arr[1].Raw), len(arr[1].Raw)), &v.Event) case 3: v.SubscriptionID = &arr[1].Str - return easyjson.Unmarshal([]byte(arr[2].Raw), &v.Event) + return easyjson.Unmarshal(unsafe.Slice(unsafe.StringData(arr[2].Raw), len(arr[2].Raw)), &v.Event) default: return fmt.Errorf("failed to decode EVENT envelope") } @@ -134,8 +128,8 @@ type ReqEnvelope struct { func (_ ReqEnvelope) Label() string { return "REQ" } -func (v *ReqEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *ReqEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) < 3 { return fmt.Errorf("failed to decode REQ envelope: missing filters") @@ -144,7 +138,7 @@ func (v *ReqEnvelope) UnmarshalJSON(data []byte) error { v.Filters = make(Filters, len(arr)-2) f := 0 for i := 2; i < len(arr); i++ { - if err := easyjson.Unmarshal([]byte(arr[i].Raw), &v.Filters[f]); err != nil { + if err := easyjson.Unmarshal(unsafe.Slice(unsafe.StringData(arr[i].Raw), len(arr[i].Raw)), &v.Filters[f]); err != nil { return fmt.Errorf("%w -- on filter %d", err, f) } f++ @@ -180,8 +174,8 @@ func (c CountEnvelope) String() string { return string(v) } -func (v *CountEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *CountEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) < 3 { return fmt.Errorf("failed to decode COUNT envelope: missing filters") @@ -192,7 +186,7 @@ func (v *CountEnvelope) UnmarshalJSON(data []byte) error { Count *int64 `json:"count"` HLL string `json:"hll"` } - if err := json.Unmarshal([]byte(arr[2].Raw), &countResult); err == nil && countResult.Count != nil { + if err := json.Unmarshal(unsafe.Slice(unsafe.StringData(arr[2].Raw), len(arr[2].Raw)), &countResult); err == nil && countResult.Count != nil { v.Count = countResult.Count if len(countResult.HLL) == 512 { v.HyperLogLog, err = hex.DecodeString(countResult.HLL) @@ -205,7 +199,7 @@ func (v *CountEnvelope) UnmarshalJSON(data []byte) error { f := 0 for i := 2; i < len(arr); i++ { - item := []byte(arr[i].Raw) + item := unsafe.Slice(unsafe.StringData(arr[i].Raw), len(arr[i].Raw)) if err := easyjson.Unmarshal(item, &v.Filter); err != nil { return fmt.Errorf("%w -- on filter %d", err, f) @@ -249,8 +243,8 @@ func (n NoticeEnvelope) String() string { return string(v) } -func (v *NoticeEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *NoticeEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) < 2 { return fmt.Errorf("failed to decode NOTICE envelope") @@ -276,8 +270,8 @@ func (e EOSEEnvelope) String() string { return string(v) } -func (v *EOSEEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *EOSEEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) < 2 { return fmt.Errorf("failed to decode EOSE envelope") @@ -303,8 +297,8 @@ func (c CloseEnvelope) String() string { return string(v) } -func (v *CloseEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *CloseEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() switch len(arr) { case 2: @@ -335,8 +329,8 @@ func (c ClosedEnvelope) String() string { return string(v) } -func (v *ClosedEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *ClosedEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() switch len(arr) { case 3: @@ -370,8 +364,8 @@ func (o OKEnvelope) String() string { return string(v) } -func (v *OKEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *OKEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) < 4 { return fmt.Errorf("failed to decode OK envelope: missing fields") @@ -411,14 +405,14 @@ func (a AuthEnvelope) String() string { return string(v) } -func (v *AuthEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *AuthEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) < 2 { return fmt.Errorf("failed to decode Auth envelope: missing fields") } if arr[1].IsObject() { - return easyjson.Unmarshal([]byte(arr[1].Raw), &v.Event) + return easyjson.Unmarshal(unsafe.Slice(unsafe.StringData(arr[1].Raw), len(arr[1].Raw)), &v.Event) } else { v.Challenge = &arr[1].Str } diff --git a/envelopes_benchmark_test.go b/envelopes_benchmark_test.go index 2121221..04127b8 100644 --- a/envelopes_benchmark_test.go +++ b/envelopes_benchmark_test.go @@ -1,3 +1,5 @@ +//go:build sonic + package nostr import ( @@ -6,6 +8,7 @@ import ( "math/rand/v2" "testing" "time" + "unsafe" ) func BenchmarkParseMessage(b *testing.B) { @@ -17,7 +20,7 @@ func BenchmarkParseMessage(b *testing.B) { for i := 0; i < b.N; i++ { for _, msg := range messages { var v any - stdlibjson.Unmarshal(msg, &v) + stdlibjson.Unmarshal(unsafe.Slice(unsafe.StringData(msg), len(msg)), &v) } } }) @@ -42,8 +45,8 @@ func BenchmarkParseMessage(b *testing.B) { } } -func generateTestMessages(typ string) [][]byte { - messages := make([][]byte, 0, 600) +func generateTestMessages(typ string) []string { + messages := make([]string, 0, 600) setup := map[string]map[int]func() []byte{ "client": { @@ -62,7 +65,7 @@ func generateTestMessages(typ string) [][]byte { for count, generator := range setup { for range count { - messages = append(messages, generator()) + messages = append(messages, string(generator())) } } diff --git a/envelopes_default.go b/envelopes_default.go index 379e647..089c038 100644 --- a/envelopes_default.go +++ b/envelopes_default.go @@ -3,8 +3,8 @@ package nostr import ( - "bytes" "errors" + "strings" ) func NewMessageParser() MessageParser { @@ -13,41 +13,45 @@ func NewMessageParser() MessageParser { type messageParser struct{} -func (messageParser) ParseMessage(message []byte) (Envelope, error) { - firstComma := bytes.Index(message, []byte{','}) - if firstComma == -1 { +func (messageParser) ParseMessage(message string) (Envelope, error) { + firstQuote := strings.IndexRune(message, '"') + if firstQuote == -1 { return nil, errors.New("malformed json") } - label := message[0:firstComma] + secondQuote := strings.IndexRune(message[firstQuote+1:], '"') + if secondQuote == -1 { + return nil, errors.New("malformed json") + } + label := message[firstQuote+1 : firstQuote+1+secondQuote] var v Envelope - switch { - case bytes.Contains(label, labelEvent): + switch label { + case "EVENT": v = &EventEnvelope{} - case bytes.Contains(label, labelReq): + case "REQ": v = &ReqEnvelope{} - case bytes.Contains(label, labelCount): + case "COUNT": v = &CountEnvelope{} - case bytes.Contains(label, labelNotice): + case "NOTICE": x := NoticeEnvelope("") v = &x - case bytes.Contains(label, labelEose): + case "EOSE": x := EOSEEnvelope("") v = &x - case bytes.Contains(label, labelOk): + case "OK": v = &OKEnvelope{} - case bytes.Contains(label, labelAuth): + case "AUTH": v = &AuthEnvelope{} - case bytes.Contains(label, labelClosed): + case "CLOSED": v = &ClosedEnvelope{} - case bytes.Contains(label, labelClose): + case "CLOSE": x := CloseEnvelope("") v = &x default: return nil, UnknownLabel } - if err := v.UnmarshalJSON(message); err != nil { + if err := v.FromJSON(message); err != nil { return nil, err } return v, nil diff --git a/envelopes_sonic.go b/envelopes_sonic.go index 369cc9a..43c8c5a 100644 --- a/envelopes_sonic.go +++ b/envelopes_sonic.go @@ -551,11 +551,11 @@ func (smp *sonicMessageParser) doneWithIntSlice(slice []int) { // When an unexpected message (like ["NEG-OPEN", ...]) is found, the error UnknownLabel will be // returned. Other errors will be returned if the JSON is malformed or the objects are not exactly // as they should. -func (smp sonicMessageParser) ParseMessage(message []byte) (Envelope, error) { +func (smp sonicMessageParser) ParseMessage(message string) (Envelope, error) { sv := &sonicVisitor{smp: &smp} sv.whereWeAre = inEnvelope - err := ast.Preorder(unsafe.String(unsafe.SliceData(message), len(message)), sv, nil) + err := ast.Preorder(message, sv, nil) return sv.mainEnvelope, err } diff --git a/envelopes_test.go b/envelopes_test.go index cb4b421..b9e54e8 100644 --- a/envelopes_test.go +++ b/envelopes_test.go @@ -1,3 +1,5 @@ +//go:build sonic + package nostr import ( @@ -11,97 +13,97 @@ import ( func TestParseMessage(t *testing.T) { testCases := []struct { Name string - Message []byte + Message string ExpectedEnvelope Envelope }{ { Name: "nil", - Message: nil, + Message: "", ExpectedEnvelope: nil, }, { Name: "invalid string", - Message: []byte("invalid input"), + Message: "invalid input", ExpectedEnvelope: nil, }, { Name: "invalid string with a comma", - Message: []byte("invalid, input"), + Message: "invalid, input", ExpectedEnvelope: nil, }, { Name: "EVENT envelope with subscription id", - Message: []byte(`["EVENT","_",{"kind":1,"id":"dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962","pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","created_at":1644271588,"tags":[],"content":"now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?","sig":"230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}]`), + Message: `["EVENT","_",{"kind":1,"id":"dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962","pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","created_at":1644271588,"tags":[],"content":"now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?","sig":"230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}]`, ExpectedEnvelope: &EventEnvelope{SubscriptionID: ptr("_"), Event: Event{Kind: 1, ID: "dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962", PubKey: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", CreatedAt: 1644271588, Tags: Tags{}, Content: "now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?", Sig: "230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}}, }, { Name: "EVENT envelope without subscription id", - Message: []byte(`["EVENT",{"kind":1,"id":"dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962","pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","created_at":1644271588,"tags":[],"content":"now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?","sig":"230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}]`), + Message: `["EVENT",{"kind":1,"id":"dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962","pubkey":"3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","created_at":1644271588,"tags":[],"content":"now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?","sig":"230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}]`, ExpectedEnvelope: &EventEnvelope{Event: Event{Kind: 1, ID: "dc90c95f09947507c1044e8f48bcf6350aa6bff1507dd4acfc755b9239b5c962", PubKey: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d", CreatedAt: 1644271588, Tags: Tags{}, Content: "now that https://blueskyweb.org/blog/2-7-2022-overview was announced we can stop working on nostr?", Sig: "230e9d8f0ddaf7eb70b5f7741ccfa37e87a455c9a469282e3464e2052d3192cd63a167e196e381ef9d7e69e9ea43af2443b839974dc85d8aaab9efe1d9296524"}}, }, { Name: "EVENT envelope with tags", - Message: []byte(`["EVENT",{"kind":3,"id":"9e662bdd7d8abc40b5b15ee1ff5e9320efc87e9274d8d440c58e6eed2dddfbe2","pubkey":"373ebe3d45ec91977296a178d9f19f326c70631d2a1b0bbba5c5ecc2eb53b9e7","created_at":1644844224,"tags":[["p","3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"],["e","75fc5ac2487363293bd27fb0d14fb966477d0f1dbc6361d37806a6a740eda91e"],["p","46d0dfd3a724a302ca9175163bdf788f3606b3fd1bb12d5fe055d1e418cb60ea"]],"content":"{\"wss://nostr-pub.wellorder.net\":{\"read\":true,\"write\":true},\"wss://nostr.bitcoiner.social\":{\"read\":false,\"write\":true},\"wss://expensive-relay.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relayer.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relay.bitid.nz\":{\"read\":true,\"write\":true},\"wss://nostr.rocks\":{\"read\":true,\"write\":true}}","sig":"811355d3484d375df47581cb5d66bed05002c2978894098304f20b595e571b7e01b2efd906c5650080ffe49cf1c62b36715698e9d88b9e8be43029a2f3fa66be"}]`), + Message: `["EVENT",{"kind":3,"id":"9e662bdd7d8abc40b5b15ee1ff5e9320efc87e9274d8d440c58e6eed2dddfbe2","pubkey":"373ebe3d45ec91977296a178d9f19f326c70631d2a1b0bbba5c5ecc2eb53b9e7","created_at":1644844224,"tags":[["p","3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"],["e","75fc5ac2487363293bd27fb0d14fb966477d0f1dbc6361d37806a6a740eda91e"],["p","46d0dfd3a724a302ca9175163bdf788f3606b3fd1bb12d5fe055d1e418cb60ea"]],"content":"{\"wss://nostr-pub.wellorder.net\":{\"read\":true,\"write\":true},\"wss://nostr.bitcoiner.social\":{\"read\":false,\"write\":true},\"wss://expensive-relay.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relayer.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relay.bitid.nz\":{\"read\":true,\"write\":true},\"wss://nostr.rocks\":{\"read\":true,\"write\":true}}","sig":"811355d3484d375df47581cb5d66bed05002c2978894098304f20b595e571b7e01b2efd906c5650080ffe49cf1c62b36715698e9d88b9e8be43029a2f3fa66be"}]`, ExpectedEnvelope: &EventEnvelope{Event: Event{Kind: 3, ID: "9e662bdd7d8abc40b5b15ee1ff5e9320efc87e9274d8d440c58e6eed2dddfbe2", PubKey: "373ebe3d45ec91977296a178d9f19f326c70631d2a1b0bbba5c5ecc2eb53b9e7", CreatedAt: 1644844224, Tags: Tags{Tag{"p", "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d"}, Tag{"e", "75fc5ac2487363293bd27fb0d14fb966477d0f1dbc6361d37806a6a740eda91e"}, Tag{"p", "46d0dfd3a724a302ca9175163bdf788f3606b3fd1bb12d5fe055d1e418cb60ea"}}, Content: "{\"wss://nostr-pub.wellorder.net\":{\"read\":true,\"write\":true},\"wss://nostr.bitcoiner.social\":{\"read\":false,\"write\":true},\"wss://expensive-relay.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relayer.fiatjaf.com\":{\"read\":true,\"write\":true},\"wss://relay.bitid.nz\":{\"read\":true,\"write\":true},\"wss://nostr.rocks\":{\"read\":true,\"write\":true}}", Sig: "811355d3484d375df47581cb5d66bed05002c2978894098304f20b595e571b7e01b2efd906c5650080ffe49cf1c62b36715698e9d88b9e8be43029a2f3fa66be"}}, }, { Name: "NOTICE envelope", - Message: []byte(`["NOTICE","kjasbdlasvdluiasvd\"kjasbdksab\\d"]`), + Message: `["NOTICE","kjasbdlasvdluiasvd\"kjasbdksab\\d"]`, ExpectedEnvelope: ptr(NoticeEnvelope("kjasbdlasvdluiasvd\"kjasbdksab\\d")), }, { Name: "EOSE envelope", - Message: []byte(`["EOSE","kjasbdlasvdluiasvd\"kjasbdksab\\d"]`), + Message: `["EOSE","kjasbdlasvdluiasvd\"kjasbdksab\\d"]`, ExpectedEnvelope: ptr(EOSEEnvelope("kjasbdlasvdluiasvd\"kjasbdksab\\d")), }, { Name: "COUNT envelope", - Message: []byte(`["COUNT","z",{"count":12}]`), + Message: `["COUNT","z",{"count":12}]`, ExpectedEnvelope: &CountEnvelope{SubscriptionID: "z", Count: ptr(int64(12))}, }, { Name: "COUNT envelope with HLL", - Message: []byte(`["COUNT","sub1",{"count":42, "hll": "0100000101000000000000040000000001020000000002000000000200000003000002040000000101020001010000000000000007000004010000000200040000020400000000000102000002000004010000010000000301000102030002000301000300010000070000000001000004000102010000000400010002000000000103000100010001000001040100020001000000000000010000020000000000030100000001000400010000000000000901010100000000040000000b030000010100010000010000010000000003000000000000010003000100020000000000010000010100000100000104000200030001000300000001000101000102"}]`), + Message: `["COUNT","sub1",{"count":42, "hll": "0100000101000000000000040000000001020000000002000000000200000003000002040000000101020001010000000000000007000004010000000200040000020400000000000102000002000004010000010000000301000102030002000301000300010000070000000001000004000102010000000400010002000000000103000100010001000001040100020001000000000000010000020000000000030100000001000400010000000000000901010100000000040000000b030000010100010000010000010000000003000000000000010003000100020000000000010000010100000100000104000200030001000300000001000101000102"}]`, ExpectedEnvelope: &CountEnvelope{SubscriptionID: "sub1", Count: ptr(int64(42)), HyperLogLog: []byte{1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 2, 4, 0, 0, 0, 1, 1, 2, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 4, 1, 0, 0, 0, 2, 0, 4, 0, 0, 2, 4, 0, 0, 0, 0, 0, 1, 2, 0, 0, 2, 0, 0, 4, 1, 0, 0, 1, 0, 0, 0, 3, 1, 0, 1, 2, 3, 0, 2, 0, 3, 1, 0, 3, 0, 1, 0, 0, 7, 0, 0, 0, 0, 1, 0, 0, 4, 0, 1, 2, 1, 0, 0, 0, 4, 0, 1, 0, 2, 0, 0, 0, 0, 1, 3, 0, 1, 0, 1, 0, 1, 0, 0, 1, 4, 1, 0, 2, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 2, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 1, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0, 9, 1, 1, 1, 0, 0, 0, 0, 4, 0, 0, 0, 11, 3, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 1, 0, 3, 0, 1, 0, 2, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 4, 0, 2, 0, 3, 0, 1, 0, 3, 0, 0, 0, 1, 0, 1, 1, 0, 1, 2}}, }, { Name: "OK envelope success", - Message: []byte(`["OK","3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefaaaaa",true,""]`), + Message: `["OK","3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefaaaaa",true,""]`, ExpectedEnvelope: &OKEnvelope{EventID: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefaaaaa", OK: true, Reason: ""}, }, { Name: "OK envelope failure", - Message: []byte(`["OK","3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefaaaaa",false,"error: could not connect to the database"]`), + Message: `["OK","3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefaaaaa",false,"error: could not connect to the database"]`, ExpectedEnvelope: &OKEnvelope{EventID: "3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefaaaaa", OK: false, Reason: "error: could not connect to the database"}, }, { Name: "CLOSED envelope with underscore", - Message: []byte(`["CLOSED","_","error: something went wrong"]`), + Message: `["CLOSED","_","error: something went wrong"]`, ExpectedEnvelope: &ClosedEnvelope{SubscriptionID: "_", Reason: "error: something went wrong"}, }, { Name: "CLOSED envelope with colon", - Message: []byte(`["CLOSED",":1","auth-required: take a selfie and send it to the CIA"]`), + Message: `["CLOSED",":1","auth-required: take a selfie and send it to the CIA"]`, ExpectedEnvelope: &ClosedEnvelope{SubscriptionID: ":1", Reason: "auth-required: take a selfie and send it to the CIA"}, }, { Name: "AUTH envelope with challenge", - Message: []byte(`["AUTH","kjsabdlasb aslkd kasndkad \"as.kdnbskadb"]`), + Message: `["AUTH","kjsabdlasb aslkd kasndkad \"as.kdnbskadb"]`, ExpectedEnvelope: &AuthEnvelope{Challenge: ptr("kjsabdlasb aslkd kasndkad \"as.kdnbskadb")}, }, { Name: "AUTH envelope with event", - Message: []byte(`["AUTH",{"kind":1,"id":"ae1fc7154296569d87ca4663f6bdf448c217d1590d28c85d158557b8b43b4d69","pubkey":"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","created_at":1683660344,"tags":[],"content":"hello world","sig":"94e10947814b1ebe38af42300ecd90c7642763896c4f69506ae97bfdf54eec3c0c21df96b7d95daa74ff3d414b1d758ee95fc258125deebc31df0c6ba9396a51"}]`), + Message: `["AUTH",{"kind":1,"id":"ae1fc7154296569d87ca4663f6bdf448c217d1590d28c85d158557b8b43b4d69","pubkey":"79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","created_at":1683660344,"tags":[],"content":"hello world","sig":"94e10947814b1ebe38af42300ecd90c7642763896c4f69506ae97bfdf54eec3c0c21df96b7d95daa74ff3d414b1d758ee95fc258125deebc31df0c6ba9396a51"}]`, ExpectedEnvelope: &AuthEnvelope{Event: Event{Kind: 1, ID: "ae1fc7154296569d87ca4663f6bdf448c217d1590d28c85d158557b8b43b4d69", PubKey: "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798", CreatedAt: 1683660344, Tags: Tags{}, Content: "hello world", Sig: "94e10947814b1ebe38af42300ecd90c7642763896c4f69506ae97bfdf54eec3c0c21df96b7d95daa74ff3d414b1d758ee95fc258125deebc31df0c6ba9396a51"}}, }, { Name: "REQ envelope", - Message: []byte(`["REQ","million", {"kinds": [1]}, {"kinds": [30023 ], "#d": ["buteko", "batuke"]}]`), + Message: `["REQ","million", {"kinds": [1]}, {"kinds": [30023 ], "#d": ["buteko", "batuke"]}]`, ExpectedEnvelope: &ReqEnvelope{SubscriptionID: "million", Filters: Filters{{Kinds: []int{1}}, {Kinds: []int{30023}, Tags: TagMap{"d": []string{"buteko", "batuke"}}}}}, }, { Name: "CLOSE envelope", - Message: []byte(`["CLOSE","subscription123"]`), + Message: `["CLOSE","subscription123"]`, ExpectedEnvelope: ptr(CloseEnvelope("subscription123")), }, } @@ -168,8 +170,8 @@ func TestParseMessagesFromFile(t *testing.T) { continue } - standardEnvelope := ParseMessage(line) - sonicEnvelope, err := smp.ParseMessage(line) + standardEnvelope := ParseMessage(string(line)) + sonicEnvelope, err := smp.ParseMessage(string(line)) if standardEnvelope == nil { require.Nil(t, sonicEnvelope, "line %d: standard parser returned nil but sonic parser didn't", lineNum) diff --git a/helpers.go b/helpers.go index fe68d8b..c0bd969 100644 --- a/helpers.go +++ b/helpers.go @@ -1,7 +1,6 @@ package nostr import ( - "bytes" "strconv" "strings" "sync" @@ -119,35 +118,39 @@ func isLowerHex(thing string) bool { return true } -func extractSubID(jsonStr []byte) string { +func extractSubID(jsonStr string) string { // look for "EVENT" pattern - start := bytes.Index(jsonStr, []byte(`"EVENT"`)) + start := strings.Index(jsonStr, `"EVENT"`) if start == -1 { return "" } // move to the next quote - offset := bytes.Index(jsonStr[start+7:], []byte{'"'}) + offset := strings.Index(jsonStr[start+7:], `"`) + if offset == -1 { + return "" + } + start += 7 + offset + 1 // find the ending quote - end := bytes.Index(jsonStr[start:], []byte{'"'}) + end := strings.Index(jsonStr[start:], `"`) // get the contents - return unsafe.String(unsafe.SliceData(jsonStr[start:start+end]), end) + return jsonStr[start : start+end] } -func extractEventID(jsonStr []byte) string { - // look for "id": pattern - start := bytes.Index(jsonStr, []byte(`"id":`)) +func extractEventID(jsonStr string) string { + // look for "id" pattern + start := strings.Index(jsonStr, `"id"`) if start == -1 { return "" } // move to the next quote - offset := bytes.Index(jsonStr[start+4:], []byte{'"'}) + offset := strings.IndexRune(jsonStr[start+4:], '"') start += 4 + offset + 1 // get 64 characters of the id - return unsafe.String(unsafe.SliceData(jsonStr[start:start+64]), 64) + return jsonStr[start : start+64] } diff --git a/helpers_test.go b/helpers_test.go index 88d248e..1bf6fc0 100644 --- a/helpers_test.go +++ b/helpers_test.go @@ -27,18 +27,18 @@ func TestIsLower(t *testing.T) { func TestIDExtract(t *testing.T) { { - data := []byte(`{"kind":1,"id":"6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16","pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","created_at":1736909072,"tags":[["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638"}`) + data := `{"kind":1,"id":"6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16","pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","created_at":1736909072,"tags":[["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638"}` require.Equal(t, "6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16", extractEventID(data)) } { - data := []byte(`{"kind":1,"pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","created_at":1736909072,"tags":[["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638","id": "6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16" }`) + data := `{"kind":1,"pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","created_at":1736909072,"tags":[["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638","id": "6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16" }` require.Equal(t, "6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16", extractEventID(data)) } } func TestSubIdExtract(t *testing.T) { { - data := []byte(`["EVENT", "xxz" ,{"kind":1,"id":"6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16","pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","created_at":1736909072,"tags":[["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638"}]`) + data := `["EVENT", "xxz" ,{"kind":1,"id":"6b5988e9471fa340880a40df815befc69c901420facfb670acd8308012088f16","pubkey":"67ada8e344532cbf82f0e702472e24c7896e0e1c96235eacbaaa4b8616052171","created_at":1736909072,"tags":[["e","cfdf18b78527455097515545be4ccbe17e9b88f64539a566c632e405e2c0d08a","","root"],["e","f1ec9c301383be082f1860f7e24e49164d855bfab67f8e5c3ed17f6f3f867cca","","reply"],["p","1afe0c74e3d7784eba93a5e3fa554a6eeb01928d12739ae8ba4832786808e36d"],["p","8aa642e26e65072139e10db59646a89aa7538a59965aab3ed89191d71967d6c3"],["p","f4d89779148ccd245c8d50914a284fd62d97cb0fb68b797a70f24a172b522db9"],["p","18905d0a5d623ab81a98ba98c582bd5f57f2506c6b808905fc599d5a0b229b08"],["p","9a0e2043afaa056a12b8bbe77ac4c3185c0e2bc46b12aac158689144323c0e3c"],["p","45f195cffcb8c9724efc248f0507a2fb65b579dfabe7cd35398598163cab7627"]],"content":"🫡","sig":"d21aaf43963b07a3cb5f85ac8809c2b2e4dd3269195f4d810e1b7650895178fe01cf685ab3ee93f193cdde1f8d17419ff05332c6e3fc7429bbbe3d70016b8638"}]` require.Equal(t, "xxz", extractSubID(data)) } } diff --git a/nip77/envelopes.go b/nip77/envelopes.go index b870c57..2b5603e 100644 --- a/nip77/envelopes.go +++ b/nip77/envelopes.go @@ -3,6 +3,8 @@ package nip77 import ( "bytes" "fmt" + "strings" + "unsafe" "github.com/mailru/easyjson" jwriter "github.com/mailru/easyjson/jwriter" @@ -10,28 +12,28 @@ import ( "github.com/tidwall/gjson" ) -func ParseNegMessage(message []byte) nostr.Envelope { - firstComma := bytes.Index(message, []byte{','}) +func ParseNegMessage(message string) nostr.Envelope { + firstComma := strings.Index(message, ",") if firstComma == -1 { return nil } label := message[0:firstComma] var v nostr.Envelope - switch { - case bytes.Contains(label, []byte("NEG-MSG")): + switch label { + case "NEG-MSG": v = &MessageEnvelope{} - case bytes.Contains(label, []byte("NEG-OPEN")): + case "NEG-OPEN": v = &OpenEnvelope{} - case bytes.Contains(label, []byte("NEG-ERR")): + case "NEG-ERR": v = &ErrorEnvelope{} - case bytes.Contains(label, []byte("NEG-CLOSE")): + case "NEG-CLOSE": v = &CloseEnvelope{} default: return nil } - if err := v.UnmarshalJSON(message); err != nil { + if err := v.FromJSON(message); err != nil { return nil } return v @@ -56,8 +58,8 @@ func (v OpenEnvelope) String() string { return string(b) } -func (v *OpenEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *OpenEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) != 4 { return fmt.Errorf("failed to decode NEG-OPEN envelope") @@ -65,7 +67,7 @@ func (v *OpenEnvelope) UnmarshalJSON(data []byte) error { v.SubscriptionID = arr[1].Str v.Message = arr[3].Str - return easyjson.Unmarshal([]byte(arr[2].Raw), &v.Filter) + return easyjson.Unmarshal(unsafe.Slice(unsafe.StringData(arr[2].Raw), len(arr[2].Raw)), &v.Filter) } func (v OpenEnvelope) MarshalJSON() ([]byte, error) { @@ -97,8 +99,8 @@ func (v MessageEnvelope) String() string { return string(b) } -func (v *MessageEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *MessageEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) < 3 { return fmt.Errorf("failed to decode NEG-MSG envelope") @@ -130,8 +132,8 @@ func (v CloseEnvelope) String() string { return string(b) } -func (v *CloseEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *CloseEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) < 2 { return fmt.Errorf("failed to decode NEG-CLOSE envelope") @@ -159,8 +161,8 @@ func (v ErrorEnvelope) String() string { return string(b) } -func (v *ErrorEnvelope) UnmarshalJSON(data []byte) error { - r := gjson.ParseBytes(data) +func (v *ErrorEnvelope) FromJSON(data string) error { + r := gjson.Parse(data) arr := r.Array() if len(arr) < 3 { return fmt.Errorf("failed to decode NEG-ERROR envelope") diff --git a/nip77/idsonly.go b/nip77/idsonly.go index e50ee8f..0bd7781 100644 --- a/nip77/idsonly.go +++ b/nip77/idsonly.go @@ -20,7 +20,7 @@ func FetchIDsOnly( result := make(chan error) var r *nostr.Relay - r, err := nostr.RelayConnect(ctx, url, nostr.WithCustomHandler(func(data []byte) { + r, err := nostr.RelayConnect(ctx, url, nostr.WithCustomHandler(func(data string) { envelope := ParseNegMessage(data) if envelope == nil { return diff --git a/nip77/nip77.go b/nip77/nip77.go index a6374af..a4e078c 100644 --- a/nip77/nip77.go +++ b/nip77/nip77.go @@ -49,7 +49,7 @@ func NegentropySync( result := make(chan error) var r *nostr.Relay - r, err = nostr.RelayConnect(ctx, url, nostr.WithCustomHandler(func(data []byte) { + r, err = nostr.RelayConnect(ctx, url, nostr.WithCustomHandler(func(data string) { envelope := ParseNegMessage(data) if envelope == nil { return diff --git a/relay.go b/relay.go index 48e720e..d02d340 100644 --- a/relay.go +++ b/relay.go @@ -13,6 +13,7 @@ import ( "sync" "sync/atomic" "time" + "unsafe" "github.com/puzpuzpuz/xsync/v3" ) @@ -35,7 +36,7 @@ type Relay struct { challenge string // NIP-42 challenge, we only keep the last noticeHandler func(string) // NIP-01 NOTICEs - customHandler func([]byte) // nonstandard unparseable messages + customHandler func(string) // nonstandard unparseable messages okCallbacks *xsync.MapOf[string, func(bool, string)] writeQueue chan writeRequest subscriptionChannelCloseQueue chan *Subscription @@ -104,7 +105,7 @@ func (nh WithNoticeHandler) ApplyRelayOption(r *Relay) { // WithCustomHandler must be a function that handles any relay message that couldn't be // parsed as a standard envelope. -type WithCustomHandler func(data []byte) +type WithCustomHandler func(data string) func (ch WithCustomHandler) ApplyRelayOption(r *Relay) { r.customHandler = ch @@ -212,6 +213,7 @@ func (r *Relay) ConnectWithTLS(ctx context.Context, tlsConfig *tls.Config) error // general message reader loop go func() { buf := new(bytes.Buffer) + mp := NewMessageParser() for { buf.Reset() @@ -222,7 +224,8 @@ func (r *Relay) ConnectWithTLS(ctx context.Context, tlsConfig *tls.Config) error break } - message := buf.Bytes() + msgb := buf.Bytes() + message := unsafe.String(unsafe.SliceData(msgb), len(msgb)) debugLogf("{%s} received %v\n", r.URL, message) // if this is an "EVENT" we will have this preparser logic that should speed things up a little @@ -235,9 +238,9 @@ func (r *Relay) ConnectWithTLS(ctx context.Context, tlsConfig *tls.Config) error } } - envelope := ParseMessage(message) + envelope, err := mp.ParseMessage(message) if envelope == nil { - if r.customHandler != nil { + if r.customHandler != nil && err == UnknownLabel { r.customHandler(message) } continue @@ -258,13 +261,13 @@ func (r *Relay) ConnectWithTLS(ctx context.Context, tlsConfig *tls.Config) error r.challenge = *env.Challenge case *EventEnvelope: // we already have the subscription from the pre-check above, so we can just reuse it - if subscription == nil { + if sub == nil { // InfoLogger.Printf("{%s} no subscription with id '%s'\n", r.URL, *env.SubscriptionID) continue } else { // check if the event matches the desired filter, ignore otherwise - if !subscription.match(&env.Event) { - InfoLogger.Printf("{%s} filter does not match: %v ~ %v\n", r.URL, subscription.Filters, env.Event) + if !sub.match(&env.Event) { + InfoLogger.Printf("{%s} filter does not match: %v ~ %v\n", r.URL, sub.Filters, env.Event) continue } @@ -277,7 +280,7 @@ func (r *Relay) ConnectWithTLS(ctx context.Context, tlsConfig *tls.Config) error } // dispatch this to the internal .events channel of the subscription - subscription.dispatchEvent(&env.Event) + sub.dispatchEvent(&env.Event) } case *EOSEEnvelope: if subscription, ok := r.Subscriptions.Load(subIdToSerial(string(*env))); ok {