eventreg.gno

6.37 Kb ยท 246 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	eventsByOrganizer   avl.Tree // <organizerID>/<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	for _, organizer := range info.Organizers {
 76		key = organizer + "/" + unixTimeKey(info.EndDate) + "/" + pkgPath
 77		eventsByOrganizer.Set(key, pkgPath)
 78	}
 79}
 80
 81func UpdateIndex(pkgPath string) {
 82	Ownable.AssertCallerIsOwner()
 83
 84	prevInfo := mustGetEventByPkgPath(pkgPath)
 85
 86	info := mustGetInfo(pkgPath)
 87	eventsByPkgPath.Set(pkgPath, info)
 88
 89	if prevInfo.EndDate != info.EndDate {
 90		key := unixTimeKey(prevInfo.EndDate) + "/" + pkgPath
 91		eventsByEndDate.Remove(key)
 92
 93		newKey := unixTimeKey(info.EndDate) + "/" + pkgPath
 94		eventsByEndDate.Set(newKey, pkgPath)
 95
 96		for _, organizer := range prevInfo.Organizers {
 97			key = organizer + "/" + unixTimeKey(prevInfo.EndDate) + "/" + pkgPath
 98			eventsByOrganizer.Remove(key)
 99		}
100
101		for _, organizer := range info.Organizers {
102			key = organizer + "/" + unixTimeKey(info.EndDate) + "/" + pkgPath
103			eventsByOrganizer.Set(key, pkgPath)
104		}
105
106		startKey := pkgPath + "/"
107		endKey := startKey[:len(startKey)-1] + string('/'+1)
108		participantsByEvent.Iterate(startKey, endKey, func(key string, value interface{}) bool {
109			userID := value.(string)
110
111			key = userID + "/" + unixTimeKey(prevInfo.EndDate) + "/" + pkgPath
112			eventsByParticipant.Remove(key)
113
114			newKey = userID + "/" + unixTimeKey(info.EndDate) + "/" + pkgPath
115			eventsByParticipant.Set(newKey, pkgPath)
116
117			return false
118		})
119	} else if !sliceIsEqual(prevInfo.Organizers, info.Organizers) {
120		for _, organizer := range prevInfo.Organizers {
121			key := organizer + "/" + unixTimeKey(prevInfo.EndDate) + "/" + pkgPath
122			eventsByOrganizer.Remove(key)
123		}
124		for _, organizer := range info.Organizers {
125			key := organizer + "/" + unixTimeKey(info.EndDate) + "/" + pkgPath
126			eventsByOrganizer.Set(key, pkgPath)
127		}
128	}
129}
130
131func AddParticipant(eventPkgPath string, userID string) {
132	Ownable.AssertCallerIsOwner()
133
134	evt := mustGetEventByPkgPath(eventPkgPath)
135
136	key := userID + "/" + unixTimeKey(evt.EndDate) + "/" + eventPkgPath
137	eventsByParticipant.Set(key, eventPkgPath)
138
139	key = eventPkgPath + "/" + userID
140	participantsByEvent.Set(key, userID)
141
142	info := mustGetInfo(eventPkgPath)
143	eventsByPkgPath.Set(eventPkgPath, info)
144}
145
146func RemoveParticipant(eventPkgPath string, userID string) {
147	Ownable.AssertCallerIsOwner()
148
149	evt := mustGetEventByPkgPath(eventPkgPath)
150
151	key := userID + "/" + unixTimeKey(evt.EndDate) + "/" + eventPkgPath
152	eventsByParticipant.Remove(key)
153
154	key = eventPkgPath + "/" + userID
155	participantsByEvent.Remove(key)
156
157	info := mustGetInfo(eventPkgPath)
158	eventsByPkgPath.Set(eventPkgPath, info)
159}
160
161var ErrEventNotFound = errors.New("event not found")
162
163func getEventByPkgPath(pkgPath string) *zenaov1.EventInfo {
164	raw, ok := eventsByPkgPath.Get(pkgPath)
165	if !ok {
166		return nil
167	}
168	info := raw.(*zenaov1.EventInfo)
169	return info
170}
171
172func mustGetEventByPkgPath(pkgPath string) *zenaov1.EventInfo {
173	evt := getEventByPkgPath(pkgPath)
174	if evt == nil {
175		panic(ErrEventNotFound)
176	}
177	return evt
178}
179
180func listEvents(from, to int64, limit, offset uint32) []*zenaov1.EventInfo {
181	fromKey := unixTimeKey(from) + "/"
182	toKey := unixTimeKey(to) + "/"
183
184	return listEventsInternal(&eventsByEndDate, fromKey, toKey, from > to, limit, offset)
185}
186
187func listEventsByOrganizer(organizerID string, from, to int64, limit, offset uint32) []*zenaov1.EventInfo {
188	fromKey := organizerID + "/" + unixTimeKey(from) + "/"
189	toKey := organizerID + "/" + unixTimeKey(to) + "/"
190
191	return listEventsInternal(&eventsByOrganizer, fromKey, toKey, from > to, limit, offset)
192}
193
194func listEventsByParticipant(participantID string, from, to int64, limit, offset uint32) []*zenaov1.EventInfo {
195	fromKey := participantID + "/" + unixTimeKey(from) + "/"
196	toKey := participantID + "/" + unixTimeKey(to) + "/"
197
198	return listEventsInternal(&eventsByParticipant, fromKey, toKey, from > to, limit, offset)
199}
200
201func listEventsInternal(at avl.ITree, fromKey string, toKey string, rev bool, limit, offset uint32) []*zenaov1.EventInfo {
202	res := []*zenaov1.EventInfo{}
203	count := uint32(0)
204	it := func(key string, value interface{}) bool {
205		if count < offset {
206			count++
207			return false
208		}
209		var evt zenaov1.EventInfo
210		switch val := value.(type) {
211		case *zenaov1.EventInfo:
212			evt = *val
213			evt.PkgPath = key
214		case string:
215			evt = *mustGetEventByPkgPath(val)
216			evt.PkgPath = val
217		}
218		res = append(res, &evt)
219		return uint32(len(res)) >= limit
220	}
221	if rev {
222		at.ReverseIterate(toKey, fromKey, it)
223	} else {
224		at.Iterate(fromKey, toKey, it)
225	}
226	return res
227}
228
229func unixTimeKey(t int64) string {
230	if t < 0 {
231		panic("negative unix time")
232	}
233	return seqid.ID(t).Binary()
234}
235
236func sliceIsEqual(a, b []string) bool {
237	if len(a) != len(b) {
238		return false
239	}
240	for i, v := range a {
241		if v != b[i] {
242			return false
243		}
244	}
245	return true
246}