FILE / ScuroNeko/Laniakea
scene_locks.go
Исходный файл и его история в репозитории.
(fix): runtime reliability (tests): regression coverage (doc): v1.1 release notes
81 lines
1.5 KiB
Go
81 lines
1.5 KiB
Go
package laniakea
|
|
|
|
import (
|
|
"sort"
|
|
"sync"
|
|
)
|
|
|
|
type sceneLockEntry struct {
|
|
mu sync.Mutex
|
|
refs int
|
|
}
|
|
|
|
type sceneKeyLocker struct {
|
|
mu sync.Mutex
|
|
entries map[string]*sceneLockEntry
|
|
}
|
|
|
|
func (l *sceneKeyLocker) lock(keys []string) func() {
|
|
keys = uniqueSortedStrings(keys)
|
|
if len(keys) == 0 {
|
|
return func() {}
|
|
}
|
|
|
|
l.mu.Lock()
|
|
if l.entries == nil {
|
|
l.entries = make(map[string]*sceneLockEntry)
|
|
}
|
|
entries := make([]*sceneLockEntry, len(keys))
|
|
for i, key := range keys {
|
|
entry := l.entries[key]
|
|
if entry == nil {
|
|
entry = new(sceneLockEntry)
|
|
l.entries[key] = entry
|
|
}
|
|
entry.refs++
|
|
entries[i] = entry
|
|
}
|
|
l.mu.Unlock()
|
|
|
|
for _, entry := range entries {
|
|
entry.mu.Lock()
|
|
}
|
|
|
|
return func() {
|
|
for i := len(entries) - 1; i >= 0; i-- {
|
|
entries[i].mu.Unlock()
|
|
}
|
|
|
|
l.mu.Lock()
|
|
for i, key := range keys {
|
|
entries[i].refs--
|
|
if entries[i].refs == 0 {
|
|
delete(l.entries, key)
|
|
}
|
|
}
|
|
l.mu.Unlock()
|
|
}
|
|
}
|
|
|
|
func uniqueSortedStrings(values []string) []string {
|
|
sort.Strings(values)
|
|
result := values[:0]
|
|
for _, value := range values {
|
|
if value == "" || len(result) > 0 && result[len(result)-1] == value {
|
|
continue
|
|
}
|
|
result = append(result, value)
|
|
}
|
|
return result
|
|
}
|
|
|
|
func sceneKeysForContext(ctx *MessageContext) []string {
|
|
keys := make([]string, 0, 3)
|
|
for _, scope := range []SceneScope{SceneScopeUserChat, SceneScopeChat, SceneScopeUser} {
|
|
if key, ok := buildSceneKey(scope, ctx); ok {
|
|
keys = append(keys, key)
|
|
}
|
|
}
|
|
return keys
|
|
}
|