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  }