well-goknown/vendor/github.com/nbd-wtf/go-nostr/nip77/envelopes.go
2024-11-18 19:32:21 -05:00

182 lines
4.1 KiB
Go

package nip77
import (
"bytes"
"fmt"
"github.com/mailru/easyjson"
jwriter "github.com/mailru/easyjson/jwriter"
"github.com/nbd-wtf/go-nostr"
"github.com/tidwall/gjson"
)
func ParseNegMessage(message []byte) nostr.Envelope {
firstComma := bytes.Index(message, []byte{','})
if firstComma == -1 {
return nil
}
label := message[0:firstComma]
var v nostr.Envelope
switch {
case bytes.Contains(label, []byte("NEG-MSG")):
v = &MessageEnvelope{}
case bytes.Contains(label, []byte("NEG-OPEN")):
v = &OpenEnvelope{}
case bytes.Contains(label, []byte("NEG-ERR")):
v = &ErrorEnvelope{}
case bytes.Contains(label, []byte("NEG-CLOSE")):
v = &CloseEnvelope{}
default:
return nil
}
if err := v.UnmarshalJSON(message); err != nil {
return nil
}
return v
}
var (
_ nostr.Envelope = (*OpenEnvelope)(nil)
_ nostr.Envelope = (*MessageEnvelope)(nil)
_ nostr.Envelope = (*CloseEnvelope)(nil)
_ nostr.Envelope = (*ErrorEnvelope)(nil)
)
type OpenEnvelope struct {
SubscriptionID string
Filter nostr.Filter
Message string
}
func (_ OpenEnvelope) Label() string { return "NEG-OPEN" }
func (v OpenEnvelope) String() string {
b, _ := v.MarshalJSON()
return string(b)
}
func (v *OpenEnvelope) UnmarshalJSON(data []byte) error {
r := gjson.ParseBytes(data)
arr := r.Array()
if len(arr) != 4 {
return fmt.Errorf("failed to decode NEG-OPEN envelope")
}
v.SubscriptionID = arr[1].Str
v.Message = arr[3].Str
return easyjson.Unmarshal([]byte(arr[2].Raw), &v.Filter)
}
func (v OpenEnvelope) MarshalJSON() ([]byte, error) {
res := bytes.NewBuffer(make([]byte, 0, 17+len(v.SubscriptionID)+len(v.Message)+500))
res.WriteString(`["NEG-OPEN","`)
res.WriteString(v.SubscriptionID)
res.WriteString(`",`)
w := jwriter.Writer{NoEscapeHTML: true}
v.Filter.MarshalEasyJSON(&w)
w.Buffer.DumpTo(res)
res.WriteString(`,"`)
res.WriteString(v.Message)
res.WriteString(`"]`)
return res.Bytes(), nil
}
type MessageEnvelope struct {
SubscriptionID string
Message string
}
func (_ MessageEnvelope) Label() string { return "NEG-MSG" }
func (v MessageEnvelope) String() string {
b, _ := v.MarshalJSON()
return string(b)
}
func (v *MessageEnvelope) UnmarshalJSON(data []byte) error {
r := gjson.ParseBytes(data)
arr := r.Array()
if len(arr) < 3 {
return fmt.Errorf("failed to decode NEG-MSG envelope")
}
v.SubscriptionID = arr[1].Str
v.Message = arr[2].Str
return nil
}
func (v MessageEnvelope) MarshalJSON() ([]byte, error) {
res := bytes.NewBuffer(make([]byte, 0, 17+len(v.SubscriptionID)+len(v.Message)))
res.WriteString(`["NEG-MSG","`)
res.WriteString(v.SubscriptionID)
res.WriteString(`","`)
res.WriteString(v.Message)
res.WriteString(`"]`)
return res.Bytes(), nil
}
type CloseEnvelope struct {
SubscriptionID string
}
func (_ CloseEnvelope) Label() string { return "NEG-CLOSE" }
func (v CloseEnvelope) String() string {
b, _ := v.MarshalJSON()
return string(b)
}
func (v *CloseEnvelope) UnmarshalJSON(data []byte) error {
r := gjson.ParseBytes(data)
arr := r.Array()
if len(arr) < 2 {
return fmt.Errorf("failed to decode NEG-CLOSE envelope")
}
v.SubscriptionID = arr[1].Str
return nil
}
func (v CloseEnvelope) MarshalJSON() ([]byte, error) {
res := bytes.NewBuffer(make([]byte, 0, 14+len(v.SubscriptionID)))
res.WriteString(`["NEG-CLOSE","`)
res.WriteString(v.SubscriptionID)
res.WriteString(`"]`)
return res.Bytes(), nil
}
type ErrorEnvelope struct {
SubscriptionID string
Reason string
}
func (_ ErrorEnvelope) Label() string { return "NEG-ERROR" }
func (v ErrorEnvelope) String() string {
b, _ := v.MarshalJSON()
return string(b)
}
func (v *ErrorEnvelope) UnmarshalJSON(data []byte) error {
r := gjson.ParseBytes(data)
arr := r.Array()
if len(arr) < 3 {
return fmt.Errorf("failed to decode NEG-ERROR envelope")
}
v.SubscriptionID = arr[1].Str
v.Reason = arr[2].Str
return nil
}
func (v ErrorEnvelope) MarshalJSON() ([]byte, error) {
res := bytes.NewBuffer(make([]byte, 0, 19+len(v.SubscriptionID)+len(v.Reason)))
res.WriteString(`["NEG-ERROR","`)
res.WriteString(v.SubscriptionID)
res.WriteString(`","`)
res.WriteString(v.Reason)
res.WriteString(`"]`)
return res.Bytes(), nil
}