github.com/cloud-foundations/dominator@v0.0.0-20221004181915-6e4fee580046/lib/fsutil/watchFile_linux.go (about)

     1  package fsutil
     2  
     3  import (
     4  	"io"
     5  	"os"
     6  	"path"
     7  	"sync"
     8  
     9  	"github.com/Cloud-Foundations/Dominator/lib/log"
    10  	"gopkg.in/fsnotify/fsnotify.v0"
    11  )
    12  
    13  var (
    14  	lock     sync.RWMutex
    15  	watchers []*fsnotify.Watcher
    16  )
    17  
    18  func watchFileWithFsNotify(pathname string, channel chan<- io.ReadCloser,
    19  	logger log.Logger) bool {
    20  	watcher, err := fsnotify.NewWatcher()
    21  	if err != nil {
    22  		logger.Println("Error creating watcher:", err)
    23  		return false
    24  	}
    25  	lock.Lock()
    26  	defer lock.Unlock()
    27  	watchers = append(watchers, watcher)
    28  	pathname = path.Clean(pathname)
    29  	dirname := path.Dir(pathname)
    30  	if err := watcher.WatchFlags(dirname, fsnotify.FSN_CREATE); err != nil {
    31  		logger.Println("Error adding watch:", err)
    32  		return false
    33  	}
    34  	go waitForNotifyEvents(watcher, pathname, channel, logger)
    35  	return true
    36  }
    37  
    38  func watchFileStopWithFsNotify() bool {
    39  	lock.Lock()
    40  	defer lock.Unlock()
    41  	// Send cleanup notification to watchers.
    42  	for _, watcher := range watchers {
    43  		watcher.Close()
    44  	}
    45  	// Wait for cleanup of each watcher.
    46  	for _, watcher := range watchers {
    47  		for {
    48  			if _, ok := <-watcher.Event; !ok {
    49  				break
    50  			}
    51  		}
    52  	}
    53  	watchers = nil
    54  	return true
    55  }
    56  
    57  func waitForNotifyEvents(watcher *fsnotify.Watcher, pathname string,
    58  	channel chan<- io.ReadCloser, logger log.Logger) {
    59  	if file, err := os.Open(pathname); err == nil {
    60  		channel <- file
    61  	}
    62  	for {
    63  		select {
    64  		case event, ok := <-watcher.Event:
    65  			if !ok {
    66  				return
    67  			}
    68  			if path.Clean(event.Name) != pathname {
    69  				continue
    70  			}
    71  			if file, err := os.Open(pathname); err != nil {
    72  				if os.IsNotExist(err) {
    73  					continue
    74  				}
    75  				if logger != nil {
    76  					logger.Printf("Error opening file: %s: %s\n", pathname, err)
    77  				}
    78  			} else {
    79  				channel <- file
    80  			}
    81  		case err, ok := <-watcher.Error:
    82  			if !ok {
    83  				return
    84  			}
    85  			logger.Println("Error with watcher:", err)
    86  		}
    87  	}
    88  }