Files
goclaw/internal/channels/replycontext/reply-context-store.go
T
2026-07-03 06:53:46 +07:00

98 lines
2.3 KiB
Go

package replycontext
import (
"strings"
"time"
)
func scopedKey(scope Scope, messageID string) cacheKey {
return cacheKey{
tenant: strings.TrimSpace(scope.TenantID),
channel: strings.TrimSpace(scope.ChannelID),
thread: strings.TrimSpace(scope.ThreadID),
message: strings.TrimSpace(messageID),
}
}
func (c *Cache) lookupLocked(scope Scope, ids []string) *node {
for _, id := range ids {
key := scopedKey(scope, id)
if canonical, ok := c.aliases[key]; ok {
return c.nodes[canonical]
}
if n := c.nodes[key]; n != nil {
return n
}
}
return nil
}
func (c *Cache) collectChainLocked(scope Scope, start *node) []renderMessage {
visited := make(map[cacheKey]struct{}, c.opts.MaxDepth)
reversed := make([]renderMessage, 0, c.opts.MaxDepth)
for n := start; n != nil && len(reversed) < c.opts.MaxDepth; {
if _, ok := visited[n.key]; ok {
break
}
visited[n.key] = struct{}{}
reversed = append(reversed, renderMessage{sender: n.sender, body: n.body})
parent := c.lookupLocked(scope, n.parentIDs)
if parent == nil && len(reversed) < c.opts.MaxDepth {
if fallback := n.parentFallback(); fallback.body != "" {
reversed = append(reversed, fallback)
}
}
n = parent
}
for i, j := 0, len(reversed)-1; i < j; i, j = i+1, j-1 {
reversed[i], reversed[j] = reversed[j], reversed[i]
}
return reversed
}
func (n *node) parentFallback() renderMessage {
return renderMessage{
sender: n.parentQuote.Sender,
body: n.parentQuote.Body,
}
}
func (c *Cache) purgeExpiredLocked(now time.Time) {
if c.opts.TTL <= 0 {
return
}
for key, n := range c.nodes {
if now.Sub(n.createdAt) > c.opts.TTL {
c.deleteNodeLocked(key, n)
}
}
}
func (c *Cache) evictLocked() {
for len(c.nodes) > c.opts.MaxEntries {
var oldestKey cacheKey
var oldest *node
for key, n := range c.nodes {
if oldest == nil || n.createdAt.Before(oldest.createdAt) {
oldestKey = key
oldest = n
}
}
if oldest == nil {
return
}
c.deleteNodeLocked(oldestKey, oldest)
}
}
func (c *Cache) deleteNodeLocked(key cacheKey, n *node) {
delete(c.nodes, key)
for _, id := range n.ids {
aliasKey := cacheKey{tenant: key.tenant, channel: key.channel, thread: key.thread, message: id}
if c.aliases[aliasKey] == key {
delete(c.aliases, aliasKey)
}
}
}