github.com/ojongerius/docker@v1.11.2/daemon/events/events.go (about)

     1  package events
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/docker/docker/pkg/pubsub"
     8  	eventtypes "github.com/docker/engine-api/types/events"
     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  	e.mu.Lock()
    37  	current := make([]eventtypes.Message, len(e.events))
    38  	copy(current, e.events)
    39  	l := e.pub.Subscribe()
    40  	e.mu.Unlock()
    41  
    42  	cancel := func() {
    43  		e.Evict(l)
    44  	}
    45  	return current, l, cancel
    46  }
    47  
    48  // SubscribeTopic adds new listener to events, returns slice of 64 stored
    49  // last events, a channel in which you can expect new events (in form
    50  // of interface{}, so you need type assertion).
    51  func (e *Events) SubscribeTopic(since, sinceNano int64, ef *Filter) ([]eventtypes.Message, chan interface{}) {
    52  	e.mu.Lock()
    53  
    54  	var topic func(m interface{}) bool
    55  	if ef != nil && ef.filter.Len() > 0 {
    56  		topic = func(m interface{}) bool { return ef.Include(m.(eventtypes.Message)) }
    57  	}
    58  
    59  	buffered := e.loadBufferedEvents(since, sinceNano, topic)
    60  
    61  	var ch chan interface{}
    62  	if topic != nil {
    63  		ch = e.pub.SubscribeTopic(topic)
    64  	} else {
    65  		// Subscribe to all events if there are no filters
    66  		ch = e.pub.Subscribe()
    67  	}
    68  
    69  	e.mu.Unlock()
    70  	return buffered, ch
    71  }
    72  
    73  // Evict evicts listener from pubsub
    74  func (e *Events) Evict(l chan interface{}) {
    75  	e.pub.Evict(l)
    76  }
    77  
    78  // Log broadcasts event to listeners. Each listener has 100 millisecond for
    79  // receiving event or it will be skipped.
    80  func (e *Events) Log(action, eventType string, actor eventtypes.Actor) {
    81  	now := time.Now().UTC()
    82  	jm := eventtypes.Message{
    83  		Action:   action,
    84  		Type:     eventType,
    85  		Actor:    actor,
    86  		Time:     now.Unix(),
    87  		TimeNano: now.UnixNano(),
    88  	}
    89  
    90  	// fill deprecated fields for container and images
    91  	switch eventType {
    92  	case eventtypes.ContainerEventType:
    93  		jm.ID = actor.ID
    94  		jm.Status = action
    95  		jm.From = actor.Attributes["image"]
    96  	case eventtypes.ImageEventType:
    97  		jm.ID = actor.ID
    98  		jm.Status = action
    99  	}
   100  
   101  	e.mu.Lock()
   102  	if len(e.events) == cap(e.events) {
   103  		// discard oldest event
   104  		copy(e.events, e.events[1:])
   105  		e.events[len(e.events)-1] = jm
   106  	} else {
   107  		e.events = append(e.events, jm)
   108  	}
   109  	e.mu.Unlock()
   110  	e.pub.Publish(jm)
   111  }
   112  
   113  // SubscribersCount returns number of event listeners
   114  func (e *Events) SubscribersCount() int {
   115  	return e.pub.Len()
   116  }
   117  
   118  // loadBufferedEvents iterates over the cached events in the buffer
   119  // and returns those that were emitted before a specific date.
   120  // The date is splitted in two values:
   121  //   - the `since` argument is a date timestamp without nanoseconds, or -1 to return an empty slice.
   122  //   - the `sinceNano` argument is the nanoseconds offset from the timestamp.
   123  // It uses `time.Unix(seconds, nanoseconds)` to generate a valid date with those two first arguments.
   124  // It filters those buffered messages with a topic function if it's not nil, otherwise it adds all messages.
   125  func (e *Events) loadBufferedEvents(since, sinceNano int64, topic func(interface{}) bool) []eventtypes.Message {
   126  	var buffered []eventtypes.Message
   127  	if since == -1 {
   128  		return buffered
   129  	}
   130  
   131  	sinceNanoUnix := time.Unix(since, sinceNano).UnixNano()
   132  	for i := len(e.events) - 1; i >= 0; i-- {
   133  		ev := e.events[i]
   134  		if ev.TimeNano < sinceNanoUnix {
   135  			break
   136  		}
   137  		if topic == nil || topic(ev) {
   138  			buffered = append([]eventtypes.Message{ev}, buffered...)
   139  		}
   140  	}
   141  	return buffered
   142  }