eventreg.gno

5.82 Kb ยท 220 lines
  1package eventreg
  2
  3import (
  4	"errors"
  5	"std"
  6
  7	"gno.land/p/demo/avl"
  8	"gno.land/p/demo/ownable"
  9	"gno.land/p/demo/seqid"
 10	"gno.land/p/zenao/events"
 11	zenaov1 "gno.land/p/zenao/zenao/v1"
 12)
 13
 14// all dates are in unix seconds for easier interfacing with maketx call and vm/qeval
 15
 16var (
 17	Ownable *ownable.Ownable
 18
 19	registered          avl.Tree // <eventPkgPath> -> func() events.Info
 20	eventsByPkgPath     avl.Tree // <eventPkgPath> -> events.Info
 21	eventsByEndDate     avl.Tree // <endDateUnixSeconds>/<eventPkgPath> -> eventPkgPath
 22	eventsByParticipant avl.Tree // <participantID>/<endDateUnixSeconds>/<eventPkgPath> -> eventPkgPath
 23	eventsByCreator     avl.Tree // <creatorID>/<endDateUnixSeconds>/<eventPkgPath> -> eventPkgPath
 24	participantsByEvent avl.Tree // <eventPkgPath>/<participantID> -> participantID
 25)
 26
 27func init() {
 28	Ownable = ownable.NewWithAddress(std.Address("g1djrkw9tf4px658j85cc6fhsvm50uf9s0g6kfsm")) // zenao-dev-admin
 29}
 30
 31// XXX: split this package into eventreg and eventsindex
 32
 33func Register(infoGetter events.InfoGetter) {
 34	pkgPath := std.PreviousRealm().PkgPath()
 35
 36	if infoGetter == nil {
 37		registered.Remove(pkgPath)
 38		// XXX: remove from index??
 39		return
 40	}
 41
 42	registered.Set(pkgPath, infoGetter)
 43}
 44
 45func getInfo(pkgPath string) (*zenaov1.EventInfo, bool) {
 46	raw, ok := registered.Get(pkgPath)
 47	if !ok {
 48		return nil, false
 49	}
 50	return raw.(events.InfoGetter)(), true
 51}
 52
 53func mustGetInfo(pkgPath string) *zenaov1.EventInfo {
 54	info, ok := getInfo(pkgPath)
 55	if !ok {
 56		panic(ErrEventNotFound)
 57	}
 58	return info
 59}
 60
 61func IndexEvent(pkgPath string) {
 62	Ownable.AssertCallerIsOwner()
 63
 64	if prev := getEventByPkgPath(pkgPath); prev != nil {
 65		panic("already added")
 66	}
 67
 68	info := mustGetInfo(pkgPath)
 69	key := pkgPath
 70	eventsByPkgPath.Set(key, info)
 71
 72	key = unixTimeKey(info.EndDate) + "/" + pkgPath
 73	eventsByEndDate.Set(key, pkgPath)
 74
 75	key = info.Creator + "/" + unixTimeKey(info.EndDate) + "/" + pkgPath
 76	eventsByCreator.Set(key, pkgPath)
 77}
 78
 79func UpdateIndex(pkgPath string) {
 80	Ownable.AssertCallerIsOwner()
 81
 82	prevInfo := mustGetEventByPkgPath(pkgPath)
 83
 84	info := mustGetInfo(pkgPath)
 85	eventsByPkgPath.Set(pkgPath, info)
 86
 87	if prevInfo.EndDate != info.EndDate {
 88		key := unixTimeKey(prevInfo.EndDate) + "/" + pkgPath
 89		eventsByEndDate.Remove(key)
 90
 91		newKey := unixTimeKey(info.EndDate) + "/" + pkgPath
 92		eventsByEndDate.Set(newKey, pkgPath)
 93
 94		key = prevInfo.Creator + "/" + unixTimeKey(prevInfo.EndDate) + "/" + pkgPath
 95		eventsByCreator.Remove(key)
 96
 97		newKey = info.Creator + "/" + unixTimeKey(info.EndDate) + "/" + pkgPath
 98		eventsByCreator.Set(newKey, pkgPath)
 99
100		startKey := pkgPath + "/"
101		endKey := startKey[:len(startKey)-1] + string('/'+1)
102		participantsByEvent.Iterate(startKey, endKey, func(key string, value interface{}) bool {
103			userID := value.(string)
104
105			key = userID + "/" + unixTimeKey(prevInfo.EndDate) + "/" + pkgPath
106			eventsByParticipant.Remove(key)
107
108			newKey = userID + "/" + unixTimeKey(info.EndDate) + "/" + pkgPath
109			eventsByParticipant.Set(newKey, pkgPath)
110
111			return false
112		})
113	} else if prevInfo.Creator != info.Creator {
114		key := prevInfo.Creator + "/" + unixTimeKey(prevInfo.EndDate) + "/" + pkgPath
115		eventsByCreator.Remove(key)
116
117		newKey := info.Creator + "/" + unixTimeKey(info.EndDate) + "/" + pkgPath
118		eventsByCreator.Set(newKey, pkgPath)
119	}
120}
121
122func AddParticipant(eventPkgPath string, userID string) {
123	Ownable.AssertCallerIsOwner()
124
125	evt := mustGetEventByPkgPath(eventPkgPath)
126
127	key := userID + "/" + unixTimeKey(evt.EndDate) + "/" + eventPkgPath
128	eventsByParticipant.Set(key, eventPkgPath)
129
130	key = eventPkgPath + "/" + userID
131	participantsByEvent.Set(key, userID)
132
133	info := mustGetInfo(eventPkgPath)
134	eventsByPkgPath.Set(eventPkgPath, info)
135}
136
137func RemoveParticipant(eventPkgPath string, userID string) {
138	Ownable.AssertCallerIsOwner()
139
140	evt := mustGetEventByPkgPath(eventPkgPath)
141
142	key := userID + "/" + unixTimeKey(evt.EndDate) + "/" + eventPkgPath
143	eventsByParticipant.Remove(key)
144
145	key = eventPkgPath + "/" + userID
146	participantsByEvent.Remove(key)
147
148	info := mustGetInfo(eventPkgPath)
149	eventsByPkgPath.Set(eventPkgPath, info)
150}
151
152var ErrEventNotFound = errors.New("event not found")
153
154func getEventByPkgPath(pkgPath string) *zenaov1.EventInfo {
155	raw, ok := eventsByPkgPath.Get(pkgPath)
156	if !ok {
157		return nil
158	}
159	info := raw.(*zenaov1.EventInfo)
160	return info
161}
162
163func mustGetEventByPkgPath(pkgPath string) *zenaov1.EventInfo {
164	evt := getEventByPkgPath(pkgPath)
165	if evt == nil {
166		panic(ErrEventNotFound)
167	}
168	return evt
169}
170
171func listEvents(from, to int64, limit uint32) []*zenaov1.EventInfo {
172	fromKey := unixTimeKey(from) + "/"
173	toKey := unixTimeKey(to) + "/"
174
175	return listEventsInternal(&eventsByEndDate, fromKey, toKey, from > to, limit)
176}
177
178func listEventsByCreator(creatorID string, from, to int64, limit uint32) []*zenaov1.EventInfo {
179	fromKey := creatorID + "/" + unixTimeKey(from) + "/"
180	toKey := creatorID + "/" + unixTimeKey(to) + "/"
181
182	return listEventsInternal(&eventsByCreator, fromKey, toKey, from > to, limit)
183}
184
185func listEventsByParticipant(participantID string, from, to int64, limit uint32) []*zenaov1.EventInfo {
186	fromKey := participantID + "/" + unixTimeKey(from) + "/"
187	toKey := participantID + "/" + unixTimeKey(to) + "/"
188
189	return listEventsInternal(&eventsByParticipant, fromKey, toKey, from > to, limit)
190}
191
192func listEventsInternal(at avl.ITree, fromKey string, toKey string, rev bool, limit uint32) []*zenaov1.EventInfo {
193	res := []*zenaov1.EventInfo{}
194	it := func(key string, value interface{}) bool {
195		var evt zenaov1.EventInfo
196		switch val := value.(type) {
197		case *zenaov1.EventInfo:
198			evt = *val
199			evt.PkgPath = key
200		case string:
201			evt = *mustGetEventByPkgPath(val)
202			evt.PkgPath = val
203		}
204		res = append(res, &evt)
205		return uint32(len(res)) >= limit
206	}
207	if rev {
208		at.ReverseIterate(toKey, fromKey, it)
209	} else {
210		at.Iterate(fromKey, toKey, it)
211	}
212	return res
213}
214
215func unixTimeKey(t int64) string {
216	if t < 0 {
217		panic("negative unix time")
218	}
219	return seqid.ID(t).Binary()
220}