|
@@ -0,0 +1,155 @@
|
|
|
+package health
|
|
|
+
|
|
|
+import (
|
|
|
+ "encoding/json"
|
|
|
+ "fmt"
|
|
|
+ "io/ioutil"
|
|
|
+ "log"
|
|
|
+ "path"
|
|
|
+ "strings"
|
|
|
+ "sync"
|
|
|
+ "time"
|
|
|
+
|
|
|
+ "github.com/kr/pretty"
|
|
|
+)
|
|
|
+
|
|
|
+type StatusFile struct {
|
|
|
+ filename string
|
|
|
+ mu sync.RWMutex
|
|
|
+ m StatusFileData
|
|
|
+}
|
|
|
+
|
|
|
+type StatusFileData map[string]*Service
|
|
|
+
|
|
|
+func NewStatusFile(filename string) *StatusFile {
|
|
|
+ return &StatusFile{
|
|
|
+ m: make(StatusFileData),
|
|
|
+ filename: filename,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func DirectoryReader(dir string) {
|
|
|
+ for {
|
|
|
+ err := reloadDirectory(dir)
|
|
|
+ if err != nil {
|
|
|
+ log.Printf("loading health data: %s", err)
|
|
|
+ }
|
|
|
+ time.Sleep(3 * time.Second)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func reloadDirectory(dir string) error {
|
|
|
+ dirlist, err := ioutil.ReadDir(dir)
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("could not read '%s': %s", dir, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ seen := map[string]bool{}
|
|
|
+
|
|
|
+ var parseErr error
|
|
|
+
|
|
|
+ for _, file := range dirlist {
|
|
|
+ fileName := file.Name()
|
|
|
+ if !strings.HasSuffix(strings.ToLower(fileName), ".json") ||
|
|
|
+ strings.HasPrefix(path.Base(fileName), ".") ||
|
|
|
+ file.IsDir() {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ statusName := fileName[0:strings.LastIndex(fileName, ".")]
|
|
|
+
|
|
|
+ registry.mu.Lock()
|
|
|
+ s, ok := registry.m[statusName]
|
|
|
+ registry.mu.Unlock()
|
|
|
+
|
|
|
+ seen[statusName] = true
|
|
|
+
|
|
|
+ if ok {
|
|
|
+ s.Reload()
|
|
|
+ } else {
|
|
|
+ s := NewStatusFile(path.Join(dir, fileName))
|
|
|
+ err := s.Reload()
|
|
|
+ if err != nil {
|
|
|
+ log.Printf("error loading '%s': %s", fileName, err)
|
|
|
+ parseErr = err
|
|
|
+ }
|
|
|
+ registry.Add(statusName, s)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ registry.mu.Lock()
|
|
|
+ for n, _ := range registry.m {
|
|
|
+ if !seen[n] {
|
|
|
+ registry.m[n].Close()
|
|
|
+ delete(registry.m, n)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ registry.mu.Unlock()
|
|
|
+
|
|
|
+ return parseErr
|
|
|
+}
|
|
|
+
|
|
|
+func (s *StatusFile) Reload() error {
|
|
|
+ if len(s.filename) > 0 {
|
|
|
+ return s.Load(s.filename)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// Load imports the data atomically into the status map. If there's
|
|
|
+// a JSON error the old data is preserved.
|
|
|
+func (s *StatusFile) Load(filename string) error {
|
|
|
+ n := StatusFileData{}
|
|
|
+ b, err := ioutil.ReadFile(filename)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ err = json.Unmarshal(b, &n)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ s.mu.Lock()
|
|
|
+ s.m = n
|
|
|
+ s.mu.Unlock()
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (s *StatusFile) Close() error {
|
|
|
+ s.mu.Lock()
|
|
|
+ s.m = nil
|
|
|
+ s.mu.Unlock()
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (s *StatusFile) GetStatus(check string) StatusType {
|
|
|
+ s.mu.RLock()
|
|
|
+ defer s.mu.RUnlock()
|
|
|
+
|
|
|
+ if s.m == nil {
|
|
|
+ return StatusUnknown
|
|
|
+ }
|
|
|
+
|
|
|
+ pretty.Println(s)
|
|
|
+
|
|
|
+ st, ok := s.m[check]
|
|
|
+ if !ok {
|
|
|
+ log.Printf("Not found '%s'", check)
|
|
|
+ return StatusUnknown
|
|
|
+ }
|
|
|
+ return st.Status
|
|
|
+}
|
|
|
+
|
|
|
+// UnmarshalJSON implements the json.Unmarshaler interface.
|
|
|
+func (srv *Service) UnmarshalJSON(b []byte) error {
|
|
|
+ var i int64
|
|
|
+ if err := json.Unmarshal(b, &i); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ *srv = Service{Status: StatusType(i)}
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// UnmarshalJSON implements the json.Marshaler interface.
|
|
|
+// func (srv *Service) MarshalJSON() ([]byte, error) {
|
|
|
+// return
|
|
|
+// }
|