event.mx raw

   1  package event
   2  
   3  import (
   4  	"bytes"
   5  	"crypto/sha256"
   6  	"encoding/hex"
   7  	"fmt"
   8  	"io"
   9  
  10  	"smesh.lol/pkg/nostr/ec/schnorr"
  11  	"smesh.lol/pkg/nostr/ints"
  12  	"smesh.lol/pkg/nostr/kind"
  13  	"smesh.lol/pkg/nostr/tag"
  14  	"smesh.lol/pkg/nostr/text"
  15  	"smesh.lol/pkg/lol/chk"
  16  	"smesh.lol/pkg/lol/errorf"
  17  )
  18  
  19  // E is the primary datatype of nostr.
  20  type E struct {
  21  	ID        []byte
  22  	Pubkey    []byte
  23  	CreatedAt int64
  24  	Kind      uint16
  25  	Tags      *tag.S
  26  	Content   []byte
  27  	Sig       []byte
  28  }
  29  
  30  var (
  31  	jId        = []byte("id")
  32  	jPubkey    = []byte("pubkey")
  33  	jCreatedAt = []byte("created_at")
  34  	jKind      = []byte("kind")
  35  	jTags      = []byte("tags")
  36  	jContent   = []byte("content")
  37  	jSig       = []byte("sig")
  38  )
  39  
  40  func New() *E { return &E{} }
  41  
  42  func (ev *E) Free() {
  43  	ev.ID = nil
  44  	ev.Pubkey = nil
  45  	ev.Tags = nil
  46  	ev.Content = nil
  47  	ev.Sig = nil
  48  }
  49  
  50  func (ev *E) Clone() *E {
  51  	clone := &E{CreatedAt: ev.CreatedAt, Kind: ev.Kind}
  52  	if ev.ID != nil {
  53  		clone.ID = []byte{:len(ev.ID)}
  54  		copy(clone.ID, ev.ID)
  55  	}
  56  	if ev.Pubkey != nil {
  57  		clone.Pubkey = []byte{:len(ev.Pubkey)}
  58  		copy(clone.Pubkey, ev.Pubkey)
  59  	}
  60  	if ev.Content != nil {
  61  		clone.Content = []byte{:len(ev.Content)}
  62  		copy(clone.Content, ev.Content)
  63  	}
  64  	if ev.Sig != nil {
  65  		clone.Sig = []byte{:len(ev.Sig)}
  66  		copy(clone.Sig, ev.Sig)
  67  	}
  68  	if ev.Tags != nil {
  69  		clone.Tags = tag.NewS()
  70  		for _, tg := range *ev.Tags {
  71  			if tg != nil {
  72  				newTag := tag.NewWithCap(len(tg.T))
  73  				for _, element := range tg.T {
  74  					e := []byte{:len(element)}
  75  					copy(e, element)
  76  					newTag.T = append(newTag.T, e)
  77  				}
  78  				clone.Tags.Append(newTag)
  79  			}
  80  		}
  81  	}
  82  	return clone
  83  }
  84  
  85  func (ev *E) EstimateSize() (size int) {
  86  	size = len(ev.ID)*2 + len(ev.Pubkey)*2 + len(ev.Sig)*2 + len(ev.Content)*2
  87  	if ev.Tags == nil {
  88  		return
  89  	}
  90  	for _, v := range *ev.Tags {
  91  		for _, w := range (*v).T {
  92  			size += len(w) * 2
  93  		}
  94  	}
  95  	return
  96  }
  97  
  98  func (ev *E) Marshal(dst []byte) (b []byte) {
  99  	b = dst
 100  	if b == nil {
 101  		b = []byte{:0:ev.EstimateSize()+100}
 102  	}
 103  	b = append(b, '{')
 104  	b = append(b, '"')
 105  	b = append(b, jId...)
 106  	b = append(b, `":"`...)
 107  	hexStart := len(b)
 108  	b = append(b, []byte{:2*sha256.Size}...)
 109  	hex.Encode(b[hexStart:], ev.ID)
 110  	b = append(b, `","`...)
 111  	b = append(b, jPubkey...)
 112  	b = append(b, `":"`...)
 113  	hexStart = len(b)
 114  	b = append(b, []byte{:2*schnorr.PubKeyBytesLen}...)
 115  	hex.Encode(b[hexStart:], ev.Pubkey)
 116  	b = append(b, `","`...)
 117  	b = append(b, jCreatedAt...)
 118  	b = append(b, `":`...)
 119  	b = ints.New(ev.CreatedAt).Marshal(b)
 120  	b = append(b, `,"`...)
 121  	b = append(b, jKind...)
 122  	b = append(b, `":`...)
 123  	b = ints.New(ev.Kind).Marshal(b)
 124  	b = append(b, `,"`...)
 125  	b = append(b, jTags...)
 126  	b = append(b, `":`...)
 127  	if ev.Tags != nil {
 128  		b = ev.Tags.Marshal(b)
 129  	} else {
 130  		b = append(b, '[', ']')
 131  	}
 132  	b = append(b, `,"`...)
 133  	b = append(b, jContent...)
 134  	b = append(b, `":"`...)
 135  	b = text.NostrEscape(b, ev.Content)
 136  	b = append(b, `","`...)
 137  	b = append(b, jSig...)
 138  	b = append(b, `":"`...)
 139  	if len(ev.Sig) > 0 {
 140  		hexStart = len(b)
 141  		b = append(b, []byte{:2*schnorr.SignatureSize}...)
 142  		hex.Encode(b[hexStart:], ev.Sig)
 143  	}
 144  	b = append(b, `"}`...)
 145  	return
 146  }
 147  
 148  func (ev *E) MarshalJSON() (b []byte, err error) {
 149  	b = ev.Marshal(nil)
 150  	return
 151  }
 152  
 153  func (ev *E) Serialize() (b []byte) { return ev.Marshal(nil) }
 154  
 155  func (ev *E) Unmarshal(b []byte) (rem []byte, err error) {
 156  	key := []byte{:0:9}
 157  	for ; len(b) > 0; b = b[1:] {
 158  		if isWhitespace(b[0]) {
 159  			continue
 160  		}
 161  		if b[0] == '{' {
 162  			b = b[1:]
 163  			goto BetweenKeys
 164  		}
 165  	}
 166  	goto eof
 167  BetweenKeys:
 168  	for ; len(b) > 0; b = b[1:] {
 169  		if isWhitespace(b[0]) {
 170  			continue
 171  		}
 172  		if b[0] == '"' {
 173  			b = b[1:]
 174  			goto InKey
 175  		}
 176  	}
 177  	goto eof
 178  InKey:
 179  	for ; len(b) > 0; b = b[1:] {
 180  		if b[0] == '"' {
 181  			b = b[1:]
 182  			goto InKV
 183  		}
 184  		key = append(key, b[0])
 185  	}
 186  	goto eof
 187  InKV:
 188  	for ; len(b) > 0; b = b[1:] {
 189  		if isWhitespace(b[0]) {
 190  			continue
 191  		}
 192  		if b[0] == ':' {
 193  			b = b[1:]
 194  			goto InVal
 195  		}
 196  	}
 197  	goto eof
 198  InVal:
 199  	for len(b) > 0 && isWhitespace(b[0]) {
 200  		b = b[1:]
 201  	}
 202  	switch key[0] {
 203  	case jId[0]:
 204  		if !bytes.Equal(jId, key) {
 205  			goto invalid
 206  		}
 207  		var id []byte
 208  		if id, b, err = text.UnmarshalHex(b); chk.E(err) {
 209  			return
 210  		}
 211  		if len(id) != sha256.Size {
 212  			err = errorf.E(
 213  				[]byte("invalid id, require %d got %d"), sha256.Size, len(id),
 214  			)
 215  			return
 216  		}
 217  		ev.ID = id
 218  		goto BetweenKV
 219  	case jPubkey[0]:
 220  		if !bytes.Equal(jPubkey, key) {
 221  			goto invalid
 222  		}
 223  		var pk []byte
 224  		if pk, b, err = text.UnmarshalHex(b); chk.E(err) {
 225  			return
 226  		}
 227  		if len(pk) != schnorr.PubKeyBytesLen {
 228  			err = errorf.E(
 229  				[]byte("invalid pubkey, require %d got %d"),
 230  				schnorr.PubKeyBytesLen, len(pk),
 231  			)
 232  			return
 233  		}
 234  		ev.Pubkey = pk
 235  		goto BetweenKV
 236  	case jKind[0]:
 237  		if !bytes.Equal(jKind, key) {
 238  			goto invalid
 239  		}
 240  		k := kind.New(0)
 241  		if b, err = k.Unmarshal(b); chk.E(err) {
 242  			return
 243  		}
 244  		ev.Kind = k.ToU16()
 245  		goto BetweenKV
 246  	case jTags[0]:
 247  		if !bytes.Equal(jTags, key) {
 248  			goto invalid
 249  		}
 250  		ev.Tags = tag.NewS()
 251  		if b, err = ev.Tags.Unmarshal(b); chk.E(err) {
 252  			return
 253  		}
 254  		goto BetweenKV
 255  	case jSig[0]:
 256  		if !bytes.Equal(jSig, key) {
 257  			goto invalid
 258  		}
 259  		var sig []byte
 260  		if sig, b, err = text.UnmarshalHex(b); chk.E(err) {
 261  			return
 262  		}
 263  		if len(sig) != 0 && len(sig) != schnorr.SignatureSize {
 264  			sig = nil
 265  		}
 266  		ev.Sig = sig
 267  		goto BetweenKV
 268  	case jContent[0]:
 269  		if key[1] == jContent[1] {
 270  			if !bytes.Equal(jContent, key) {
 271  				goto invalid
 272  			}
 273  			if ev.Content, b, err = text.UnmarshalQuoted(b); chk.T(err) {
 274  				return
 275  			}
 276  			goto BetweenKV
 277  		} else if key[1] == jCreatedAt[1] {
 278  			if !bytes.Equal(jCreatedAt, key) {
 279  				goto invalid
 280  			}
 281  			i := ints.New(0)
 282  			if b, err = i.Unmarshal(b); chk.T(err) {
 283  				return
 284  			}
 285  			ev.CreatedAt = i.Int64()
 286  			goto BetweenKV
 287  		} else {
 288  			goto invalid
 289  		}
 290  	default:
 291  		goto invalid
 292  	}
 293  BetweenKV:
 294  	key = key[:0]
 295  	for ; len(b) > 0; b = b[1:] {
 296  		if isWhitespace(b[0]) {
 297  			continue
 298  		}
 299  		switch {
 300  		case len(b) == 0:
 301  			return
 302  		case b[0] == '}':
 303  			b = b[1:]
 304  			goto AfterClose
 305  		case b[0] == ',':
 306  			b = b[1:]
 307  			goto BetweenKeys
 308  		case b[0] == '"':
 309  			b = b[1:]
 310  			goto InKey
 311  		}
 312  	}
 313  	goto AfterClose
 314  AfterClose:
 315  	rem = b
 316  	return
 317  invalid:
 318  	err = fmt.Errorf(
 319  		"invalid key,\n'%s'\n'%s'\n'%s'", string(b), string(b[:]),
 320  		string(b),
 321  	)
 322  	return
 323  eof:
 324  	err = io.EOF
 325  	return
 326  }
 327  
 328  func (ev *E) UnmarshalJSON(b []byte) (err error) {
 329  	_, err = ev.Unmarshal(b)
 330  	return
 331  }
 332  
 333  func isWhitespace(b byte) bool {
 334  	return b == ' ' || b == '\t' || b == '\n' || b == '\r'
 335  }
 336  
 337  // S is an array of event.E that sorts in reverse chronological order.
 338  type S []*E
 339  
 340  func (ev S) Len() int           { return len(ev) }
 341  func (ev S) Less(i, j int) bool { return ev[i].CreatedAt > ev[j].CreatedAt }
 342  func (ev S) Swap(i, j int)      { ev[i], ev[j] = ev[j], ev[i] }
 343  
 344  type C chan *E
 345