feat: ent ORM, admin UI, client auth, Fyne GUI, Windows/MSI packaging
This commit is contained in:
@@ -18,6 +18,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
@@ -146,6 +147,9 @@ type Service struct {
|
||||
// string if no configuration file was used.
|
||||
configFilePath string
|
||||
|
||||
// configURL is the URL to fetch configuration from on startup and periodically.
|
||||
configURL string
|
||||
|
||||
// service context
|
||||
ctx context.Context
|
||||
// call cancel to stop service
|
||||
@@ -199,6 +203,7 @@ func NewService(options ServiceOptions) (*Service, error) {
|
||||
common: options.Common,
|
||||
reloadCommon: options.Common,
|
||||
configFilePath: options.ConfigFilePath,
|
||||
configURL: options.Common.ConfigURL,
|
||||
unsafeFeatures: options.UnsafeFeatures,
|
||||
proxyCfgs: proxyCfgs,
|
||||
visitorCfgs: visitorCfgs,
|
||||
@@ -265,6 +270,10 @@ func (svr *Service) Run(ctx context.Context) error {
|
||||
|
||||
go svr.keepControllerWorking()
|
||||
|
||||
if svr.configURL != "" {
|
||||
go svr.pollConfigURL()
|
||||
}
|
||||
|
||||
<-svr.ctx.Done()
|
||||
svr.stop()
|
||||
return nil
|
||||
@@ -513,3 +522,74 @@ func (svr *Service) reloadConfigFromSourcesLocked() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (svr *Service) pollConfigURL() {
|
||||
url := svr.configURL
|
||||
if url == "" {
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("starting config URL poller: %s", url)
|
||||
lastBody := ""
|
||||
|
||||
ticker := time.NewTicker(30 * time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-svr.ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
}
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
log.Warnf("failed to fetch config from %s: %v", url, err)
|
||||
continue
|
||||
}
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
resp.Body.Close()
|
||||
if err != nil {
|
||||
log.Warnf("failed to read config from %s: %v", url, err)
|
||||
continue
|
||||
}
|
||||
|
||||
bodyStr := string(body)
|
||||
if bodyStr == lastBody {
|
||||
continue
|
||||
}
|
||||
|
||||
log.Infof("config changed, reloading from %s", url)
|
||||
|
||||
allCfg := v1.ClientConfig{}
|
||||
if err := config.LoadConfigure(body, &allCfg, false, "toml"); err != nil {
|
||||
log.Warnf("failed to parse config from %s: %v", url, err)
|
||||
continue
|
||||
}
|
||||
|
||||
proxyCfgs := make([]v1.ProxyConfigurer, 0)
|
||||
for _, c := range allCfg.Proxies {
|
||||
proxyCfgs = append(proxyCfgs, c.ProxyConfigurer)
|
||||
}
|
||||
visitorCfgs := make([]v1.VisitorConfigurer, 0)
|
||||
for _, c := range allCfg.Visitors {
|
||||
visitorCfgs = append(visitorCfgs, c.VisitorConfigurer)
|
||||
}
|
||||
|
||||
// Update common config for new proxies
|
||||
if allCfg.ClientCommonConfig.Log.To != "" {
|
||||
svr.cfgMu.Lock()
|
||||
svr.reloadCommon = &allCfg.ClientCommonConfig
|
||||
svr.cfgMu.Unlock()
|
||||
}
|
||||
|
||||
if err := svr.UpdateConfigSource(&allCfg.ClientCommonConfig, proxyCfgs, visitorCfgs); err != nil {
|
||||
log.Warnf("failed to apply config from %s: %v", url, err)
|
||||
continue
|
||||
}
|
||||
|
||||
lastBody = bodyStr
|
||||
log.Infof("config reloaded successfully from %s", url)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user