diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 14827b9..9877a4c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,4 +18,4 @@ jobs: with: go-version-file: ./go.mod - - run: go test ./... + - run: go test ./... -tags=sonic diff --git a/envelopes.go b/envelopes.go index c838e4e..c75402c 100644 --- a/envelopes.go +++ b/envelopes.go @@ -26,7 +26,12 @@ var ( UnknownLabel = errors.New("unknown envelope label") ) -// ParseMessage parses a message into an Envelope. +type MessageParser interface { + // ParseMessage parses a message into an Envelope. + ParseMessage([]byte) (Envelope, error) +} + +// Deprecated: use NewMessageParser instead func ParseMessage(message []byte) Envelope { firstComma := bytes.Index(message, []byte{','}) if firstComma == -1 { diff --git a/envelopes_default.go b/envelopes_default.go new file mode 100644 index 0000000..379e647 --- /dev/null +++ b/envelopes_default.go @@ -0,0 +1,54 @@ +//go:build !sonic + +package nostr + +import ( + "bytes" + "errors" +) + +func NewMessageParser() MessageParser { + return messageParser{} +} + +type messageParser struct{} + +func (messageParser) ParseMessage(message []byte) (Envelope, error) { + firstComma := bytes.Index(message, []byte{','}) + if firstComma == -1 { + return nil, errors.New("malformed json") + } + label := message[0:firstComma] + + var v Envelope + switch { + case bytes.Contains(label, labelEvent): + v = &EventEnvelope{} + case bytes.Contains(label, labelReq): + v = &ReqEnvelope{} + case bytes.Contains(label, labelCount): + v = &CountEnvelope{} + case bytes.Contains(label, labelNotice): + x := NoticeEnvelope("") + v = &x + case bytes.Contains(label, labelEose): + x := EOSEEnvelope("") + v = &x + case bytes.Contains(label, labelOk): + v = &OKEnvelope{} + case bytes.Contains(label, labelAuth): + v = &AuthEnvelope{} + case bytes.Contains(label, labelClosed): + v = &ClosedEnvelope{} + case bytes.Contains(label, labelClose): + x := CloseEnvelope("") + v = &x + default: + return nil, UnknownLabel + } + + if err := v.UnmarshalJSON(message); err != nil { + return nil, err + } + return v, nil +} diff --git a/envelopes_sonic.go b/envelopes_sonic.go index 0ff6942..369cc9a 100644 --- a/envelopes_sonic.go +++ b/envelopes_sonic.go @@ -1,3 +1,5 @@ +//go:build sonic + package nostr import ( @@ -360,6 +362,8 @@ func (sv *sonicVisitor) OnString(v string) error { sv.whereWeAre = inClosed case "NOTICE": sv.whereWeAre = inNotice + default: + return UnknownLabel } // in an envelope @@ -483,9 +487,9 @@ type sonicMessageParser struct { reusableIntArray []int } -// NewSonicMessageParser returns a sonicMessageParser object that is intended to be reused many times. +// NewMessageParser returns a sonicMessageParser object that is intended to be reused many times. // It is not goroutine-safe. -func NewSonicMessageParser() sonicMessageParser { +func NewMessageParser() sonicMessageParser { return sonicMessageParser{ reusableFilterArray: make([]Filter, 0, 1000), reusableTagArray: make([]Tag, 0, 10000), @@ -494,6 +498,8 @@ func NewSonicMessageParser() sonicMessageParser { } } +var NewSonicMessageParser = NewMessageParser + func (smp *sonicMessageParser) doneWithFilterSlice(slice []Filter) { if unsafe.SliceData(smp.reusableFilterArray) == unsafe.SliceData(slice) { smp.reusableFilterArray = slice[len(slice):]