github.com/vlifesystems/rulehunter@v0.0.0-20180501090014-673078aa4a83/watcher/watcher.go (about) 1 // Copyright (C) 2016-2017 vLife Systems Ltd <http://vlifesystems.com> 2 // Licensed under an MIT licence. Please see LICENSE.md for details. 3 4 // Package watcher is used to find experiment files that need processing 5 package watcher 6 7 import ( 8 "github.com/vlifesystems/rulehunter/fileinfo" 9 "github.com/vlifesystems/rulehunter/logger" 10 "github.com/vlifesystems/rulehunter/quitter" 11 "io/ioutil" 12 "path/filepath" 13 "time" 14 ) 15 16 // DirError indicates that there was an error reading the directory 17 type DirError string 18 19 func (e DirError) Error() string { 20 return "can not watch directory: " + string(e) 21 } 22 23 // Watch sends experiment filenames that need processing 24 // to the filenames channel. It checks every period of time. 25 func Watch( 26 dir string, 27 period time.Duration, 28 l logger.Logger, 29 quit *quitter.Quitter, 30 files chan<- fileinfo.FileInfo, 31 ) { 32 var lastLogErr error 33 quit.Add() 34 defer quit.Done() 35 ticker := time.NewTicker(period).C 36 allFiles, err := getFilesToMap(dir) 37 if err != nil { 38 lastLogErr = l.Error(err) 39 } 40 41 for _, file := range allFiles { 42 files <- file 43 } 44 45 // Used to only send old files every other run 46 flipFlop := true 47 for { 48 select { 49 case <-quit.C: 50 close(files) 51 return 52 case <-ticker: 53 newFiles, err := getFilesToMap(dir) 54 if err != nil { 55 if lastLogErr == nil || lastLogErr.Error() != err.Error() { 56 lastLogErr = l.Error(err) 57 } 58 break 59 } 60 lastLogErr = nil 61 62 for filename, file := range newFiles { 63 if lastFile, ok := allFiles[filename]; ok { 64 isNew := !fileinfo.IsEqual(lastFile, file) 65 if isNew { 66 files <- file 67 } else if flipFlop { 68 files <- file 69 } 70 } else { 71 files <- file 72 } 73 allFiles[filename] = file 74 } 75 allFiles = newFiles 76 flipFlop = !flipFlop 77 } 78 } 79 } 80 81 func GetExperimentFiles(dir string) ([]fileinfo.FileInfo, error) { 82 experimentFiles := make([]fileinfo.FileInfo, 0) 83 files, err := ioutil.ReadDir(dir) 84 if err != nil { 85 return experimentFiles, DirError(dir) 86 } 87 88 for _, file := range files { 89 ext := filepath.Ext(file.Name()) 90 if !file.IsDir() && (ext == ".json" || ext == ".yaml") { 91 experimentFiles = append(experimentFiles, file) 92 } 93 } 94 return experimentFiles, nil 95 } 96 97 func getFilesToMap(dir string) (map[string]fileinfo.FileInfo, error) { 98 filesMap := make(map[string]fileinfo.FileInfo) 99 files, err := GetExperimentFiles(dir) 100 if err != nil { 101 return filesMap, err 102 } 103 for _, file := range files { 104 filesMap[file.Name()] = file 105 } 106 return filesMap, nil 107 }