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}
eventreg.gno
6.37 Kb ยท 246 lines