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 }