envelope.mx raw

   1  // Package envelope provides marshal/unmarshal for all nostr protocol envelope types.
   2  package envelope
   3  
   4  import (
   5  	"io"
   6  )
   7  
   8  // Identify extracts the label from a nostr envelope JSON array.
   9  func Identify(b []byte) (t string, rem []byte, err error) {
  10  	var openBrackets, openQuotes, afterQuotes bool
  11  	var label []byte
  12  	rem = b
  13  	for ; len(rem) > 0; rem = rem[1:] {
  14  		if !openBrackets && rem[0] == '[' {
  15  			openBrackets = true
  16  		} else if openBrackets {
  17  			if !openQuotes && rem[0] == '"' {
  18  				openQuotes = true
  19  			} else if afterQuotes {
  20  				if rem[0] == ',' {
  21  					rem = rem[1:]
  22  					return
  23  				}
  24  			} else if openQuotes {
  25  				for i := range rem {
  26  					if rem[i] == '"' {
  27  						label = rem[:i]
  28  						rem = rem[i:]
  29  						t = string(label)
  30  						afterQuotes = true
  31  						break
  32  					}
  33  				}
  34  			}
  35  		}
  36  	}
  37  	return
  38  }
  39  
  40  // Marshaller is a function signature for marshalling envelope content.
  41  type Marshaller func(dst []byte) (b []byte)
  42  
  43  // Marshal wraps content in a JSON array envelope with the given label.
  44  func Marshal(dst []byte, label string, m Marshaller) (b []byte) {
  45  	b = dst
  46  	b = append(b, '[', '"')
  47  	b = append(b, label...)
  48  	b = append(b, '"', ',')
  49  	b = m(b)
  50  	b = append(b, ']')
  51  	return
  52  }
  53  
  54  // SkipToTheEnd scans forward to the closing bracket of an envelope.
  55  func SkipToTheEnd(dst []byte) (rem []byte, err error) {
  56  	if len(dst) == 0 {
  57  		return
  58  	}
  59  	rem = dst
  60  	for ; len(rem) > 0; rem = rem[1:] {
  61  		if rem[0] == ']' {
  62  			rem = rem[:0]
  63  			return
  64  		}
  65  	}
  66  	err = io.EOF
  67  	return
  68  }
  69