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 }