github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/pkg/discovery/file/file.go (about) 1 package file // import "github.com/demonoid81/moby/pkg/discovery/file" 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "strings" 7 "time" 8 9 "github.com/demonoid81/moby/pkg/discovery" 10 ) 11 12 // Discovery is exported 13 type Discovery struct { 14 heartbeat time.Duration 15 path string 16 } 17 18 func init() { 19 Init() 20 } 21 22 // Init is exported 23 func Init() { 24 discovery.Register("file", &Discovery{}) 25 } 26 27 // Initialize is exported 28 func (s *Discovery) Initialize(path string, heartbeat time.Duration, ttl time.Duration, _ map[string]string) error { 29 s.path = path 30 s.heartbeat = heartbeat 31 return nil 32 } 33 34 func parseFileContent(content []byte) []string { 35 var result []string 36 for _, line := range strings.Split(strings.TrimSpace(string(content)), "\n") { 37 line = strings.TrimSpace(line) 38 // Ignoring line starts with # 39 if strings.HasPrefix(line, "#") { 40 continue 41 } 42 // Inlined # comment also ignored. 43 if strings.Contains(line, "#") { 44 line = line[0:strings.Index(line, "#")] 45 // Trim additional spaces caused by above stripping. 46 line = strings.TrimSpace(line) 47 } 48 result = append(result, discovery.Generate(line)...) 49 } 50 return result 51 } 52 53 func (s *Discovery) fetch() (discovery.Entries, error) { 54 fileContent, err := ioutil.ReadFile(s.path) 55 if err != nil { 56 return nil, fmt.Errorf("failed to read '%s': %v", s.path, err) 57 } 58 return discovery.CreateEntries(parseFileContent(fileContent)) 59 } 60 61 // Watch is exported 62 func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) { 63 ch := make(chan discovery.Entries) 64 errCh := make(chan error) 65 ticker := time.NewTicker(s.heartbeat) 66 67 go func() { 68 defer close(errCh) 69 defer close(ch) 70 71 // Send the initial entries if available. 72 currentEntries, err := s.fetch() 73 if err != nil { 74 errCh <- err 75 } else { 76 ch <- currentEntries 77 } 78 79 // Periodically send updates. 80 for { 81 select { 82 case <-ticker.C: 83 newEntries, err := s.fetch() 84 if err != nil { 85 errCh <- err 86 continue 87 } 88 89 // Check if the file has really changed. 90 if !newEntries.Equals(currentEntries) { 91 ch <- newEntries 92 } 93 currentEntries = newEntries 94 case <-stopCh: 95 ticker.Stop() 96 return 97 } 98 } 99 }() 100 101 return ch, errCh 102 } 103 104 // Register is exported 105 func (s *Discovery) Register(addr string) error { 106 return discovery.ErrNotImplemented 107 }