From 5320b561c592e875f0523760d4d20df8d66b30a7 Mon Sep 17 00:00:00 2001 From: raven Date: Mon, 20 Oct 2025 18:06:13 -0500 Subject: user and channel saving --- server/object/object.go | 124 +++++++++++++++++++++++++++++++++++++++++++-- server/object/tombstone.go | 10 ++++ 2 files changed, 130 insertions(+), 4 deletions(-) (limited to 'server/object') diff --git a/server/object/object.go b/server/object/object.go index e0d0239..e05ae0f 100644 --- a/server/object/object.go +++ b/server/object/object.go @@ -3,31 +3,143 @@ package object import ( "citrons.xyz/talk/proto" "citrons.xyz/talk/server/session" + "citrons.xyz/talk/server/validate" + "bufio" + "bytes" + "log" + bolt "go.etcd.io/bbolt" ) type Object interface { SendRequest(session.Request) InfoFor(uid string) proto.Object + Data() proto.Object +} + +type HasHandle interface { + Handle() string +} + +type Kind interface { + Undata(o proto.Object) Object } type World struct { + db *bolt.DB + kinds map[string]Kind objects map[string]Object } -func NewWorld() *World { - return &World {make(map[string]Object)} +func NewWorld(db *bolt.DB) *World { + w := &World {db, make(map[string]Kind), make(map[string]Object)} + w.AddObjectKind("gone", TombstoneKind{}) + return w +} + +func (w *World) AddObjectKind(name string, kind Kind) { + w.kinds[name] = kind +} + +func (w *World) getData(id string) proto.Object { + var data []byte + err := w.db.View(func (tx *bolt.Tx) error { + bucket := tx.Bucket([]byte("world")) + if bucket != nil { + data = bucket.Get([]byte(id)) + } + return nil + }) + if err != nil { + log.Fatal("reading database: ", err) + } + if len(data) == 0 { + return proto.Object {} + } + o, err := proto.ReadObject(bufio.NewReader(bytes.NewReader(data))) + if err != nil { + panic(err) + } + return o +} + +func (w *World) setData(id string, o proto.Object) { + var buf bytes.Buffer + writer := bufio.NewWriter(&buf) + proto.WriteObject(writer, o) + writer.Flush() + err := w.db.Update(func (tx *bolt.Tx) error { + bucket, _ := tx.CreateBucketIfNotExists([]byte("world")) + return bucket.Put([]byte(id), buf.Bytes()) + }) + if err != nil { + log.Fatal("updating database: ", err) + } } func (w *World) GetObject(id string) Object { + if w.objects[id] == nil { + o := w.getData(id) + if o.Kind != "" { + w.objects[id] = w.kinds[o.Kind].Undata(o) + } + } return w.objects[id] } func (w *World) PutObject(id string, o Object) { w.objects[id] = o + if id == "" { + return + } + switch h := o.(type) { + case HasHandle: + err := w.db.Update(func(tx *bolt.Tx) error { + kinds, _ := tx.CreateBucketIfNotExists([]byte("kinds")) + kind, _ := kinds.CreateBucketIfNotExists([]byte(o.Data().Kind)) + byHandle, _ := kind.CreateBucketIfNotExists([]byte("by handle")) + byId, _ := kind.CreateBucketIfNotExists([]byte("by id")) + + existing := byId.Get([]byte(id)) + if len(existing) != 0 { + byHandle.Delete(existing) + } + handle := []byte(validate.Fold(h.Handle())) + log.Println(string(handle), o.Data().Kind) + byHandle.Put(handle, []byte(id)) + byId.Put([]byte(id), handle) + + return nil + }) + if err != nil { + log.Fatal("updating database: ", err) + } + } + w.setData(id, o.Data()) } -func (w *World) RemoveObject(id string) { - w.objects[id] = nil +func (w *World) Lookup(kind string, handle string) Object { + handle = validate.Fold(handle) + + var id string + err := w.db.View(func(tx *bolt.Tx) error { + kinds := tx.Bucket([]byte("kinds")) + if kinds == nil { + return nil + } + kind := kinds.Bucket([]byte(kind)) + if kind == nil { + return nil + } + id = string(kind.Bucket([]byte("by handle")).Get([]byte(handle))) + return nil + }) + if err != nil { + log.Fatal("reading database: ", err) + } + if id != "" { + return w.GetObject(id) + } + return nil } func (w *World) NewObject(o Object) string { @@ -35,3 +147,7 @@ func (w *World) NewObject(o Object) string { w.PutObject(id, o) return id } + +func (w *World) DB() *bolt.DB { + return w.db +} diff --git a/server/object/tombstone.go b/server/object/tombstone.go index 05d9600..a2872f6 100644 --- a/server/object/tombstone.go +++ b/server/object/tombstone.go @@ -10,7 +10,17 @@ type Tombstone struct { Fields map[string]string } +type TombstoneKind struct {} + +func (t TombstoneKind) Undata(o proto.Object) Object { + return Tombstone {Id: o.Id, Fields: o.Fields} +} + func (t Tombstone) InfoFor(uid string) proto.Object { + return t.Data() +} + +func (t Tombstone) Data() proto.Object { return proto.Object {"gone", t.Id, t.Fields} } -- cgit v1.2.3