ackchually generates events

This commit is contained in:
2025-02-20 19:13:48 -01:06
parent ec19703727
commit 64bd999cdd
24 changed files with 431 additions and 70 deletions

5
go.mod
View File

@@ -8,11 +8,14 @@ require (
go.uber.org/atomic v1.11.0
golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3
lukechampine.com/frand v1.5.1
realy.lol v1.7.13
)
require (
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/templexxx/cpu v0.1.1 // indirect
github.com/templexxx/xhex v0.0.0-20200614015412-aed53437177b // indirect
golang.org/x/sys v0.30.0 // indirect
)

13
go.sum
View File

@@ -2,6 +2,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/klauspost/cpuid/v2 v2.2.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -10,18 +12,21 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
github.com/templexxx/cpu v0.1.1 h1:isxHaxBXpYFWnk2DReuKkigaZyrjs2+9ypIdGP4h+HI=
github.com/templexxx/cpu v0.1.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
github.com/templexxx/xhex v0.0.0-20200614015412-aed53437177b h1:XeDLE6c9mzHpdv3Wb1+pWBaWv/BlHK0ZYIu/KaL6eHg=
github.com/templexxx/xhex v0.0.0-20200614015412-aed53437177b/go.mod h1:7rwmCH0wC2fQvNEvPZ3sKXukhyCTyiaZ5VTZMQYpZKQ=
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c h1:KL/ZBHXgKGVmuZBZ01Lt57yE5ws8ZPSkkihmEyq7FXc=
golang.org/x/exp v0.0.0-20250128182459-e0ece0dbea4c/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3 h1:qNgPs5exUA+G0C96DrPwNrvLSj7GT/9D+3WMWUcUg34=
golang.org/x/exp v0.0.0-20250207012021-f9890c6ad9f3/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
lukechampine.com/frand v1.5.1 h1:fg0eRtdmGFIxhP5zQJzM1lFDbD6CUfu/f+7WgAZd5/w=
lukechampine.com/frand v1.5.1/go.mod h1:4VstaWc2plN4Mjr10chUD46RAVGWhpkZ5Nja8+Azp0Q=
realy.lol v1.7.13 h1:+7kIa+RFmvdP23DRjj1GEe7+F7cmyl/xuII8QMwe7nM=
realy.lol v1.7.13/go.mod h1:qtk9aklmo7dpX+uSj20ol4utmh3ldWXQOpyzH4dcRG8=

View File

@@ -20,7 +20,7 @@ func (c *C) Marshal(d []byte) (r []byte, err error) {
r = append(r, '\n')
// log.I.S(r)
r = append(r, c.Content...)
r = append(r, '\n')
// r = append(r, '\n')
// log.I.S(r)
return
}

View File

@@ -5,6 +5,8 @@ import (
"crypto/rand"
mrand "math/rand"
"testing"
"protocol.realy.lol/pkg/separator"
)
func TestC_Marshal_Unmarshal(t *testing.T) {
@@ -19,6 +21,7 @@ func TestC_Marshal_Unmarshal(t *testing.T) {
if res, err = c1.Marshal(nil); chk.E(err) {
t.Fatal(err)
}
res = separator.Add(res)
c2 := new(C)
var rem []byte
if rem, err = c2.Unmarshal(res); chk.E(err) {

View File

@@ -70,6 +70,7 @@ func (n *T) Marshal(d []byte) (r []byte, err error) {
r = append(r, bb...)
n.N = n.N - q*powers[k].N
}
// r = append(r, '\n')
n.N = nn
return
}

View File

@@ -1,21 +1,27 @@
package event
import (
"realy.lol/sha256"
"realy.lol/signer"
"protocol.realy.lol/pkg/content"
"protocol.realy.lol/pkg/decimal"
"protocol.realy.lol/pkg/event/types"
"protocol.realy.lol/pkg/pubkey"
"protocol.realy.lol/pkg/separator"
"protocol.realy.lol/pkg/signature"
"protocol.realy.lol/pkg/tags"
"protocol.realy.lol/pkg/types"
)
type E struct {
id []byte
Type *types.T
Pubkey *pubkey.P
Timestamp *decimal.T
Tags *tags.T
Content *content.C
Signature *signature.S
encoded []byte
}
// New creates a new event with some typical data already filled. This should be
@@ -44,26 +50,87 @@ func New(pk []byte, typ string) (ev *E, err error) {
return
}
func (e *E) Marshal(d []byte) (r []byte, err error) {
// Invalidate empties the existing encoded cache of the event. This needs to be
// called in case of mutating its fields. It also nils the signature.
func (e *E) Invalidate() { e.encoded = e.encoded[:0]; e.Signature = nil; e.id = nil }
func (e *E) Sign(s signer.I) (err error) {
var h []byte
if h, err = e.Hash(); chk.E(err) {
return
}
var sig []byte
if sig, err = s.Sign(h); chk.E(err) {
return
}
if e.Signature, err = signature.New(sig); chk.E(err) {
return
}
return
}
func (e *E) Encode(d []byte) (r []byte, err error) {
r = d
if r, err = e.Type.Marshal(d); chk.E(err) {
if e.Type == nil {
err = errorf.E("type is not defined for event")
return
}
if r, err = e.Pubkey.Marshal(d); chk.E(err) {
if r, err = e.Type.Marshal(r); chk.E(err) {
return
}
if r, err = e.Timestamp.Marshal(d); chk.E(err) {
r = separator.Add(r)
if e.Pubkey == nil {
err = errorf.E("pubkey is not defined for event")
return
}
if r, err = e.Tags.Marshal(d); chk.E(err) {
// log.I.S(r)
if r, err = e.Pubkey.Marshal(r); chk.E(err) {
return
}
if r, err = e.Content.Marshal(d); chk.E(err) {
r = separator.Add(r)
if e.Timestamp == nil {
err = errorf.E("timestamp is not defined for event")
return
}
if r, err = e.Signature.Marshal(d); chk.E(err) {
if r, err = e.Timestamp.Marshal(r); chk.E(err) {
return
}
r = separator.Add(r)
if r, err = e.Tags.Marshal(r); chk.E(err) {
return
}
if e.Content != nil {
if r, err = e.Content.Marshal(r); chk.E(err) {
return
}
r = separator.Add(r)
}
e.encoded = r
return
}
func (e *E) Hash() (h []byte, err error) {
var b []byte
if e.encoded == nil {
if e.encoded, err = e.Encode(nil); chk.E(err) {
return
}
b = e.encoded
}
hh := sha256.Sum256(b)
h = hh[:]
e.id = h
return
}
func (e *E) Marshal(d []byte) (r []byte, err error) {
if r, err = e.Encode(d); chk.E(err) {
return
}
if r, err = e.Signature.Marshal(r); chk.E(err) {
return
}
r = separator.Add(r)
return
}

View File

@@ -1,9 +1,205 @@
package event
import (
"encoding/binary"
mrand "math/rand"
"math/rand/v2"
"testing"
"time"
"lukechampine.com/frand"
"realy.lol/signer"
"protocol.realy.lol/pkg/content"
"protocol.realy.lol/pkg/decimal"
"protocol.realy.lol/pkg/id"
"protocol.realy.lol/pkg/pubkey"
"protocol.realy.lol/pkg/tag"
"protocol.realy.lol/pkg/tags"
"protocol.realy.lol/pkg/types"
"realy.lol/p256k"
)
func TestE_Marshal_Unmarshal(t *testing.T) {
const seed = 0
func GenerateFake32Bytes(rng *rand.Rand) (fake []byte) {
fake = make([]byte, 32)
for i := range 4 {
n := rng.Uint64()
binary.LittleEndian.PutUint64(fake[i*8:i*8+8], n)
}
return
}
var Hashtags, _ = tag.New(
"halsey",
"$DIAM",
"Trevor Lawrence",
"#AEWCEO",
"Reuters",
"Linda McMahon",
"Bolton",
"Raining in Houston",
"#SwiftDay",
"Munich",
"NATO",
"#thursdayvibes",
"Good Thursday",
"$SEA",
"#AEWGrandSlam",
"Brian Steele",
"#GalentinesDay",
"Bregman",
"Afghan",
"The Accountant 2",
"Happy Friday Eve",
"TLaw",
"Red Sox",
"Large Scale Social Deception",
"2024 BMW",
"Onew",
"Secretary of Education",
"$HIMS",
"Core PPI",
"Avowed",
"Kemp",
"Angel's Venture",
"YouTube TV",
"Bri Bri",
"Teslas",
"Thirsty Thursday",
"matz",
"Jack the Ripper",
"Paramount",
"Megan Boswell",
"Zeldin",
"Zelensky",
"Censure",
"Sheldon Whitehouse",
"Arenado",
"Parasite Class",
"Kennedy Center",
"I Love Jesus",
"James Cook",
)
func GenerateContent(rng *rand.Rand, l int) (c *content.C) {
c = &content.C{}
return
}
const lorem = `Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.`
func GenerateTags(rng *rand.Rand, n int) (t *tags.T, err error) {
nE, nP, nH := rng.IntN(n)+1, rng.IntN(n)+1, rng.IntN(n)+1
var tt []*tag.T
k := tag.List.GetElementBytes(tag.KeyEvent)
for range nE {
var tg *tag.T
v := GenerateFake32Bytes(rng)
var e *id.T
if e, err = id.New(v); chk.E(err) {
return
}
var b []byte
if b, err = e.Marshal(b); chk.E(err) {
return
}
if tg, err = tag.New(k, b, []byte("root")); chk.E(err) {
return
}
tt = append(tt, tg)
}
k = tag.List.GetElementBytes(tag.KeyPubkey)
for range nP {
var tg *tag.T
v := GenerateFake32Bytes(rng)
var p *pubkey.P
if p, err = pubkey.New(v); chk.E(err) {
return
}
var b []byte
if b, err = p.Marshal(b); chk.E(err) {
return
}
if tg, err = tag.New(k, b); chk.E(err) {
return
}
tt = append(tt, tg)
}
k = tag.List.GetElementBytes(tag.KeyHashtag)
for range nH {
var tg *tag.T
v := Hashtags.GetElementBytes(rng.IntN(Hashtags.Len() - 1))
// v = bytes.ReplaceAll(v, []byte{';'}, []byte{'_'})
// v = bytes.ReplaceAll(v, []byte{':'}, []byte{'-'})
// log.I.S(v)
if tg, err = tag.New(k, v); chk.E(err) {
return
}
tt = append(tt, tg)
}
t = tags.New(tt...)
return
}
func GenerateEvent(sign signer.I) (ev *E, err error) {
s2 := rand.NewPCG(uint64(time.Now().UnixNano()), seed)
rng := rand.New(s2)
sign = new(p256k.Signer)
if err = sign.Generate(); chk.E(err) {
return
}
var pk *pubkey.P
if pk, err = pubkey.New(sign.Pub()); chk.E(err) {
return
}
var t *tags.T
if t, err = GenerateTags(rng, 3+1); chk.E(err) {
return
}
cont := make([]byte, mrand.Intn(100)+25)
_, err = frand.Read(cont)
ev = &E{
Type: types.New("note/adoc"),
Pubkey: pk,
Timestamp: decimal.New(time.Now().Unix()),
Tags: t,
Content: &content.C{Content: []byte(lorem)},
}
if err = ev.Sign(sign); chk.E(err) {
return
}
return
}
func TestE_Marshal_Unmarshal(t *testing.T) {
var ev *E
var err error
var b1, b2 []byte
sign := &p256k.Signer{}
if err = sign.Generate(); chk.E(err) {
t.Fatal(err)
}
for range 10 {
if ev, err = GenerateEvent(sign); chk.E(err) {
t.Fatal(err)
}
if b1, err = ev.Marshal(b1); chk.E(err) {
t.Fatal(err)
}
log.I.F("\n```\n%s```\n", b1)
log.I.S(ev)
b1 = b1[:0]
_ = b2
}
}

View File

@@ -9,19 +9,19 @@ import (
const Len = 43
type P struct{ b []byte }
type T struct{ b []byte }
func New(id []byte) (p *P, err error) {
func New(id []byte) (p *T, err error) {
if len(id) != ed25519.PublicKeySize {
err = errorf.E("invalid public key size: %d; require %d",
len(id), ed25519.PublicKeySize)
return
}
p = &P{id}
p = &T{id}
return
}
func (p *P) Marshal(d []byte) (r []byte, err error) {
func (p *T) Marshal(d []byte) (r []byte, err error) {
r = d
if p == nil || p.b == nil || len(p.b) == 0 {
err = errorf.E("nil/zero length pubkey")
@@ -40,11 +40,12 @@ func (p *P) Marshal(d []byte) (r []byte, err error) {
if err = w.Close(); chk.E(err) {
return
}
r = append(buf.Bytes(), '\n')
r = append(r, buf.Bytes()...)
// r = append(buf.Bytes(), '\n')
return
}
func (p *P) Unmarshal(data []byte) (r []byte, err error) {
func (p *T) Unmarshal(data []byte) (r []byte, err error) {
r = data
if p == nil {
err = errorf.E("can't unmarshal into nil types.T")

View File

@@ -5,6 +5,8 @@ import (
"crypto/ed25519"
"crypto/rand"
"testing"
"protocol.realy.lol/pkg/separator"
)
func TestT_Marshal_Unmarshal(t *testing.T) {
@@ -14,7 +16,7 @@ func TestT_Marshal_Unmarshal(t *testing.T) {
if _, err = rand.Read(pk); chk.E(err) {
t.Fatal(err)
}
var p *P
var p *T
if p, err = New(pk); chk.E(err) {
t.Fatal(err)
}
@@ -22,7 +24,8 @@ func TestT_Marshal_Unmarshal(t *testing.T) {
if o, err = p.Marshal(nil); chk.E(err) {
t.Fatal(err)
}
p2 := &P{}
o = separator.Add(o)
p2 := &T{}
var rem []byte
if rem, err = p2.Unmarshal(o); chk.E(err) {
t.Fatal(err)

View File

@@ -32,7 +32,7 @@ func (p *P) Marshal(d []byte) (r []byte, err error) {
len(p.PublicKey), ed25519.PublicKeySize, p.PublicKey)
return
}
buf := bytes.NewBuffer(r)
buf := new(bytes.Buffer)
w := base64.NewEncoder(base64.RawURLEncoding, buf)
if _, err = w.Write(p.PublicKey); chk.E(err) {
return
@@ -40,7 +40,9 @@ func (p *P) Marshal(d []byte) (r []byte, err error) {
if err = w.Close(); chk.E(err) {
return
}
r = append(buf.Bytes(), '\n')
// log.I.S(buf.Bytes())
r = append(r, buf.Bytes()...)
// r = append(buf.Bytes(), '\n')
return
}

View File

@@ -5,6 +5,8 @@ import (
"crypto/ed25519"
"crypto/rand"
"testing"
"protocol.realy.lol/pkg/separator"
)
func TestP_Marshal_Unmarshal(t *testing.T) {
@@ -22,6 +24,8 @@ func TestP_Marshal_Unmarshal(t *testing.T) {
if o, err = p.Marshal(nil); chk.E(err) {
t.Fatal(err)
}
o = separator.Add(o)
log.I.S(o)
p2 := &P{}
var rem []byte
if rem, err = p2.Unmarshal(o); chk.E(err) {

View File

@@ -0,0 +1,3 @@
package separator
func Add(dst []byte) (r []byte) { r = append(dst, '\n'); return }

View File

@@ -40,7 +40,7 @@ func (p *S) Marshal(d []byte) (r []byte, err error) {
len(p.Signature), ed25519.SignatureSize, p.Signature)
return
}
buf := bytes.NewBuffer(r)
buf := new(bytes.Buffer)
w := base64.NewEncoder(base64.RawURLEncoding, buf)
if _, err = w.Write(p.Signature); chk.E(err) {
return
@@ -48,7 +48,8 @@ func (p *S) Marshal(d []byte) (r []byte, err error) {
if err = w.Close(); chk.E(err) {
return
}
r = append(buf.Bytes(), '\n')
r = append(r, buf.Bytes()...)
// r = append(buf.Bytes(), '\n')
return
}

View File

@@ -5,6 +5,8 @@ import (
"crypto/ed25519"
"crypto/rand"
"testing"
"protocol.realy.lol/pkg/separator"
)
func TestS_Marshal_Unmarshal(t *testing.T) {
@@ -22,6 +24,7 @@ func TestS_Marshal_Unmarshal(t *testing.T) {
if o, err = s.Marshal(nil); chk.E(err) {
t.Fatal(err)
}
o = separator.Add(o)
p2 := &S{}
var rem []byte
if rem, err = p2.Unmarshal(o); chk.E(err) {

17
pkg/tag/common.go Normal file
View File

@@ -0,0 +1,17 @@
package tag
const (
KeyEvent = iota
KeyPubkey
KeyHashtag
)
var List, _ = New(
// event is a reference to an event, the value is an Event Id
"event",
// pubkey is a reference to a public key, the value is a pubkey.P
"pubkey",
// hashtag is a string that can be searched by a hashtag filter tag
"hashtag",
// ... can many more things be in here for purposes
)

View File

@@ -27,6 +27,7 @@ func New[V ~[]byte | ~string](v ...V) (t *T, err error) {
t.fields = append(t.fields, k)
for i, val := range v {
var b []byte
// log.I.S(val)
if b, err = ValidateField(val, i); chk.E(err) {
return
}
@@ -35,6 +36,29 @@ func New[V ~[]byte | ~string](v ...V) (t *T, err error) {
return
}
func (t *T) Len() int { return len(t.fields) }
func (t *T) Less(i, j int) bool { return bytes.Compare(t.fields[i], t.fields[j]) < 0 }
func (t *T) Swap(i, j int) { t.fields[i], t.fields[j] = t.fields[j], t.fields[i] }
func (t *T) GetElementBytes(i int) (s []byte) {
if i >= len(t.fields) {
// return empty string if not found
return
}
return t.fields[i]
}
func (t *T) GetElementString(i int) (s string) {
return string(t.GetElementBytes(i))
}
func (t *T) GetStringSlice() (s []string) {
for _, v := range t.fields {
s = append(s, string(v))
}
return
}
// ValidateKey checks that the key is valid. Keys must be the same most language symbols:
//
// - first character is alphabetic [a-zA-Z]

View File

@@ -4,10 +4,12 @@ import (
"bytes"
"fmt"
"protocol.realy.lol/pkg/decimal"
"protocol.realy.lol/pkg/separator"
"protocol.realy.lol/pkg/tag"
)
const Sentinel = "tags:\n"
const Sentinel = "tags:"
var SentinelBytes = []byte(Sentinel)
@@ -17,15 +19,24 @@ type T struct{ tags }
func New(v ...*tag.T) *T { return &T{tags: v} }
func (t *T) Marshal(dst []byte) (result []byte, err error) {
result = dst
result = append(result, Sentinel...)
func (t *T) Marshal(dst []byte) (r []byte, err error) {
r = dst
r = append(r, Sentinel...)
var l int
if t != nil {
l = len(t.tags)
}
if r, err = decimal.New(l).Marshal(r); chk.E(err) {
return
}
r = separator.Add(r)
if t != nil {
for _, tt := range t.tags {
if result, err = tt.Marshal(result); chk.E(err) {
if r, err = tt.Marshal(r); chk.E(err) {
return
}
}
result = append(result, '\n')
}
return
}
@@ -34,20 +45,23 @@ func (t *T) Unmarshal(data []byte) (rem []byte, err error) {
err = fmt.Errorf("bytes too short to contain tags")
return
}
var dat []byte
var d []byte
if bytes.Equal(data[:len(Sentinel)], SentinelBytes) {
dat = data[len(Sentinel):]
d = data[len(Sentinel):]
}
if len(dat) < 1 {
l := decimal.New(0)
if d, err = l.Unmarshal(d); chk.E(err) {
return
}
for len(dat) > 0 {
if len(dat) == 1 && dat[0] == '\n' {
break
// and then there must be a newline
if d[0] != '\n' {
err = errorf.E("must be newline after content:<length>:\n%n", d)
return
}
// log.I.S(dat)
d = d[1:]
for range l.N {
tt := new(tag.T)
if dat, err = tt.Unmarshal(dat); chk.E(err) {
if d, err = tt.Unmarshal(d); chk.E(err) {
return
}
t.tags = append(t.tags, tt)

View File

@@ -9,9 +9,9 @@ import (
func TestT_Marshal_Unmarshal(t *testing.T) {
var tegs = [][]string{
{"reply", "e:l_T9Of4ru-PLGUxxvw3SfZH0e6XW11VYy8ZSgbcsD9Y", "realy.example.com/repo1"},
{"root", "e:l_T9Of4ru-PLGUxxvw3SfZH0e6XW11VYy8ZSgbcsD9Y", "realy.example.com/repo2"},
{"mention", "p:JMkZVnu9QFplR4F_KrWX-3chQsklXZq_5I6eYcXfz1Q", "realy.example.com/repo3"},
{"reply", "l_T9Of4ru-PLGUxxvw3SfZH0e6XW11VYy8ZSgbcsD9Y", "realy.example.com/repo1"},
{"root", "l_T9Of4ru-PLGUxxvw3SfZH0e6XW11VYy8ZSgbcsD9Y", "realy.example.com/repo2"},
{"mention", "JMkZVnu9QFplR4F_KrWX-3chQsklXZq_5I6eYcXfz1Q", "realy.example.com/repo3"},
}
var err error
var tgs []*tag.T
@@ -40,6 +40,7 @@ func TestT_Marshal_Unmarshal(t *testing.T) {
t.Fatal(err)
}
if !bytes.Equal(m1, m2) {
log.I.S(m1, m2)
t.Fatalf("not equal:\n%s\n%s", m1, m2)
}
}

View File

@@ -18,7 +18,7 @@ func (t *T) Marshal(d []byte) (r []byte, err error) {
if t == nil {
return
}
r = append(append(d, t.t...), '\n')
r = append(d, t.t...)
return
}
@@ -39,7 +39,7 @@ func (t *T) Unmarshal(d []byte) (r []byte, err error) {
// write read data up to the newline and return the remainder after
// the newline.
t.t = r[:i]
r = r[i+1:]
r = r[i:]
return
}
}

View File

@@ -2,6 +2,8 @@ package types
import (
"testing"
"protocol.realy.lol/pkg/separator"
)
func TestT_Marshal_Unmarshal(t *testing.T) {
@@ -11,6 +13,8 @@ func TestT_Marshal_Unmarshal(t *testing.T) {
if res, err = typ.Marshal(nil); chk.E(err) {
t.Fatal(err)
}
res = separator.Add(res)
log.I.S(res)
t2 := new(T)
var rem []byte
if rem, err = t2.Unmarshal(res); chk.E(err) {

View File

@@ -27,7 +27,7 @@ func (u *U) Equal(u2 *U) bool { return bytes.Equal(u.uu, u2.uu) }
// Marshal a URL, use New to ensure it is valid beforehand. Appends a terminal
// newline.
func (u *U) Marshal(dst []byte) (result []byte, err error) {
result = append(append(dst, u.uu...), '\n')
result = append(dst, u.uu...)
return
}

View File

@@ -2,6 +2,8 @@ package url
import (
"testing"
"protocol.realy.lol/pkg/separator"
)
func TestU_Marshal_Unmarshal(t *testing.T) {
@@ -15,6 +17,7 @@ func TestU_Marshal_Unmarshal(t *testing.T) {
if m1, err = u1.Marshal(nil); chk.E(err) {
t.Fatal(err)
}
m1 = separator.Add(m1)
u2 := new(U)
var rem []byte
if rem, err = u2.Unmarshal(m1); chk.E(err) {

View File

@@ -1,5 +1,11 @@
= REALY Protocol
:toc:
:important-caption: 🔥
:note-caption: 🗩
:tip-caption: 💡
:caution-caption: ⚠
:table-caption: 🔍
:example-caption: 🥚
image:https://img.shields.io/badge/godoc-documentation-blue.svg[Documentation,link=https://pkg.go.dev/protocol.realy.lol]
image:https://img.shields.io/badge/matrix-chat-green.svg[matrix chat,link=https://matrix.to/#/#realy-general:matrix.org]
@@ -229,10 +235,10 @@ As per implementation, each capability should be part of a registered list of me
| `<type name>\n` | can be anything, hierarchic names like `note/html` `note/md` are possible, or `type.subtype` or whatever
| `<pubkey>\n` | encoded in URL-base64 with the padding single `=` elided
| `<unix second precision timestamp in decimal ascii>\n` |
| `tags:\n`| Tags are a zero or more length list of lines delimited by this header and a new line after the content
| `tags:<number>\n`| Tags has the number of tags present, and then one linebreak for each tag
| `key:value;extra;...\n` | zero or more line separated, fields cannot contain a semicolon, end with newline instead of semicolon, key lowercase alphanumeric, first alpha, no whitespace or symbols, only key and following `:` are mandatory
| `\n` | tags end with a double linebreak
| `content:\n` | literally this word on one line *directly* after the newline of the previous
| `content:<length>\n` | literally this word on one line *directly* after the newline of the previous
| `<content>\n` | any number of further line breaks, last line is signature, everything before signature line is part of the canonical hash
2+^| The canonical form is the above, creating the message hash that is generated with Blake 2b
| `<ed25519 signature encoded in URL-base64>\n` | this field would have two padding chars `==`, these should be elided before generating the encoding.