olivetin/service/internal/entities/storage.go

157 lines
3.1 KiB
Go

package entities
/**
* The ephemeralvariablemap is used "only" for variable substitution in config
* titles, shell arguments, etc, in the foorm of {{ key }}, like Jinja2.
*
* OliveTin itself really only ever "writes" to this map, mostly by loading
* EntityFiles, and the only form of "reading" is for the variable substitution
* in configs.
*/
import (
"maps"
"sort"
"strconv"
"strings"
"sync"
)
type entityInstancesByKey map[string]*Entity
type EntitiesByClass map[string]entityInstancesByKey
var (
rwmutex = sync.RWMutex{}
entities EntitiesByClass
)
func init() {
rwmutex.Lock()
entities = make(EntitiesByClass, 0)
rwmutex.Unlock()
}
func GetEntities() EntitiesByClass {
rwmutex.RLock()
copiedEntities := make(EntitiesByClass, len(entities))
for entityName, entityInstances := range entities {
copiedInstances := make(entityInstancesByKey, len(entityInstances))
maps.Copy(copiedInstances, entityInstances)
copiedEntities[entityName] = copiedInstances
}
rwmutex.RUnlock()
return copiedEntities
}
func GetEntityInstances(entityName string) entityInstancesByKey {
rwmutex.RLock()
defer rwmutex.RUnlock()
if entities, ok := entities[entityName]; ok {
copiedInstances := make(entityInstancesByKey, len(entities))
maps.Copy(copiedInstances, entities)
return copiedInstances
}
return make(entityInstancesByKey, 0)
}
func GetEntityInstancesOrdered(entityName string) []*Entity {
instances := GetEntityInstances(entityName)
if len(instances) == 0 {
return nil
}
keys := make([]string, 0, len(instances))
for key := range instances {
keys = append(keys, key)
}
sort.Slice(keys, func(i, j int) bool {
return compareEntityKeys(keys[i], keys[j]) < 0
})
result := make([]*Entity, 0, len(keys))
for _, key := range keys {
result = append(result, instances[key])
}
return result
}
//gocyclo:ignore
func compareEntityKeys(a, b string) int {
ai, errA := strconv.ParseInt(a, 10, 64)
bi, errB := strconv.ParseInt(b, 10, 64)
if errA == nil && errB == nil {
if ai < bi {
return -1
}
if ai > bi {
return 1
}
return 0
}
if a < b {
return -1
}
if a > b {
return 1
}
return 0
}
func AddEntity(entityName string, entityKey string, data any) {
rwmutex.Lock()
if _, ok := entities[entityName]; !ok {
entities[entityName] = make(entityInstancesByKey, 0)
}
entities[entityName][entityKey] = &Entity{
Data: data,
UniqueKey: entityKey,
Title: findEntityTitle(data),
}
rwmutex.Unlock()
}
//gocyclo:ignore
func findEntityTitle(data any) string {
if mapData, ok := data.(map[string]any); ok {
keys := make(map[string]string)
for k := range mapData {
lookupKey := strings.ToLower(k)
keys[lookupKey] = k
}
for _, key := range []string{"title", "name", "id", "hostname", "host", "label"} {
if lookupKey, exists := keys[strings.ToLower(key)]; exists {
if value, ok := mapData[lookupKey]; ok {
if valueStr, ok := value.(string); ok {
return valueStr
}
}
}
}
}
return "Untitled Entity"
}
func ClearEntitiesOfType(entityType string) {
rwmutex.Lock()
defer rwmutex.Unlock()
delete(entities, entityType)
}