storage.go 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package entities
  2. /**
  3. * The ephemeralvariablemap is used "only" for variable substitution in config
  4. * titles, shell arguments, etc, in the foorm of {{ key }}, like Jinja2.
  5. *
  6. * OliveTin itself really only ever "writes" to this map, mostly by loading
  7. * EntityFiles, and the only form of "reading" is for the variable substitution
  8. * in configs.
  9. */
  10. import (
  11. "sort"
  12. "strconv"
  13. "strings"
  14. "sync"
  15. )
  16. type entityInstancesByKey map[string]*Entity
  17. type EntitiesByClass map[string]entityInstancesByKey
  18. var (
  19. rwmutex = sync.RWMutex{}
  20. entities EntitiesByClass
  21. )
  22. func init() {
  23. rwmutex.Lock()
  24. entities = make(EntitiesByClass, 0)
  25. rwmutex.Unlock()
  26. }
  27. func GetEntities() EntitiesByClass {
  28. rwmutex.RLock()
  29. copiedEntities := make(EntitiesByClass, len(entities))
  30. for entityName, entityInstances := range entities {
  31. copiedInstances := make(entityInstancesByKey, len(entityInstances))
  32. for key, entity := range entityInstances {
  33. copiedInstances[key] = entity
  34. }
  35. copiedEntities[entityName] = copiedInstances
  36. }
  37. rwmutex.RUnlock()
  38. return copiedEntities
  39. }
  40. func GetEntityInstances(entityName string) entityInstancesByKey {
  41. rwmutex.RLock()
  42. defer rwmutex.RUnlock()
  43. if entities, ok := entities[entityName]; ok {
  44. copiedInstances := make(entityInstancesByKey, len(entities))
  45. for key, entity := range entities {
  46. copiedInstances[key] = entity
  47. }
  48. return copiedInstances
  49. }
  50. return make(entityInstancesByKey, 0)
  51. }
  52. func GetEntityInstancesOrdered(entityName string) []*Entity {
  53. instances := GetEntityInstances(entityName)
  54. if len(instances) == 0 {
  55. return nil
  56. }
  57. keys := make([]string, 0, len(instances))
  58. for key := range instances {
  59. keys = append(keys, key)
  60. }
  61. sort.Slice(keys, func(i, j int) bool {
  62. return compareEntityKeys(keys[i], keys[j]) < 0
  63. })
  64. result := make([]*Entity, 0, len(keys))
  65. for _, key := range keys {
  66. result = append(result, instances[key])
  67. }
  68. return result
  69. }
  70. //gocyclo:ignore
  71. func compareEntityKeys(a, b string) int {
  72. ai, errA := strconv.ParseInt(a, 10, 64)
  73. bi, errB := strconv.ParseInt(b, 10, 64)
  74. if errA == nil && errB == nil {
  75. if ai < bi {
  76. return -1
  77. }
  78. if ai > bi {
  79. return 1
  80. }
  81. return 0
  82. }
  83. if a < b {
  84. return -1
  85. }
  86. if a > b {
  87. return 1
  88. }
  89. return 0
  90. }
  91. func AddEntity(entityName string, entityKey string, data any) {
  92. rwmutex.Lock()
  93. if _, ok := entities[entityName]; !ok {
  94. entities[entityName] = make(entityInstancesByKey, 0)
  95. }
  96. entities[entityName][entityKey] = &Entity{
  97. Data: data,
  98. UniqueKey: entityKey,
  99. Title: findEntityTitle(data),
  100. }
  101. rwmutex.Unlock()
  102. }
  103. //gocyclo:ignore
  104. func findEntityTitle(data any) string {
  105. if mapData, ok := data.(map[string]any); ok {
  106. keys := make(map[string]string)
  107. for k := range mapData {
  108. lookupKey := strings.ToLower(k)
  109. keys[lookupKey] = k
  110. }
  111. for _, key := range []string{"title", "name", "id", "hostname", "host", "label"} {
  112. if lookupKey, exists := keys[strings.ToLower(key)]; exists {
  113. if value, ok := mapData[lookupKey]; ok {
  114. if valueStr, ok := value.(string); ok {
  115. return valueStr
  116. }
  117. }
  118. }
  119. }
  120. }
  121. return "Untitled Entity"
  122. }
  123. func ClearEntitiesOfType(entityType string) {
  124. rwmutex.Lock()
  125. defer rwmutex.Unlock()
  126. delete(entities, entityType)
  127. }