blob: b6a7aeb992f37af3385c25673bb65d512123cfed [file] [log] [blame]
package util
import (
"encoding/json"
"net/http"
"strconv"
"sync"
"time"
"github.com/skia-dev/glog"
)
// PollingStatus is a convenience struct used for periodically querying
// some resource.
type PollingStatus struct {
lock sync.RWMutex
value interface{}
pollFn func(interface{}) error
stop chan bool
}
func NewPollingStatus(value interface{}, poll func(interface{}) error, frequency time.Duration) (*PollingStatus, error) {
s := PollingStatus{
sync.RWMutex{},
value,
poll,
make(chan bool),
}
if err := s.poll(); err != nil {
return nil, err
}
go func(s *PollingStatus) {
ticker := time.Tick(frequency)
for {
select {
case <-s.stop:
return
case <-ticker:
if err := s.poll(); err != nil {
glog.Error(err)
}
}
}
}(&s)
return &s, nil
}
func (s *PollingStatus) poll() error {
s.lock.Lock()
defer s.lock.Unlock()
if err := s.pollFn(s.value); err != nil {
return err
}
return nil
}
func (s *PollingStatus) MarshalJSON() ([]byte, error) {
s.lock.RLock()
defer s.lock.RUnlock()
return json.Marshal(s.value)
}
func (s *PollingStatus) Stop() {
s.stop <- true
}
// IntPollingStatus is a wrapper around PollingStatus which expects an
// integer value.
type IntPollingStatus struct {
*PollingStatus
}
type intValue struct {
Value int `json:"value" influxdb:"value"`
}
func NewIntPollingStatus(poll func(interface{}) error, frequency time.Duration) (*IntPollingStatus, error) {
var val intValue
s, err := NewPollingStatus(&val, poll, frequency)
if err != nil {
return nil, err
}
return &IntPollingStatus{s}, nil
}
func (s *IntPollingStatus) MarshalJSON() ([]byte, error) {
s.lock.RLock()
defer s.lock.RUnlock()
return []byte(strconv.FormatInt(int64(s.value.(*intValue).Value), 10)), nil
}
// JSONPollingStatus is a wrapper around PollingStatus which makes HTTP
// requests and expects responses which contain valid JSON. If client is nil,
// uses a default http.Client.
func NewJSONPollingStatus(value interface{}, url string, frequency time.Duration, client *http.Client) (*PollingStatus, error) {
if client == nil {
client = NewTimeoutClient()
}
return NewPollingStatus(value, func(interface{}) error {
resp, err := client.Get(url)
if err != nil {
return err
}
defer Close(resp.Body)
if err := json.NewDecoder(resp.Body).Decode(value); err != nil {
return err
}
return nil
}, frequency)
}