github.com/sijibomii/docker@v0.0.0-20231230191044-5cf6ca554647/pkg/discovery/file/file.go (about)

     1  package file
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/docker/docker/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  		for _, ip := range discovery.Generate(line) {
    49  			result = append(result, ip)
    50  		}
    51  	}
    52  	return result
    53  }
    54  
    55  func (s *Discovery) fetch() (discovery.Entries, error) {
    56  	fileContent, err := ioutil.ReadFile(s.path)
    57  	if err != nil {
    58  		return nil, fmt.Errorf("failed to read '%s': %v", s.path, err)
    59  	}
    60  	return discovery.CreateEntries(parseFileContent(fileContent))
    61  }
    62  
    63  // Watch is exported
    64  func (s *Discovery) Watch(stopCh <-chan struct{}) (<-chan discovery.Entries, <-chan error) {
    65  	ch := make(chan discovery.Entries)
    66  	errCh := make(chan error)
    67  	ticker := time.NewTicker(s.heartbeat)
    68  
    69  	go func() {
    70  		defer close(errCh)
    71  		defer close(ch)
    72  
    73  		// Send the initial entries if available.
    74  		currentEntries, err := s.fetch()
    75  		if err != nil {
    76  			errCh <- err
    77  		} else {
    78  			ch <- currentEntries
    79  		}
    80  
    81  		// Periodically send updates.
    82  		for {
    83  			select {
    84  			case <-ticker.C:
    85  				newEntries, err := s.fetch()
    86  				if err != nil {
    87  					errCh <- err
    88  					continue
    89  				}
    90  
    91  				// Check if the file has really changed.
    92  				if !newEntries.Equals(currentEntries) {
    93  					ch <- newEntries
    94  				}
    95  				currentEntries = newEntries
    96  			case <-stopCh:
    97  				ticker.Stop()
    98  				return
    99  			}
   100  		}
   101  	}()
   102  
   103  	return ch, errCh
   104  }
   105  
   106  // Register is exported
   107  func (s *Discovery) Register(addr string) error {
   108  	return discovery.ErrNotImplemented
   109  }