package communityreg import ( "chain/runtime" "errors" "gno.land/p/nt/avl" "gno.land/p/nt/ownable" "gno.land/p/zenao/communities" zenaov1 "gno.land/p/zenao/zenao/v1" ) var ( Ownable *ownable.Ownable registered avl.Tree // -> func() communities.Info communityesByMembers avl.Tree // / -> communityPkgPath communitiesByPkgPath avl.Tree // -> communities.Info communitiesByEvent avl.Tree // / -> communityID ErrCommunityNotFound = errors.New("community not found") ) func init() { Ownable = ownable.NewWithAddress(address("g1djrkw9tf4px658j85cc6fhsvm50uf9s0g6kfsm")) // zenao-dev-admin } // XXX: split this package into communityreg and communitiesindex func Register(_ realm, infoGetter communities.InfoGetter) { caller := runtime.PreviousRealm() if caller.IsUser() { panic("can't register user") } pkgPath := caller.PkgPath() if infoGetter == nil { registered.Remove(pkgPath) // XXX: remove from index?? return } registered.Set(pkgPath, infoGetter) } func getInfo(pkgPath string) (*zenaov1.CommunityInfo, bool) { raw, ok := registered.Get(pkgPath) if !ok { return nil, false } return raw.(communities.InfoGetter)(), true } func mustGetInfo(pkgPath string) *zenaov1.CommunityInfo { info, ok := getInfo(pkgPath) if !ok { panic(ErrCommunityNotFound) } return info } func IndexCommunity(_ realm, pkgPath string) { Ownable.AssertOwnedByPrevious() if exist := getCommunityByPkgPath(pkgPath); exist != nil { panic("community already indexed: " + pkgPath) } info := mustGetInfo(pkgPath) communitiesByPkgPath.Set(pkgPath, info) } func AddMember(_ realm, communityPkgPath string, memberID string) { Ownable.AssertOwnedByPrevious() mustGetCommunityByPkgPath(communityPkgPath) key := memberID + "/" + communityPkgPath communityesByMembers.Set(key, communityPkgPath) info := mustGetInfo(communityPkgPath) communitiesByPkgPath.Set(communityPkgPath, info) } func RemoveMember(_ realm, communityPkgPath string, memberID string) { Ownable.AssertOwnedByPrevious() mustGetCommunityByPkgPath(communityPkgPath) key := memberID + "/" + communityPkgPath communityesByMembers.Remove(key) info := mustGetInfo(communityPkgPath) communitiesByPkgPath.Set(communityPkgPath, info) } func AddEvent(_ realm, communityPkgPath string, eventID string) { Ownable.AssertOwnedByPrevious() mustGetCommunityByPkgPath(communityPkgPath) key := eventID + "/" + communityPkgPath communitiesByEvent.Set(key, communityPkgPath) } func RemoveEvent(_ realm, communityPkgPath string, eventID string) { Ownable.AssertOwnedByPrevious() mustGetCommunityByPkgPath(communityPkgPath) key := eventID + "/" + communityPkgPath communitiesByEvent.Remove(key) } func getCommunityByPkgPath(pkgPath string) *zenaov1.CommunityInfo { raw, ok := communitiesByPkgPath.Get(pkgPath) if !ok { return nil } return raw.(*zenaov1.CommunityInfo) } func mustGetCommunityByPkgPath(pkgPath string) *zenaov1.CommunityInfo { info := getCommunityByPkgPath(pkgPath) if info == nil { panic(ErrCommunityNotFound) } return info } func listCommunities(limit, offset uint32) []*zenaov1.CommunityInfo { return listCommunitiesInternal(&communitiesByPkgPath, "", "", false, limit, offset) } func listCommunitiesByMembers(memberID string, limit, offset uint32) []*zenaov1.CommunityInfo { // ff is 255 in hex, which is the highest byte value, so it will match all keys that start with memberID. fromKey := memberID + "/" toKey := memberID + "/\xff" return listCommunitiesInternal(&communityesByMembers, fromKey, toKey, false, limit, offset) } func listCommunitiesByEvent(eventID string, limit, offset uint32) []*zenaov1.CommunityInfo { fromKey := eventID + "/" toKey := eventID + "/\xff" return listCommunitiesInternal(&communitiesByEvent, fromKey, toKey, false, limit, offset) } func listCommunitiesInternal(at avl.ITree, fromKey string, toKey string, rev bool, limit, offset uint32) []*zenaov1.CommunityInfo { res := []*zenaov1.CommunityInfo{} count := uint32(0) it := func(key string, value interface{}) bool { if count < offset { count++ return false } var info zenaov1.CommunityInfo switch val := value.(type) { case *zenaov1.CommunityInfo: info = *val case string: info = *mustGetCommunityByPkgPath(val) } info.PkgPath = key res = append(res, &info) return uint32(len(res)) >= limit } if rev { at.ReverseIterate(toKey, fromKey, it) } else { at.Iterate(fromKey, toKey, it) } return res }