add content codec

This commit is contained in:
2025-01-31 03:45:06 -01:06
parent d36bcdb243
commit 4c6e7b08ac
4 changed files with 103 additions and 1 deletions

View File

@@ -32,7 +32,7 @@ Event ID hashes will be encoded in URL-base64 where used in tags or mentioned in
Indexing tags should be done with a truncated Blake2b hash cut at 8 bytes in the event store.
Submitting an event to be stored is the same as a result sent from an Event Id query except with the type of operation inteded: `store\n` to store an event, `replace:<Event Id>\n` to replace an existing event and `relay\n` to not store but send to subscribers with open matching filters.
Submitting an event to be stored is the same as a result sent from an Event Id query except with the type of operation inteded: `store\n` to store an event, `replace:<Event Id>\n` to replace an existing event and `relay\n` to not store but send to subscribers with open matching filters. Replace will not be accepted if the message type and pubkey are different to the original that is specified.
An event is then acknowledged to be stored or rejected with a message `ok:<true/false>;<Event Id>;<reason type>:human readable part` where the reason type is one of a set of common types to indicate the reason for the false

54
pkg/content/content.go Normal file
View File

@@ -0,0 +1,54 @@
package content
import (
"bytes"
)
// C is raw content bytes of a message. This can contain anything but when it is
// unmarshalled it is assumed that the last line (content between the second
// last and last line break) is not part of the content, as this is where the
// signature is placed.
//
// The only guaranteed property of an encoded content.C is that it has two
// newline characters, one at the very end, and a second one before it that
// demarcates the end of the actual content. It can be entirely binary and mess
// up a terminal to render the unsanitized possible control characters.
type C struct{ Content []byte }
// Marshal just writes the provided data with a `content:\n` prefix and adds a
// terminal newline.
func (c *C) Marshal(dst []byte) (result []byte, err error) {
result = append(append(append(dst, "content:\n"...), c.Content...), '\n')
return
}
var Prefix = "content:\n"
// Unmarshal expects the `content:\n` prefix and stops at the second last
// newline. The data between the second last and last newline in the data is
// assumed to be a signature but it could be anything in another use case.
func (c *C) Unmarshal(data []byte) (rem []byte, err error) {
if !bytes.HasPrefix(data, []byte("content:\n")) {
err = errorf.E("content prefix `content:\\n' not found: '%s'", data[:len(Prefix)+1])
return
}
// trim off the prefix.
data = data[len(Prefix):]
// check that there is a last newline.
if data[len(data)-1] != '\n' {
err = errorf.E("input data does not end with newline")
return
}
// we start at the second last, previous to the terminal newline byte.
lastPos := len(data) - 2
for ; lastPos >= len(Prefix); lastPos-- {
// the content ends at the byte before the second last newline byte.
if data[lastPos] == '\n' {
break
}
}
c.Content = data[:lastPos]
// return the remainder after the content-terminal newline byte.
rem = data[lastPos+1:]
return
}

View File

@@ -0,0 +1,39 @@
package content
import (
"bytes"
"crypto/rand"
mrand "math/rand"
"testing"
)
func TestC_Marshal_Unmarshal(t *testing.T) {
c := make([]byte, mrand.Intn(100)+25)
_, err := rand.Read(c)
if err != nil {
t.Fatal(err)
}
log.I.S(c)
c1 := new(C)
c1.Content = c
var res []byte
if res, err = c1.Marshal(nil); chk.E(err) {
t.Fatal(err)
}
// append a fake zero length signature
res = append(res, '\n')
log.I.S(res)
c2 := new(C)
var rem []byte
if rem, err = c2.Unmarshal(res); chk.E(err) {
t.Fatal(err)
}
if !bytes.Equal(c1.Content, c2.Content) {
log.I.S(c1, c2)
t.Fatal("content not equal")
}
if !bytes.Equal(rem, []byte{'\n'}) {
log.I.S(rem)
t.Fatalf("remainder not found")
}
}

9
pkg/content/log.go Normal file
View File

@@ -0,0 +1,9 @@
package content
import (
"protocol.realy.lol/pkg/lol"
)
var (
log, chk, errorf = lol.Main.Log, lol.Main.Check, lol.Main.Errorf
)