strips.gno
3.92 Kb · 169 lines
1package kourtv3
2import bptree "gno.land/p/nt/bptree/v0"
3const stripActorCap = 5
4type stripRow struct {
5 slug string
6 claimID uint64
7}
8var globalStripIdx = bptree.NewBPTree32()
9func beHeightKey(h int64) string {
10 if h < 0 {
11 h = 0
12 }
13 return beClaimKey(uint64(h))
14}
15func stripDeadline(cs *claimState) int64 { return cs.answerHeight + settleDelay }
16func stripKey(cs *claimState) string {
17 return beHeightKey(stripDeadline(cs)) + beClaimKey(cs.id)
18}
19func globalStripKey(slug string, cs *claimState) string {
20 return beHeightKey(stripDeadline(cs)) + slug + beClaimKey(cs.id)
21}
22func pendingKey(cs *claimState) string {
23 return beHeightKey(cs.openedAt) + beClaimKey(cs.id)
24}
25func stripEnter(c *Court, cs *claimState) {
26 if cs.inStrip {
27 return
28 }
29 if c.stripIdx == nil {
30 c.stripIdx = bptree.NewBPTree32()
31 }
32 c.stripIdx.Set(stripKey(cs), cs.id)
33 globalStripIdx.Set(globalStripKey(c.id, cs), &stripRow{slug: c.id, claimID: cs.id})
34 cs.inStrip = true
35}
36func stripExit(c *Court, cs *claimState) {
37 if !cs.inStrip {
38 return
39 }
40 if c.stripIdx != nil {
41 c.stripIdx.Remove(stripKey(cs))
42 }
43 globalStripIdx.Remove(globalStripKey(c.id, cs))
44 cs.inStrip = false
45}
46func pendingEnter(c *Court, cs *claimState) {
47 if cs.inPending {
48 return
49 }
50 if c.pendingIdx == nil {
51 c.pendingIdx = bptree.NewBPTree32()
52 }
53 c.pendingIdx.Set(pendingKey(cs), cs.id)
54 cs.inPending = true
55}
56func pendingExit(c *Court, cs *claimState) {
57 if !cs.inPending {
58 return
59 }
60 if c.pendingIdx != nil {
61 c.pendingIdx.Remove(pendingKey(cs))
62 }
63 cs.inPending = false
64}
65func stripPageIDs(c *Court, offset, limit int) []uint64 {
66 out := []uint64{}
67 if c.stripIdx == nil || limit <= 0 {
68 return out
69 }
70 capBinds := c.stripIdx.Size() > renderPageSize
71 perAnswerer := map[string]int{}
72 perAuthor := map[string]int{}
73 skipped := 0
74 c.stripIdx.Iterate("", "", func(_ string, v any) bool {
75 id, ok := v.(uint64)
76 if !ok {
77 return false
78 }
79 cv := c.claims.Get(beClaimKey(id))
80 if cv == nil {
81 return false
82 }
83 cs := cv.(*claimState)
84 if capBinds && !cs.seeded {
85 a := cs.answerer.String()
86 b := cs.author.String()
87 if perAnswerer[a] >= stripActorCap || perAuthor[b] >= stripActorCap {
88 return false
89 }
90 perAnswerer[a]++
91 perAuthor[b]++
92 }
93 if skipped < offset {
94 skipped++
95 return false
96 }
97 out = append(out, id)
98 return len(out) >= limit
99 })
100 return out
101}
102func StripPage(courtSlug string, offset, limit int) []uint64 {
103 return stripPageIDs(mustCourt(courtSlug), offset, limit)
104}
105func StripSize(courtSlug string) int {
106 c := mustCourt(courtSlug)
107 if c.stripIdx == nil {
108 return 0
109 }
110 return c.stripIdx.Size()
111}
112func PendingPage(courtSlug string, offset, limit int) []uint64 {
113 out := []uint64{}
114 c := mustCourt(courtSlug)
115 if c.pendingIdx == nil || limit <= 0 {
116 return out
117 }
118 c.pendingIdx.IterateByOffset(offset, limit, func(_ string, v any) bool {
119 if id, ok := v.(uint64); ok {
120 out = append(out, id)
121 }
122 return false
123 })
124 return out
125}
126func PendingSize(courtSlug string) int {
127 c := mustCourt(courtSlug)
128 if c.pendingIdx == nil {
129 return 0
130 }
131 return c.pendingIdx.Size()
132}
133func DirectoryStripPage(offset, limit int) ([]string, []uint64) {
134 slugs := []string{}
135 ids := []uint64{}
136 if limit <= 0 {
137 return slugs, ids
138 }
139 capBinds := globalStripIdx.Size() > renderPageSize
140 perCourt := map[string]int{}
141 skipped := 0
142 globalStripIdx.Iterate("", "", func(_ string, v any) bool {
143 r, ok := v.(*stripRow)
144 if !ok {
145 return false
146 }
147 if capBinds {
148 if perCourt[r.slug] >= stripActorCap {
149 return false
150 }
151 perCourt[r.slug]++
152 }
153 if skipped < offset {
154 skipped++
155 return false
156 }
157 slugs = append(slugs, r.slug)
158 ids = append(ids, r.claimID)
159 return len(slugs) >= limit
160 })
161 return slugs, ids
162}
163func DirectoryStripSize() int { return globalStripIdx.Size() }
164func OnStrip(courtSlug string, claimID uint64) bool {
165 return mustClaim(mustCourt(courtSlug), claimID).inStrip
166}
167func OnPending(courtSlug string, claimID uint64) bool {
168 return mustClaim(mustCourt(courtSlug), claimID).inPending
169}