communityreg.gno

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