github.com/minio/mc@v0.0.0-20240503112107-b471de8d1882/cmd/watch.go (about) 1 // Copyright (c) 2015-2022 MinIO, Inc. 2 // 3 // This file is part of MinIO Object Storage stack 4 // 5 // This program is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Affero General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // This program is distributed in the hope that it will be useful 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Affero General Public License for more details. 14 // 15 // You should have received a copy of the GNU Affero General Public License 16 // along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 package cmd 19 20 import ( 21 "context" 22 "sync" 23 "time" 24 25 "github.com/minio/mc/pkg/probe" 26 "github.com/minio/minio-go/v7/pkg/notification" 27 ) 28 29 // EventInfo contains the information of the event that occurred and the source 30 // IP:PORT of the client which triggerred the event. 31 type EventInfo struct { 32 Time string 33 Size int64 34 UserMetadata map[string]string 35 Path string 36 Host string 37 Port string 38 UserAgent string 39 Type notification.EventType 40 } 41 42 // WatchOptions contains watch configuration options 43 type WatchOptions struct { 44 Prefix string 45 Suffix string 46 Events []string 47 Recursive bool 48 } 49 50 // WatchObject captures watch channels to read and listen on. 51 type WatchObject struct { 52 // eventInfo will be put on this chan 53 EventInfoChan chan []EventInfo 54 // errors will be put on this chan 55 ErrorChan chan *probe.Error 56 // will stop the watcher goroutines 57 DoneChan chan struct{} 58 } 59 60 // Events returns the chan receiving events 61 func (w *WatchObject) Events() chan []EventInfo { 62 return w.EventInfoChan 63 } 64 65 // Errors returns the chan receiving errors 66 func (w *WatchObject) Errors() chan *probe.Error { 67 return w.ErrorChan 68 } 69 70 // Watcher can be used to have one or multiple clients watch for notifications 71 type Watcher struct { 72 sessionStartTime time.Time 73 74 // all error will be added to this chan 75 ErrorChan chan *probe.Error 76 // all events will be added to this chan 77 EventInfoChan chan []EventInfo 78 79 // array of watchers joined 80 o []*WatchObject 81 82 // all watchers joining will enter this waitgroup 83 wg sync.WaitGroup 84 } 85 86 // NewWatcher creates a new watcher 87 func NewWatcher(sessionStartTime time.Time) *Watcher { 88 return &Watcher{ 89 sessionStartTime: sessionStartTime, 90 ErrorChan: make(chan *probe.Error), 91 EventInfoChan: make(chan []EventInfo), 92 o: []*WatchObject{}, 93 } 94 } 95 96 // Errors returns a channel which will receive errors 97 func (w *Watcher) Errors() chan *probe.Error { 98 return w.ErrorChan 99 } 100 101 // Events returns a channel which will receive events 102 func (w *Watcher) Events() chan []EventInfo { 103 return w.EventInfoChan 104 } 105 106 // Stop all watchers 107 func (w *Watcher) Stop() { 108 for _, w := range w.o { 109 close(w.DoneChan) 110 } 111 w.wg.Wait() 112 } 113 114 // Join the watcher with client 115 func (w *Watcher) Join(ctx context.Context, client Client, recursive bool) *probe.Error { 116 wo, err := client.Watch(ctx, WatchOptions{ 117 Recursive: recursive, 118 Events: []string{"put", "delete", "bucket-creation", "bucket-removal"}, 119 }) 120 if err != nil { 121 return err 122 } 123 124 w.o = append(w.o, wo) 125 126 // join monitoring waitgroup 127 w.wg.Add(1) 128 129 // wait for events and errors of individual client watchers 130 // and sent then to eventsChan and errorsChan 131 go func() { 132 defer w.wg.Done() 133 134 for { 135 select { 136 case <-wo.DoneChan: 137 return 138 case events, ok := <-wo.Events(): 139 if !ok { 140 return 141 } 142 w.EventInfoChan <- events 143 case err, ok := <-wo.Errors(): 144 if !ok { 145 return 146 } 147 148 w.ErrorChan <- err 149 } 150 } 151 }() 152 153 return nil 154 }