github.com/hms58/moby@v1.13.1/daemon/events/events.go (about)

     1  package events
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	eventtypes "github.com/docker/docker/api/types/events"
     8  	"github.com/docker/docker/pkg/pubsub"
     9  )
    10  
    11  const (
    12  	eventsLimit = 64
    13  	bufferSize  = 1024
    14  )
    15  
    16  // Events is pubsub channel for events generated by the engine.
    17  type Events struct {
    18  	mu     sync.Mutex
    19  	events []eventtypes.Message
    20  	pub    *pubsub.Publisher
    21  }
    22  
    23  // New returns new *Events instance
    24  func New() *Events {
    25  	return &Events{
    26  		events: make([]eventtypes.Message, 0, eventsLimit),
    27  		pub:    pubsub.NewPublisher(100*time.Millisecond, bufferSize),
    28  	}
    29  }
    30  
    31  // Subscribe adds new listener to events, returns slice of 64 stored
    32  // last events, a channel in which you can expect new events (in form
    33  // of interface{}, so you need type assertion), and a function to call
    34  // to stop the stream of events.
    35  func (e *Events) Subscribe() ([]eventtypes.Message, chan interface{}, func()) {
    36  	eventSubscribers.Inc()
    37  	e.mu.Lock()
    38  	current := make([]eventtypes.Message, len(e.events))
    39  	copy(current, e.events)
    40  	l := e.pub.Subscribe()
    41  	e.mu.Unlock()
    42  
    43  	cancel := func() {
    44  		e.Evict(l)
    45  	}
    46  	return current, l, cancel
    47  }
    48  
    49  // SubscribeTopic adds new listener to events, returns slice of 64 stored
    50  // last events, a channel in which you can expect new events (in form
    51  // of interface{}, so you need type assertion).
    52  func (e *Events) SubscribeTopic(since, until time.Time, ef *Filter) ([]eventtypes.Message, chan interface{}) {
    53  	eventSubscribers.Inc()
    54  	e.mu.Lock()
    55  
    56  	var topic func(m interface{}) bool
    57  	if ef != nil && ef.filter.Len() > 0 {
    58  		topic = func(m interface{}) bool { return ef.Include(m.(eventtypes.Message)) }
    59  	}
    60  
    61  	buffered := e.loadBufferedEvents(since, until, topic)
    62  
    63  	var ch chan interface{}
    64  	if topic != nil {
    65  		ch = e.pub.SubscribeTopic(topic)
    66  	} else {
    67  		// Subscribe to all events if there are no filters
    68  		ch = e.pub.Subscribe()
    69  	}
    70  
    71  	e.mu.Unlock()
    72  	return buffered, ch
    73  }
    74  
    75  // Evict evicts listener from pubsub
    76  func (e *Events) Evict(l chan interface{}) {
    77  	eventSubscribers.Dec()
    78  	e.pub.Evict(l)
    79  }
    80  
    81  // Log broadcasts event to listeners. Each listener has 100 millisecond for
    82  // receiving event or it will be skipped.
    83  func (e *Events) Log(action, eventType string, actor eventtypes.Actor) {
    84  	eventsCounter.Inc()
    85  	now := time.Now().UTC()
    86  	jm := eventtypes.Message{
    87  		Action:   action,
    88  		Type:     eventType,
    89  		Actor:    actor,
    90  		Time:     now.Unix(),
    91  		TimeNano: now.UnixNano(),
    92  	}
    93  
    94  	// fill deprecated fields for container and images
    95  	switch eventType {
    96  	case eventtypes.ContainerEventType:
    97  		jm.ID = actor.ID
    98  		jm.Status = action
    99  		jm.From = actor.Attributes["image"]
   100  	case eventtypes.ImageEventType:
   101  		jm.ID = actor.ID
   102  		jm.Status = action
   103  	}
   104  
   105  	e.mu.Lock()
   106  	if len(e.events) == cap(e.events) {
   107  		// discard oldest event
   108  		copy(e.events, e.events[1:])
   109  		e.events[len(e.events)-1] = jm
   110  	} else {
   111  		e.events = append(e.events, jm)
   112  	}
   113  	e.mu.Unlock()
   114  	e.pub.Publish(jm)
   115  }
   116  
   117  // SubscribersCount returns number of event listeners
   118  func (e *Events) SubscribersCount() int {
   119  	return e.pub.Len()
   120  }
   121  
   122  // loadBufferedEvents iterates over the cached events in the buffer
   123  // and returns those that were emitted between two specific dates.
   124  // It uses `time.Unix(seconds, nanoseconds)` to generate valid dates with those arguments.
   125  // It filters those buffered messages with a topic function if it's not nil, otherwise it adds all messages.
   126  func (e *Events) loadBufferedEvents(since, until time.Time, topic func(interface{}) bool) []eventtypes.Message {
   127  	var buffered []eventtypes.Message
   128  	if since.IsZero() && until.IsZero() {
   129  		return buffered
   130  	}
   131  
   132  	var sinceNanoUnix int64
   133  	if !since.IsZero() {
   134  		sinceNanoUnix = since.UnixNano()
   135  	}
   136  
   137  	var untilNanoUnix int64
   138  	if !until.IsZero() {
   139  		untilNanoUnix = until.UnixNano()
   140  	}
   141  
   142  	for i := len(e.events) - 1; i >= 0; i-- {
   143  		ev := e.events[i]
   144  
   145  		if ev.TimeNano < sinceNanoUnix {
   146  			break
   147  		}
   148  
   149  		if untilNanoUnix > 0 && ev.TimeNano > untilNanoUnix {
   150  			continue
   151  		}
   152  
   153  		if topic == nil || topic(ev) {
   154  			buffered = append([]eventtypes.Message{ev}, buffered...)
   155  		}
   156  	}
   157  	return buffered
   158  }