Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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}