// Watch is the primary listener for this resource and it outputs events. // This one is a file watcher for files and directories. // Modify with caution, it is probably important to write some test cases first! // If the Watch returns an error, it means that something has gone wrong, and it // must be restarted. On a clean exit it returns nil. // FIXME: Also watch the source directory when using obj.Source !!! func (obj *FileRes) Watch(processChan chan event.Event) error { if obj.IsWatching() { return nil // TODO: should this be an error? } obj.SetWatching(true) defer obj.SetWatching(false) cuid := obj.converger.Register() defer cuid.Unregister() var startup bool Startup := func(block bool) <-chan time.Time { if block { return nil // blocks forever //return make(chan time.Time) // blocks forever } return time.After(time.Duration(500) * time.Millisecond) // 1/2 the resolution of converged timeout } var err error obj.recWatcher, err = recwatch.NewRecWatcher(obj.Path, obj.Recurse) if err != nil { return err } defer obj.recWatcher.Close() var send = false // send event? var exit = false var dirty = false for { if global.DEBUG { log.Printf("%s[%s]: Watching: %s", obj.Kind(), obj.GetName(), obj.Path) // attempting to watch... } obj.SetState(ResStateWatching) // reset select { case event, ok := <-obj.recWatcher.Events(): if !ok { // channel shutdown return nil } cuid.SetConverged(false) if err := event.Error; err != nil { return errwrap.Wrapf(err, "Unknown %s[%s] watcher error", obj.Kind(), obj.GetName()) } if global.DEBUG { // don't access event.Body if event.Error isn't nil log.Printf("%s[%s]: Event(%s): %v", obj.Kind(), obj.GetName(), event.Body.Name, event.Body.Op) } send = true dirty = true case event := <-obj.Events(): cuid.SetConverged(false) if exit, send = obj.ReadEvent(&event); exit { return nil // exit } //dirty = false // these events don't invalidate state case <-cuid.ConvergedTimer(): cuid.SetConverged(true) // converged! continue case <-Startup(startup): cuid.SetConverged(false) send = true dirty = true } // do all our event sending all together to avoid duplicate msgs if send { startup = true // startup finished send = false // only invalid state on certain types of events if dirty { dirty = false obj.isStateOK = false // something made state dirty } if exit, err := obj.DoSend(processChan, ""); exit || err != nil { return err // we exit or bubble up a NACK... } } } }
// Watch is the primary listener for this resource and it outputs events. func (obj *PasswordRes) Watch(processChan chan event.Event) error { if obj.IsWatching() { return nil // TODO: should this be an error? } obj.SetWatching(true) defer obj.SetWatching(false) cuid := obj.converger.Register() defer cuid.Unregister() var startup bool Startup := func(block bool) <-chan time.Time { if block { return nil // blocks forever //return make(chan time.Time) // blocks forever } return time.After(time.Duration(500) * time.Millisecond) // 1/2 the resolution of converged timeout } var err error obj.recWatcher, err = recwatch.NewRecWatcher(obj.path, false) if err != nil { return err } defer obj.recWatcher.Close() var send = false // send event? var exit = false for { obj.SetState(ResStateWatching) // reset select { // NOTE: this part is very similar to the file resource code case event, ok := <-obj.recWatcher.Events(): if !ok { // channel shutdown return nil } cuid.SetConverged(false) if err := event.Error; err != nil { return errwrap.Wrapf(err, "Unknown %s[%s] watcher error", obj.Kind(), obj.GetName()) } send = true obj.StateOK(false) // dirty case event := <-obj.Events(): cuid.SetConverged(false) // we avoid sending events on unpause if exit, send = obj.ReadEvent(&event); exit { return nil // exit } case <-cuid.ConvergedTimer(): cuid.SetConverged(true) // converged! continue case <-Startup(startup): cuid.SetConverged(false) send = true } // do all our event sending all together to avoid duplicate msgs if send { startup = true // startup finished send = false if exit, err := obj.DoSend(processChan, ""); exit || err != nil { return err // we exit or bubble up a NACK... } } } }