communityreg.gno

3.73 Kb ยท 147 lines
  1package communityreg
  2
  3import (
  4	"errors"
  5	"std"
  6
  7	"gno.land/p/demo/avl"
  8	"gno.land/p/demo/ownable"
  9	"gno.land/p/zenao/communities"
 10	zenaov1 "gno.land/p/zenao/zenao/v1"
 11)
 12
 13var (
 14	Ownable *ownable.Ownable
 15
 16	registered           avl.Tree // <communityPkgPath> -> func() communities.Info
 17	communityesByMembers avl.Tree // <memberID>/<communityPkgPath> -> communityPkgPath
 18	communitiesByPkgPath avl.Tree // <communityPkgPath> -> communities.Info
 19
 20	ErrCommunityNotFound = errors.New("community not found")
 21)
 22
 23func init() {
 24	Ownable = ownable.NewWithAddress(std.Address("g1djrkw9tf4px658j85cc6fhsvm50uf9s0g6kfsm")) // zenao-dev-admin
 25}
 26
 27// XXX: split this package into communityreg and communitiesindex
 28
 29func Register(infoGetter communities.InfoGetter) {
 30	pkgPath := std.PreviousRealm().PkgPath()
 31
 32	if infoGetter == nil {
 33		registered.Remove(pkgPath)
 34		// XXX: remove from index??
 35		return
 36	}
 37
 38	registered.Set(pkgPath, infoGetter)
 39}
 40
 41func getInfo(pkgPath string) (*zenaov1.CommunityInfo, bool) {
 42	raw, ok := registered.Get(pkgPath)
 43	if !ok {
 44		return nil, false
 45	}
 46	return raw.(communities.InfoGetter)(), true
 47}
 48
 49func mustGetInfo(pkgPath string) *zenaov1.CommunityInfo {
 50	info, ok := getInfo(pkgPath)
 51	if !ok {
 52		panic(ErrCommunityNotFound)
 53	}
 54	return info
 55}
 56
 57func IndexCommunity(pkgPath string) {
 58	Ownable.AssertCallerIsOwner()
 59
 60	if prev := getCommunityByPkgPath(pkgPath); prev != nil {
 61		panic("community already indexed: " + pkgPath)
 62	}
 63
 64	info := mustGetInfo(pkgPath)
 65	communitiesByPkgPath.Set(pkgPath, info)
 66}
 67
 68func AddMember(communityPkgPath string, memberID string) {
 69	Ownable.AssertCallerIsOwner()
 70
 71	if prev := getCommunityByPkgPath(communityPkgPath); prev == nil {
 72		panic("community not found: " + communityPkgPath)
 73	}
 74
 75	key := memberID + "/" + communityPkgPath
 76	communityesByMembers.Set(key, communityPkgPath)
 77	info := mustGetInfo(communityPkgPath)
 78	communitiesByPkgPath.Set(communityPkgPath, info)
 79}
 80
 81func RemoveMember(communityPkgPath string, memberID string) {
 82	Ownable.AssertCallerIsOwner()
 83
 84	if prev := getCommunityByPkgPath(communityPkgPath); prev == nil {
 85		panic("community not found: " + communityPkgPath)
 86	}
 87
 88	key := memberID + "/" + communityPkgPath
 89	communityesByMembers.Remove(key)
 90	info := mustGetInfo(communityPkgPath)
 91	communitiesByPkgPath.Set(communityPkgPath, info)
 92}
 93
 94func getCommunityByPkgPath(pkgPath string) *zenaov1.CommunityInfo {
 95	raw, ok := communitiesByPkgPath.Get(pkgPath)
 96	if !ok {
 97		return nil
 98	}
 99	return raw.(*zenaov1.CommunityInfo)
100}
101
102func mustGetCommunityByPkgPath(pkgPath string) *zenaov1.CommunityInfo {
103	info := getCommunityByPkgPath(pkgPath)
104	if info == nil {
105		panic(ErrCommunityNotFound)
106	}
107	return info
108}
109
110func listCommunities(limit, offset uint32) []*zenaov1.CommunityInfo {
111	return listCommunitiesInternal(&communitiesByPkgPath, "", "", false, limit, offset)
112}
113
114func listCommunitiesByMembers(memberID string, limit, offset uint32) []*zenaov1.CommunityInfo {
115	// ff is 255 in hex, which is the highest byte value, so it will match all keys that start with memberID.
116	fromKey := memberID + "/"
117	toKey := memberID + "/\xff"
118
119	return listCommunitiesInternal(&communityesByMembers, fromKey, toKey, false, limit, offset)
120}
121
122func listCommunitiesInternal(at avl.ITree, fromKey string, toKey string, rev bool, limit, offset uint32) []*zenaov1.CommunityInfo {
123	res := []*zenaov1.CommunityInfo{}
124	count := uint32(0)
125	it := func(key string, value interface{}) bool {
126		if count < offset {
127			count++
128			return false
129		}
130		var info zenaov1.CommunityInfo
131		switch val := value.(type) {
132		case *zenaov1.CommunityInfo:
133			info = *val
134		case string:
135			info = *mustGetCommunityByPkgPath(val)
136		}
137		info.PkgPath = key
138		res = append(res, &info)
139		return uint32(len(res)) >= limit
140	}
141	if rev {
142		at.ReverseIterate(toKey, fromKey, it)
143	} else {
144		at.Iterate(fromKey, toKey, it)
145	}
146	return res
147}