github.com/moleculer-go/moleculer@v0.3.3/registry/eventCatalog.go (about)

     1  package registry
     2  
     3  import (
     4  	"fmt"
     5  	"runtime/debug"
     6  	"sync"
     7  
     8  	"github.com/moleculer-go/moleculer"
     9  	"github.com/moleculer-go/moleculer/service"
    10  	"github.com/moleculer-go/moleculer/strategy"
    11  	log "github.com/sirupsen/logrus"
    12  )
    13  
    14  type EventEntry struct {
    15  	targetNodeID string
    16  	service      *service.Service
    17  	event        *service.Event
    18  	isLocal      bool
    19  }
    20  
    21  func (eventEntry EventEntry) TargetNodeID() string {
    22  	return eventEntry.targetNodeID
    23  }
    24  
    25  func (eventEntry *EventEntry) IsLocal() bool {
    26  	return eventEntry.isLocal
    27  }
    28  
    29  func (eventEntry *EventEntry) String() string {
    30  	return fmt.Sprint("EventEntry Node -> ", eventEntry.targetNodeID,
    31  		" - Service: ", eventEntry.event.ServiceName(),
    32  		" - Event Name: ", eventEntry.event.Name(),
    33  		" - Group: ", eventEntry.event.Group())
    34  }
    35  
    36  func catchEventError(context moleculer.BrokerContext, logger *log.Entry) {
    37  	if err := recover(); err != nil {
    38  		logger.Error("Event handler failed :( event: ", context.EventName(), " error: ", err, "\n[Stack Trace]: ", string(debug.Stack()))
    39  	}
    40  }
    41  
    42  func (eventEntry *EventEntry) emitLocalEvent(context moleculer.BrokerContext) {
    43  	logger := context.Logger().WithField("eventCatalog", "emitLocalEvent")
    44  	logger.Debug("Invoking local event: ", context.EventName())
    45  	defer catchEventError(context, logger)
    46  	handler := eventEntry.event.Handler()
    47  	handler(context.(moleculer.Context), context.Payload())
    48  	logger.Trace("After invoking local event: ", context.EventName())
    49  }
    50  
    51  type EventCatalog struct {
    52  	events sync.Map
    53  	logger *log.Entry
    54  }
    55  
    56  func CreateEventCatalog(logger *log.Entry) *EventCatalog {
    57  	events := sync.Map{}
    58  	return &EventCatalog{events: events, logger: logger}
    59  }
    60  
    61  // Add a new event to the catalog.
    62  func (eventCatalog *EventCatalog) Add(event service.Event, service *service.Service, local bool) {
    63  	entry := EventEntry{service.NodeID(), service, &event, local}
    64  	name := event.Name()
    65  	eventCatalog.logger.Debug("Add event name: ", name, " serviceName: ", event.ServiceName())
    66  	list, exists := eventCatalog.events.Load(name)
    67  	if !exists {
    68  		list = []EventEntry{entry}
    69  	} else {
    70  		list = append(list.([]EventEntry), entry)
    71  	}
    72  	eventCatalog.events.Store(name, list)
    73  }
    74  
    75  func (eventCatalog *EventCatalog) Update(nodeID string, name string, updates map[string]interface{}) {
    76  	//TODO .. the only thing that can be udpated is the Event Schema (validation) and that does not exist yet
    77  }
    78  
    79  func (eventCatalog *EventCatalog) listByName() map[string][]EventEntry {
    80  	result := make(map[string][]EventEntry)
    81  	eventCatalog.events.Range(func(key, value interface{}) bool {
    82  		result[key.(string)] = value.([]EventEntry)
    83  		return true
    84  	})
    85  	return result
    86  }
    87  
    88  func (eventCatalog *EventCatalog) Remove(nodeID string, name string) {
    89  	removed := 0
    90  	list, exists := eventCatalog.events.Load(name)
    91  	if !exists {
    92  		return
    93  	}
    94  	var newList []EventEntry
    95  	for _, event := range list.([]EventEntry) {
    96  		if event.targetNodeID != nodeID {
    97  			newList = append(newList, event)
    98  		} else {
    99  			removed++
   100  		}
   101  	}
   102  	eventCatalog.events.Store(name, newList)
   103  }
   104  
   105  // RemoveByNode remove events for the given nodeID.
   106  func (eventCatalog *EventCatalog) RemoveByNode(nodeID string) {
   107  	removed := 0
   108  	eventCatalog.events.Range(func(key, value interface{}) bool {
   109  		name := key.(string)
   110  		events := value.([]EventEntry)
   111  		var toKeep []EventEntry
   112  		for _, event := range events {
   113  			if event.targetNodeID != nodeID {
   114  				toKeep = append(toKeep, event)
   115  			} else {
   116  				removed++
   117  			}
   118  		}
   119  		eventCatalog.events.Store(name, toKeep)
   120  		return true
   121  	})
   122  }
   123  
   124  func matchGroup(event *service.Event, groups []string) bool {
   125  	if groups == nil || len(groups) == 0 {
   126  		return true
   127  	}
   128  	for _, group := range groups {
   129  		if event.Group() == group {
   130  			return true
   131  		}
   132  	}
   133  	return false
   134  }
   135  
   136  func findLocal(events []EventEntry) *EventEntry {
   137  	for _, item := range events {
   138  		if item.IsLocal() {
   139  			return &item
   140  		}
   141  	}
   142  	return nil
   143  }
   144  
   145  // Find find all events registered in this node and use the strategy to select and return the best one to be called.
   146  func (eventCatalog *EventCatalog) Find(name string, groups []string, preferLocal bool, localOnly bool, stg strategy.Strategy) []*EventEntry {
   147  	events, exists := eventCatalog.events.Load(name)
   148  	if !exists {
   149  		return make([]*EventEntry, 0)
   150  	}
   151  	eventCatalog.logger.Trace("event: ", name, " started: ", events)
   152  
   153  	entryGroups := make(map[string][]EventEntry)
   154  	for _, entry := range events.([]EventEntry) {
   155  		if localOnly && !entry.isLocal {
   156  			continue
   157  		}
   158  		if matchGroup(entry.event, groups) {
   159  			entryGroups[entry.event.Group()] = append(entryGroups[entry.event.Group()], entry)
   160  		}
   161  	}
   162  	var result []*EventEntry
   163  	for _, entries := range entryGroups {
   164  		if local := findLocal(entries); preferLocal && local != nil {
   165  			eventCatalog.logger.Trace("event: ", name, " found local: ", local)
   166  			result = append(result, local)
   167  		} else if len(entries) == 1 {
   168  			eventCatalog.logger.Debug("event: ", name, " found a single one :)  ", entries[0])
   169  			result = append(result, &entries[0])
   170  		} else if len(entries) > 1 {
   171  			if stg == nil {
   172  				eventCatalog.logger.Debug("event: ", name, " no strategy. return all entries: ", entries)
   173  				for _, entry := range entries {
   174  					result = append(result, &entry)
   175  				}
   176  			} else {
   177  				eventCatalog.logger.Debug("event: ", name, "using strategy to load balance between options: ", entries)
   178  				nodes := make([]strategy.Selector, len(entries))
   179  				for index, entry := range entries {
   180  					nodes[index] = &entry
   181  				}
   182  				if selected := stg.Select(nodes); selected != nil {
   183  					entry := (*selected).(*EventEntry)
   184  					result = append(result, entry)
   185  				}
   186  			}
   187  
   188  		}
   189  	}
   190  
   191  	return result
   192  }
   193  
   194  func (eventCatalog *EventCatalog) list() []EventEntry {
   195  	var result []EventEntry
   196  	eventCatalog.events.Range(func(key, value interface{}) bool {
   197  		entries := value.([]EventEntry)
   198  		for _, item := range entries {
   199  			result = append(result, item)
   200  		}
   201  		return true
   202  	})
   203  	return result
   204  }