You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
6.8 KiB
250 lines
6.8 KiB
//go:build !(js && wasm) |
|
|
|
package bbolt |
|
|
|
import ( |
|
"bytes" |
|
"encoding/binary" |
|
"io" |
|
) |
|
|
|
// EventVertex stores the adjacency list for an event. |
|
// Contains the author and all edges to other events/pubkeys. |
|
type EventVertex struct { |
|
AuthorSerial uint64 // Serial of the author pubkey |
|
Kind uint16 // Event kind |
|
PTagSerials []uint64 // Serials of pubkeys mentioned (p-tags) |
|
ETagSerials []uint64 // Serials of events referenced (e-tags) |
|
} |
|
|
|
// Encode serializes the EventVertex to bytes. |
|
// Format: author(5) | kind(2) | ptag_count(varint) | [ptag_serials(5)...] | etag_count(varint) | [etag_serials(5)...] |
|
func (ev *EventVertex) Encode() []byte { |
|
// Calculate size |
|
size := 5 + 2 + 2 + len(ev.PTagSerials)*5 + 2 + len(ev.ETagSerials)*5 |
|
buf := make([]byte, 0, size) |
|
|
|
// Author serial (5 bytes) |
|
authorBuf := make([]byte, 5) |
|
encodeUint40(ev.AuthorSerial, authorBuf) |
|
buf = append(buf, authorBuf...) |
|
|
|
// Kind (2 bytes) |
|
kindBuf := make([]byte, 2) |
|
binary.BigEndian.PutUint16(kindBuf, ev.Kind) |
|
buf = append(buf, kindBuf...) |
|
|
|
// P-tag count and serials |
|
ptagCountBuf := make([]byte, 2) |
|
binary.BigEndian.PutUint16(ptagCountBuf, uint16(len(ev.PTagSerials))) |
|
buf = append(buf, ptagCountBuf...) |
|
for _, serial := range ev.PTagSerials { |
|
serialBuf := make([]byte, 5) |
|
encodeUint40(serial, serialBuf) |
|
buf = append(buf, serialBuf...) |
|
} |
|
|
|
// E-tag count and serials |
|
etagCountBuf := make([]byte, 2) |
|
binary.BigEndian.PutUint16(etagCountBuf, uint16(len(ev.ETagSerials))) |
|
buf = append(buf, etagCountBuf...) |
|
for _, serial := range ev.ETagSerials { |
|
serialBuf := make([]byte, 5) |
|
encodeUint40(serial, serialBuf) |
|
buf = append(buf, serialBuf...) |
|
} |
|
|
|
return buf |
|
} |
|
|
|
// Decode deserializes bytes into an EventVertex. |
|
func (ev *EventVertex) Decode(data []byte) error { |
|
if len(data) < 9 { // minimum: author(5) + kind(2) + ptag_count(2) |
|
return io.ErrUnexpectedEOF |
|
} |
|
|
|
reader := bytes.NewReader(data) |
|
|
|
// Author serial |
|
authorBuf := make([]byte, 5) |
|
if _, err := reader.Read(authorBuf); err != nil { |
|
return err |
|
} |
|
ev.AuthorSerial = decodeUint40(authorBuf) |
|
|
|
// Kind |
|
kindBuf := make([]byte, 2) |
|
if _, err := reader.Read(kindBuf); err != nil { |
|
return err |
|
} |
|
ev.Kind = binary.BigEndian.Uint16(kindBuf) |
|
|
|
// P-tags |
|
ptagCountBuf := make([]byte, 2) |
|
if _, err := reader.Read(ptagCountBuf); err != nil { |
|
return err |
|
} |
|
ptagCount := binary.BigEndian.Uint16(ptagCountBuf) |
|
ev.PTagSerials = make([]uint64, ptagCount) |
|
for i := uint16(0); i < ptagCount; i++ { |
|
serialBuf := make([]byte, 5) |
|
if _, err := reader.Read(serialBuf); err != nil { |
|
return err |
|
} |
|
ev.PTagSerials[i] = decodeUint40(serialBuf) |
|
} |
|
|
|
// E-tags |
|
etagCountBuf := make([]byte, 2) |
|
if _, err := reader.Read(etagCountBuf); err != nil { |
|
return err |
|
} |
|
etagCount := binary.BigEndian.Uint16(etagCountBuf) |
|
ev.ETagSerials = make([]uint64, etagCount) |
|
for i := uint16(0); i < etagCount; i++ { |
|
serialBuf := make([]byte, 5) |
|
if _, err := reader.Read(serialBuf); err != nil { |
|
return err |
|
} |
|
ev.ETagSerials[i] = decodeUint40(serialBuf) |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// PubkeyVertex stores the adjacency list for a pubkey. |
|
// Contains all events authored by or mentioning this pubkey. |
|
type PubkeyVertex struct { |
|
AuthoredEvents []uint64 // Event serials this pubkey authored |
|
MentionedIn []uint64 // Event serials that mention this pubkey (p-tags) |
|
} |
|
|
|
// Encode serializes the PubkeyVertex to bytes. |
|
// Format: authored_count(varint) | [serials(5)...] | mentioned_count(varint) | [serials(5)...] |
|
func (pv *PubkeyVertex) Encode() []byte { |
|
size := 2 + len(pv.AuthoredEvents)*5 + 2 + len(pv.MentionedIn)*5 |
|
buf := make([]byte, 0, size) |
|
|
|
// Authored events |
|
authoredCountBuf := make([]byte, 2) |
|
binary.BigEndian.PutUint16(authoredCountBuf, uint16(len(pv.AuthoredEvents))) |
|
buf = append(buf, authoredCountBuf...) |
|
for _, serial := range pv.AuthoredEvents { |
|
serialBuf := make([]byte, 5) |
|
encodeUint40(serial, serialBuf) |
|
buf = append(buf, serialBuf...) |
|
} |
|
|
|
// Mentioned in events |
|
mentionedCountBuf := make([]byte, 2) |
|
binary.BigEndian.PutUint16(mentionedCountBuf, uint16(len(pv.MentionedIn))) |
|
buf = append(buf, mentionedCountBuf...) |
|
for _, serial := range pv.MentionedIn { |
|
serialBuf := make([]byte, 5) |
|
encodeUint40(serial, serialBuf) |
|
buf = append(buf, serialBuf...) |
|
} |
|
|
|
return buf |
|
} |
|
|
|
// Decode deserializes bytes into a PubkeyVertex. |
|
func (pv *PubkeyVertex) Decode(data []byte) error { |
|
if len(data) < 4 { // minimum: authored_count(2) + mentioned_count(2) |
|
return io.ErrUnexpectedEOF |
|
} |
|
|
|
reader := bytes.NewReader(data) |
|
|
|
// Authored events |
|
authoredCountBuf := make([]byte, 2) |
|
if _, err := reader.Read(authoredCountBuf); err != nil { |
|
return err |
|
} |
|
authoredCount := binary.BigEndian.Uint16(authoredCountBuf) |
|
pv.AuthoredEvents = make([]uint64, authoredCount) |
|
for i := uint16(0); i < authoredCount; i++ { |
|
serialBuf := make([]byte, 5) |
|
if _, err := reader.Read(serialBuf); err != nil { |
|
return err |
|
} |
|
pv.AuthoredEvents[i] = decodeUint40(serialBuf) |
|
} |
|
|
|
// Mentioned in events |
|
mentionedCountBuf := make([]byte, 2) |
|
if _, err := reader.Read(mentionedCountBuf); err != nil { |
|
return err |
|
} |
|
mentionedCount := binary.BigEndian.Uint16(mentionedCountBuf) |
|
pv.MentionedIn = make([]uint64, mentionedCount) |
|
for i := uint16(0); i < mentionedCount; i++ { |
|
serialBuf := make([]byte, 5) |
|
if _, err := reader.Read(serialBuf); err != nil { |
|
return err |
|
} |
|
pv.MentionedIn[i] = decodeUint40(serialBuf) |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// AddAuthored adds an event serial to the authored list if not already present. |
|
func (pv *PubkeyVertex) AddAuthored(eventSerial uint64) { |
|
for _, s := range pv.AuthoredEvents { |
|
if s == eventSerial { |
|
return |
|
} |
|
} |
|
pv.AuthoredEvents = append(pv.AuthoredEvents, eventSerial) |
|
} |
|
|
|
// AddMention adds an event serial to the mentioned list if not already present. |
|
func (pv *PubkeyVertex) AddMention(eventSerial uint64) { |
|
for _, s := range pv.MentionedIn { |
|
if s == eventSerial { |
|
return |
|
} |
|
} |
|
pv.MentionedIn = append(pv.MentionedIn, eventSerial) |
|
} |
|
|
|
// RemoveAuthored removes an event serial from the authored list. |
|
func (pv *PubkeyVertex) RemoveAuthored(eventSerial uint64) { |
|
for i, s := range pv.AuthoredEvents { |
|
if s == eventSerial { |
|
pv.AuthoredEvents = append(pv.AuthoredEvents[:i], pv.AuthoredEvents[i+1:]...) |
|
return |
|
} |
|
} |
|
} |
|
|
|
// RemoveMention removes an event serial from the mentioned list. |
|
func (pv *PubkeyVertex) RemoveMention(eventSerial uint64) { |
|
for i, s := range pv.MentionedIn { |
|
if s == eventSerial { |
|
pv.MentionedIn = append(pv.MentionedIn[:i], pv.MentionedIn[i+1:]...) |
|
return |
|
} |
|
} |
|
} |
|
|
|
// HasAuthored checks if the pubkey authored the given event. |
|
func (pv *PubkeyVertex) HasAuthored(eventSerial uint64) bool { |
|
for _, s := range pv.AuthoredEvents { |
|
if s == eventSerial { |
|
return true |
|
} |
|
} |
|
return false |
|
} |
|
|
|
// IsMentionedIn checks if the pubkey is mentioned in the given event. |
|
func (pv *PubkeyVertex) IsMentionedIn(eventSerial uint64) bool { |
|
for _, s := range pv.MentionedIn { |
|
if s == eventSerial { |
|
return true |
|
} |
|
} |
|
return false |
|
}
|
|
|