github.com/hustcat/docker@v1.3.3-0.20160314103604-901c67a8eeab/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 }