diff --git a/cmd/gost/peer.go b/cmd/gost/peer.go index 9e1d00f..0647dc7 100644 --- a/cmd/gost/peer.go +++ b/cmd/gost/peer.go @@ -14,14 +14,14 @@ import ( ) type peerConfig struct { - Strategy string `json:"strategy"` - MaxFails int `json:"max_fails"` - FailTimeout time.Duration - period time.Duration // the period for live reloading - Nodes []string `json:"nodes"` - group *gost.NodeGroup - baseNodes []gost.Node - stopped chan struct{} + Strategy string `json:"strategy"` + MaxFails int `json:"max_fails"` + FailTimeout time.Duration `json:"fail_timeout"` + ReloadPeriod time.Duration `json:"reload"` + Nodes []string `json:"nodes"` + group *gost.NodeGroup + baseNodes []gost.Node + stopped chan struct{} } func newPeerConfig() *peerConfig { @@ -129,7 +129,7 @@ func (cfg *peerConfig) parse(r io.Reader) error { case "fail_timeout": cfg.FailTimeout, _ = time.ParseDuration(ss[1]) case "reload": - cfg.period, _ = time.ParseDuration(ss[1]) + cfg.ReloadPeriod, _ = time.ParseDuration(ss[1]) case "peer": cfg.Nodes = append(cfg.Nodes, ss[1]) } @@ -142,7 +142,7 @@ func (cfg *peerConfig) Period() time.Duration { if cfg.Stopped() { return -1 } - return cfg.period + return cfg.ReloadPeriod } // Stop stops reloading. diff --git a/cmd/gost/route.go b/cmd/gost/route.go index 0db5b2e..b87b42e 100644 --- a/cmd/gost/route.go +++ b/cmd/gost/route.go @@ -7,6 +7,7 @@ import ( "encoding/base64" "fmt" "net" + "net/http" "net/url" "os" "strings" @@ -67,18 +68,31 @@ func (r *route) parseChain() (*gost.Chain, error) { ) if cfg := nodes[0].Get("peer"); cfg != "" { - f, err := os.Open(cfg) - if err != nil { - return nil, err - } - peerCfg := newPeerConfig() peerCfg.group = ngroup peerCfg.baseNodes = nodes - peerCfg.Reload(f) - f.Close() - go gost.PeriodReload(peerCfg, cfg) + if strings.HasPrefix(cfg, "http") { + client := http.Client{} + resp, err := client.Get(cfg) + if err != nil { + return nil, err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return nil, fmt.Errorf("fetch remote resource error, reply status code is not equals to 200") + } + peerCfg.Reload(resp.Body) + go gost.PeriodReloadRemote(peerCfg, cfg) + } else { + f, err := os.Open(cfg) + defer f.Close() + if err != nil { + return nil, err + } + peerCfg.Reload(f) + go gost.PeriodReload(peerCfg, cfg) + } } chain.AddNodeGroup(ngroup) diff --git a/reload.go b/reload.go index 08d708a..c06c5cd 100644 --- a/reload.go +++ b/reload.go @@ -1,7 +1,9 @@ package gost import ( + "fmt" "io" + "net/http" "os" "time" @@ -63,3 +65,39 @@ func PeriodReload(r Reloader, configFile string) error { <-time.After(period) } } + +// PeriodReloadRemote reloads the remote configFile periodically according to the period of the Reloader r. +func PeriodReloadRemote(r Reloader, cfg string) error { + if r == nil || cfg == "" { + return nil + } + + client := http.Client{} + for { + if r.Period() < 0 { + log.Log("[reload] stopped:", cfg) + return nil + } + resp, err := client.Get(cfg) + if err != nil { + return err + } + defer resp.Body.Close() + if resp.StatusCode != 200 { + return fmt.Errorf("fetch remote resource error, reply status code is not equals to 200") + } + if err := r.Reload(resp.Body); err != nil { + log.Logf("[reload] %s: %s", cfg, err) + } + + period := r.Period() + if period == 0 { + log.Log("[reload] disabled:", cfg) + return nil + } + if period < time.Second { + period = time.Second + } + <-time.After(period) + } +}