binary.mx raw

   1  package event
   2  
   3  import (
   4  	"bytes"
   5  	"io"
   6  
   7  	"crypto/secp256k1"
   8  	"git.smesh.lol/nostr/pkg/tag"
   9  	"git.smesh.lol/nostr/pkg/varint"
  10  	"git.smesh.lol/nostr/pkg/lol/chk"
  11  )
  12  
  13  func (ev *E) MarshalBinary(w io.Writer) {
  14  	_, _ = w.Write(ev.ID)
  15  	_, _ = w.Write(ev.Pubkey)
  16  	varint.Encode(w, uint64(ev.CreatedAt))
  17  	varint.Encode(w, uint64(ev.Kind))
  18  	if ev.Tags == nil {
  19  		varint.Encode(w, 0)
  20  	} else {
  21  		varint.Encode(w, uint64(ev.Tags.Len()))
  22  		for _, x := range ev.Tags.T {
  23  			varint.Encode(w, uint64(x.Len()))
  24  			for _, y := range x.T {
  25  				varint.Encode(w, uint64(len(y)))
  26  				_, _ = w.Write(y)
  27  			}
  28  		}
  29  	}
  30  	varint.Encode(w, uint64(len(ev.Content)))
  31  	_, _ = w.Write(ev.Content)
  32  	_, _ = w.Write(ev.Sig)
  33  }
  34  
  35  func (ev *E) MarshalBinaryToBytes(dst []byte) (out []byte) {
  36  	var buf *bytes.Buffer
  37  	if dst == nil {
  38  		size := 32 + 32 + 10 + 10 + 64
  39  		if ev.Tags != nil {
  40  			for _, t := range ev.Tags.T {
  41  				size += 10
  42  				for _, elem := range t.T {
  43  					size += 10 + len(elem)
  44  				}
  45  			}
  46  		}
  47  		size += 10 + len(ev.Content)
  48  		b := []byte{:0:size}
  49  		buf = bytes.NewBuffer(b)
  50  	} else {
  51  		buf = bytes.NewBuffer(dst[:0])
  52  	}
  53  	ev.MarshalBinary(buf)
  54  	return buf.Bytes()
  55  }
  56  
  57  // readFull reads exactly len(buf) bytes. io.Reader.Read may return a short
  58  // count with a nil error, so a truncated frame used to decode into a
  59  // zero-padded field and look like a valid event; io.ReadFull turns that into
  60  // ErrUnexpectedEOF.
  61  func readFull(r io.Reader, buf []byte) (err error) {
  62  	if _, err = io.ReadFull(r, buf); chk.E(err) {
  63  		return
  64  	}
  65  	return
  66  }
  67  
  68  func (ev *E) UnmarshalBinary(r io.Reader) (err error) {
  69  	ev.ID = []byte{:32}
  70  	if err = readFull(r, ev.ID); chk.E(err) {
  71  		return
  72  	}
  73  	ev.Pubkey = []byte{:32}
  74  	if err = readFull(r, ev.Pubkey); chk.E(err) {
  75  		return
  76  	}
  77  	var ca uint64
  78  	if ca, err = varint.Decode(r); chk.E(err) {
  79  		return
  80  	}
  81  	ev.CreatedAt = int64(ca)
  82  	var k uint64
  83  	if k, err = varint.Decode(r); chk.E(err) {
  84  		return
  85  	}
  86  	ev.Kind = uint16(k)
  87  	var nTags uint64
  88  	if nTags, err = varint.Decode(r); chk.E(err) {
  89  		return
  90  	}
  91  	// Declared outside the loops: a declaration in the body of a self-mutating
  92  	// method allocates in the sovereign arena on every iteration.
  93  	var nField uint64
  94  	var t *tag.T
  95  	var lenField uint64
  96  	var field []byte
  97  	if nTags == 0 {
  98  		ev.Tags = nil
  99  	} else {
 100  		ev.Tags = tag.NewSWithCap(int32(nTags))
 101  		for range nTags {
 102  			if nField, err = varint.Decode(r); chk.E(err) {
 103  				return
 104  			}
 105  			t = tag.NewWithCap(int32(nField))
 106  			for range nField {
 107  				if lenField, err = varint.Decode(r); chk.E(err) {
 108  					return
 109  				}
 110  				field = []byte{:lenField}
 111  				if err = readFull(r, field); chk.E(err) {
 112  					return
 113  				}
 114  				t.T = push(t.T, field)
 115  			}
 116  			ev.Tags.T = push(ev.Tags.T, t)
 117  		}
 118  	}
 119  	var cLen uint64
 120  	if cLen, err = varint.Decode(r); chk.E(err) {
 121  		return
 122  	}
 123  	ev.Content = []byte{:cLen}
 124  	if err = readFull(r, ev.Content); chk.E(err) {
 125  		return
 126  	}
 127  	ev.Sig = []byte{:secp256k1.SignatureSize}
 128  	if err = readFull(r, ev.Sig); chk.E(err) {
 129  		return
 130  	}
 131  	return
 132  }
 133