github.com/walkingsparrow/docker@v1.4.2-0.20151218153551-b708a2249bfa/daemon/events/events.go (about)

     1  package events
     2  
     3  import (
     4  	"sync"
     5  	"time"
     6  
     7  	"github.com/docker/docker/pkg/jsonmessage"
     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 *jsonmessage.JSONMessage
    17  type Events struct {
    18  	mu     sync.Mutex
    19  	events []*jsonmessage.JSONMessage
    20  	pub    *pubsub.Publisher
    21  }
    22  
    23  // New returns new *Events instance
    24  func New() *Events {
    25  	return &Events{
    26  		events: make([]*jsonmessage.JSONMessage, 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() ([]*jsonmessage.JSONMessage, chan interface{}, func()) {
    36  	e.mu.Lock()
    37  	current := make([]*jsonmessage.JSONMessage, 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) ([]*jsonmessage.JSONMessage, chan interface{}) {
    52  	e.mu.Lock()
    53  	defer e.mu.Unlock()
    54  
    55  	var buffered []*jsonmessage.JSONMessage
    56  	topic := func(m interface{}) bool {
    57  		return ef.Include(m.(*jsonmessage.JSONMessage))
    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([]*jsonmessage.JSONMessage{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, id, from string) {
    91  	now := time.Now().UTC()
    92  	jm := &jsonmessage.JSONMessage{Status: action, ID: id, From: from, Time: now.Unix(), TimeNano: now.UnixNano()}
    93  	e.mu.Lock()
    94  	if len(e.events) == cap(e.events) {
    95  		// discard oldest event
    96  		copy(e.events, e.events[1:])
    97  		e.events[len(e.events)-1] = jm
    98  	} else {
    99  		e.events = append(e.events, jm)
   100  	}
   101  	e.mu.Unlock()
   102  	e.pub.Publish(jm)
   103  }
   104  
   105  // SubscribersCount returns number of event listeners
   106  func (e *Events) SubscribersCount() int {
   107  	return e.pub.Len()
   108  }