github.com/moleculer-go/moleculer@v0.3.3/registry/serviceCatalog.go (about) 1 package registry 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/moleculer-go/moleculer/service" 8 log "github.com/sirupsen/logrus" 9 ) 10 11 type ServiceCatalog struct { 12 services sync.Map 13 servicesByName sync.Map 14 logger *log.Entry 15 } 16 17 type ServiceEntry struct { 18 service *service.Service 19 nodeID string 20 } 21 22 func CreateServiceCatalog(logger *log.Entry) *ServiceCatalog { 23 services := sync.Map{} 24 servicesByName := sync.Map{} 25 return &ServiceCatalog{services, servicesByName, logger} 26 } 27 28 // createKey creates the catalogy key used in the map 29 func createKey(name, version, nodeID string) string { 30 return fmt.Sprintf("%s:%s:%s", nodeID, name, version) 31 } 32 33 // Has : Checks if a service for the given name, version and nodeID already exists in the catalog. 34 func (serviceCatalog *ServiceCatalog) Find(name string, version string, nodeID string) bool { 35 key := createKey(name, version, nodeID) 36 _, exists := serviceCatalog.services.Load(key) 37 return exists 38 } 39 40 func (serviceCatalog *ServiceCatalog) FindByName(name string) bool { 41 _, exists := serviceCatalog.servicesByName.Load(name) 42 return exists 43 } 44 45 // Get : Return the service for the given name, version and nodeID if it exists in the catalog. 46 func (serviceCatalog *ServiceCatalog) Get(name string, version string, nodeID string) *service.Service { 47 key := createKey(name, version, nodeID) 48 item, exists := serviceCatalog.services.Load(key) 49 if exists { 50 svc := item.(service.Service) 51 return &svc 52 } 53 return nil 54 } 55 56 // listByName list all service entriesf grouped by name. 57 func (serviceCatalog *ServiceCatalog) listByName() map[string][]ServiceEntry { 58 result := make(map[string][]ServiceEntry) 59 serviceCatalog.services.Range(func(key, value interface{}) bool { 60 serviceEntry := value.(ServiceEntry) 61 name := serviceEntry.service.FullName() 62 entries, exists := result[name] 63 if exists { 64 result[name] = append(entries, serviceEntry) 65 } else { 66 result[name] = []ServiceEntry{serviceEntry} 67 } 68 return true 69 }) 70 return result 71 } 72 73 // list all services in the catalog. 74 // func (serviceCatalog *ServiceCatalog) list() []*service.Service { 75 // var result []*service.Service 76 // serviceCatalog.services.Range(func(key, value interface{}) bool { 77 // entry := value.(ServiceEntry) 78 // result = append(result, entry.service) 79 // return true 80 // }) 81 // return result 82 // } 83 84 // RemoveByNode remove services for the given nodeID. 85 func (serviceCatalog *ServiceCatalog) RemoveByNode(nodeID string) []*service.Service { 86 var removed []*service.Service 87 serviceCatalog.logger.Debug("RemoveByNode() nodeID: ", nodeID) 88 var keysRemove []string 89 var namesRemove []string 90 var fullNamesRemove []string 91 serviceCatalog.services.Range(func(key, value interface{}) bool { 92 service := value.(ServiceEntry) 93 if service.nodeID == nodeID { 94 service := value.(ServiceEntry) 95 removed = append(removed, service.service) 96 keysRemove = append(keysRemove, key.(string)) 97 namesRemove = append(namesRemove, service.service.Name()) 98 fullNamesRemove = append(fullNamesRemove, service.service.FullName()) 99 } 100 return true 101 }) 102 for _, key := range keysRemove { 103 serviceCatalog.services.Delete(key) 104 } 105 for _, name := range namesRemove { 106 value, exists := serviceCatalog.servicesByName.Load(name) 107 if exists { 108 counter := value.(int) 109 counter = counter - 1 110 if counter < 0 { 111 counter = 0 112 } 113 serviceCatalog.servicesByName.Store(name, counter) 114 } 115 } 116 for _, name := range fullNamesRemove { 117 value, exists := serviceCatalog.servicesByName.Load(name) 118 if exists { 119 counter := value.(int) 120 counter = counter - 1 121 if counter < 0 { 122 counter = 0 123 } 124 serviceCatalog.servicesByName.Store(name, counter) 125 } 126 } 127 return removed 128 } 129 130 // Remove service for the given nodeID and service name. 131 func (serviceCatalog *ServiceCatalog) Remove(nodeID string, name string) []*service.Service { 132 var removed []*service.Service 133 serviceCatalog.logger.Debug("Remove() params -> nodeID:", nodeID, " name:", name) 134 var keysRemove []string 135 136 serviceCatalog.services.Range(func(key, value interface{}) bool { 137 service := value.(ServiceEntry) 138 serviceCatalog.logger.Debug("service.nodeID:", service.nodeID, " service.service.Name():", service.service.Name()) 139 if service.nodeID == nodeID && service.service.Name() == name { 140 service := value.(ServiceEntry) 141 removed = append(removed, service.service) 142 keysRemove = append(keysRemove, key.(string)) 143 } 144 return true 145 }) 146 serviceCatalog.logger.Debug("keysRemove: ", keysRemove) 147 for _, key := range keysRemove { 148 serviceCatalog.services.Delete(key) 149 } 150 return removed 151 } 152 153 // Add : add a service to the catalog. 154 func (serviceCatalog *ServiceCatalog) Add(service *service.Service) { 155 nodeID := service.NodeID() 156 key := createKey(service.Name(), service.Version(), nodeID) 157 serviceCatalog.services.Store(key, ServiceEntry{service, nodeID}) 158 value, exists := serviceCatalog.servicesByName.Load(service.FullName()) 159 if exists { 160 serviceCatalog.servicesByName.Store(service.FullName(), value.(int)+1) 161 serviceCatalog.servicesByName.Store(service.Name(), value.(int)+1) 162 } else { 163 serviceCatalog.servicesByName.Store(service.FullName(), 1) 164 serviceCatalog.servicesByName.Store(service.Name(), 1) 165 } 166 } 167 168 func serviceActionExists(name string, actions []service.Action) bool { 169 for _, action := range actions { 170 if action.FullName() == name { 171 return true 172 } 173 } 174 return false 175 } 176 177 func serviceEventExists(name string, events []service.Event) bool { 178 for _, event := range events { 179 if event.Name() == name { 180 return true 181 } 182 } 183 return false 184 } 185 186 // updateEvents takes the remote service definition and the current service definition and calculates what events are new, updated or removed. 187 // add new events to the service and return new, updated and deleted events. 188 func (serviceCatalog *ServiceCatalog) updateEvents(serviceMap map[string]interface{}, current *service.Service) ([]map[string]interface{}, []service.Event, []service.Event) { 189 var updated []map[string]interface{} 190 var newEvents, deletedEvents []service.Event 191 192 events := serviceMap["events"].(map[string]interface{}) 193 for _, item := range events { 194 event := item.(map[string]interface{}) 195 name := event["name"].(string) 196 if serviceEventExists(name, current.Events()) { 197 updated = append(updated, event) 198 } else { 199 serviceEvent := current.AddEventMap(event) 200 newEvents = append(newEvents, *serviceEvent) 201 } 202 } 203 for _, event := range current.Events() { 204 name := event.Name() 205 _, exists := events[name] 206 if !exists { 207 deletedEvents = append(deletedEvents, event) 208 current.RemoveEvent(name) 209 } 210 } 211 return updated, newEvents, deletedEvents 212 } 213 214 // updateActions takes the remote service definition and the current service definition and calculates what actions are new, updated or removed. 215 // add new actions to the service and return new, updated and deleted actions. 216 func (serviceCatalog *ServiceCatalog) updateActions(serviceMap map[string]interface{}, current *service.Service) ([]map[string]interface{}, []service.Action, []service.Action) { 217 var updatedActions []map[string]interface{} 218 var newActions, deletedActions []service.Action 219 220 actions := serviceMap["actions"].(map[string]interface{}) 221 for _, item := range actions { 222 action := item.(map[string]interface{}) 223 name := action["name"].(string) 224 if serviceActionExists(name, current.Actions()) { 225 updatedActions = append(updatedActions, action) 226 } else { 227 serviceAction := current.AddActionMap(action) 228 newActions = append(newActions, *serviceAction) 229 } 230 } 231 for _, action := range current.Actions() { 232 name := action.FullName() 233 _, exists := actions[name] 234 if !exists { 235 deletedActions = append(deletedActions, action) 236 current.RemoveAction(name) 237 } 238 } 239 return updatedActions, newActions, deletedActions 240 } 241 242 // updateRemote : update remote service info and return what actions are new, updated and deleted 243 func (serviceCatalog *ServiceCatalog) updateRemote(nodeID string, serviceInfo map[string]interface{}) (*service.Service, bool, []map[string]interface{}, []service.Action, []service.Action, []map[string]interface{}, []service.Event, []service.Event) { 244 245 key := createKey(serviceInfo["name"].(string), service.ParseVersion(serviceInfo["version"]), nodeID) 246 item, serviceExists := serviceCatalog.services.Load(key) 247 248 if serviceExists { 249 entry := item.(ServiceEntry) 250 current := entry.service 251 current.UpdateFromMap(serviceInfo) 252 updatedActions, newActions, deletedActions := serviceCatalog.updateActions(serviceInfo, current) 253 updatedEvents, newEvents, deletedEvents := serviceCatalog.updateEvents(serviceInfo, current) 254 return current, false, updatedActions, newActions, deletedActions, updatedEvents, newEvents, deletedEvents 255 } 256 257 newService := service.CreateServiceFromMap(serviceInfo) 258 newService.SetNodeID(nodeID) 259 serviceCatalog.Add(newService) 260 261 newActions := newService.Actions() 262 updatedActions := make([]map[string]interface{}, 0) 263 deletedActions := make([]service.Action, 0) 264 265 newEvents := newService.Events() 266 updatedEvents := make([]map[string]interface{}, 0) 267 deletedEvents := make([]service.Event, 0) 268 return newService, true, updatedActions, newActions, deletedActions, updatedEvents, newEvents, deletedEvents 269 270 }