github.com/ruphin/docker@v1.10.1/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  	defer e.mu.Unlock()
    54  
    55  	var buffered []eventtypes.Message
    56  	topic := func(m interface{}) bool {
    57  		return ef.Include(m.(eventtypes.Message))
    58  	}
    59  
    60  	if since != -1 {
    61  		for i := len(e.events) - 1; i >= 0; i-- {
    62  			ev := e.events[i]
    63  			if ev.Time < since || ((ev.Time == since) && (ev.TimeNano < sinceNano)) {
    64  				break
    65  			}
    66  			if ef.filter.Len() == 0 || topic(ev) {
    67  				buffered = append([]eventtypes.Message{ev}, buffered...)
    68  			}
    69  		}
    70  	}
    71  
    72  	var ch chan interface{}
    73  	if ef.filter.Len() > 0 {
    74  		ch = e.pub.SubscribeTopic(topic)
    75  	} else {
    76  		// Subscribe to all events if there are no filters
    77  		ch = e.pub.Subscribe()
    78  	}
    79  
    80  	return buffered, ch
    81  }
    82  
    83  // Evict evicts listener from pubsub
    84  func (e *Events) Evict(l chan interface{}) {
    85  	e.pub.Evict(l)
    86  }
    87  
    88  // Log broadcasts event to listeners. Each listener has 100 millisecond for
    89  // receiving event or it will be skipped.
    90  func (e *Events) Log(action, eventType string, actor eventtypes.Actor) {
    91  	now := time.Now().UTC()
    92  	jm := eventtypes.Message{
    93  		Action:   action,
    94  		Type:     eventType,
    95  		Actor:    actor,
    96  		Time:     now.Unix(),
    97  		TimeNano: now.UnixNano(),
    98  	}
    99  
   100  	// fill deprecated fields for container and images
   101  	switch eventType {
   102  	case eventtypes.ContainerEventType:
   103  		jm.ID = actor.ID
   104  		jm.Status = action
   105  		jm.From = actor.Attributes["image"]
   106  	case eventtypes.ImageEventType:
   107  		jm.ID = actor.ID
   108  		jm.Status = action
   109  	}
   110  
   111  	e.mu.Lock()
   112  	if len(e.events) == cap(e.events) {
   113  		// discard oldest event
   114  		copy(e.events, e.events[1:])
   115  		e.events[len(e.events)-1] = jm
   116  	} else {
   117  		e.events = append(e.events, jm)
   118  	}
   119  	e.mu.Unlock()
   120  	e.pub.Publish(jm)
   121  }
   122  
   123  // SubscribersCount returns number of event listeners
   124  func (e *Events) SubscribersCount() int {
   125  	return e.pub.Len()
   126  }