package object import ( "citrons.xyz/talk/proto" ) type ObjCache struct { stream ObjStream objects map[string]cacheEntry } type cacheEntry struct { o proto.Object refCount int cached bool } type ObjStream interface { Sub(id string) GetInfo(id string, callback func(proto.Command)) Unsub(id string) } func NewCache(stream ObjStream) ObjCache { return ObjCache {stream, make(map[string]cacheEntry)} } func (oc *ObjCache) Get(id string) *proto.Object { entry := oc.objects[id] if !entry.cached { return nil } return &entry.o } func (oc *ObjCache) Fetch(id string, callback func(*proto.Object)) { entry := oc.objects[id] if !entry.cached { oc.stream.GetInfo(id, func(cmd proto.Command) { if cmd.Kind == "i" && len(cmd.Args) > 0 { callback(&cmd.Args[0]) } else { callback(nil) } }) } callback(&entry.o) } func (oc *ObjCache) Watch(id string) { entry, ok := oc.objects[id] if !ok { oc.stream.Sub(id) } oc.objects[id] = entry } func (oc *ObjCache) Unwatch(id string) { entry, ok := oc.objects[id] if ok { entry.refCount-- if entry.refCount <= 0 { oc.stream.Unsub(id) delete(oc.objects, id) } else { oc.objects[id] = entry } } } func (oc *ObjCache) Update(id string, new proto.Object) { entry := oc.objects[id] if entry.cached && new.Kind == entry.o.Kind { for k, v := range new.Fields { entry.o.Fields[k] = v } } else { entry.o = new } entry.cached = true oc.objects[id] = entry } func (oc *ObjCache) Gone(id string) { entry := oc.objects[id] if entry.cached { obj := entry.o obj.Fields["kind"] = obj.Kind obj.Kind = "gone" entry.o = obj oc.objects[id] = entry } }