157 lines
3.1 KiB
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)
|
|
}
|