fix incorrect reload behaviors, further organize code

This commit is contained in:
yusing
2025-01-09 04:26:00 +08:00
parent 8bbb5d2e09
commit b3c47e759f
26 changed files with 418 additions and 336 deletions

View File

@@ -7,12 +7,15 @@ import (
"sync"
"time"
"github.com/yusing/go-proxy/internal/api"
"github.com/yusing/go-proxy/internal/autocert"
"github.com/yusing/go-proxy/internal/common"
"github.com/yusing/go-proxy/internal/config/types"
"github.com/yusing/go-proxy/internal/entrypoint"
E "github.com/yusing/go-proxy/internal/error"
"github.com/yusing/go-proxy/internal/logging"
"github.com/yusing/go-proxy/internal/metrics"
"github.com/yusing/go-proxy/internal/net/http/server"
"github.com/yusing/go-proxy/internal/notif"
proxy "github.com/yusing/go-proxy/internal/route/provider"
"github.com/yusing/go-proxy/internal/task"
@@ -26,7 +29,9 @@ type Config struct {
value *types.Config
providers F.Map[string, *proxy.Provider]
autocertProvider *autocert.Provider
task *task.Task
entrypoint *entrypoint.Entrypoint
task *task.Task
}
var (
@@ -45,15 +50,18 @@ Make sure you rename it back before next time you start.`
You may run "ls-config" to show or dump the current config.`
)
var Validate = types.Validate
func GetInstance() *Config {
return instance
}
func newConfig() *Config {
return &Config{
value: types.DefaultConfig(),
providers: F.NewMapOf[string, *proxy.Provider](),
task: task.RootTask("config", false),
value: types.DefaultConfig(),
providers: F.NewMapOf[string, *proxy.Provider](),
entrypoint: entrypoint.NewEntrypoint(),
task: task.RootTask("config", false),
}
}
@@ -66,11 +74,6 @@ func Load() (*Config, E.Error) {
return instance, instance.load()
}
func Validate(data []byte) E.Error {
var model types.Config
return utils.DeserializeYAML(data, &model)
}
func MatchDomains() []string {
return instance.value.MatchDomains
}
@@ -101,6 +104,7 @@ func OnConfigChange(ev []events.Event) {
}
if err := Reload(); err != nil {
logger.Warn().Msg("using last config")
// recovered in event queue
panic(err)
}
@@ -122,15 +126,19 @@ func Reload() E.Error {
// -> replace config -> start new subtasks
instance.task.Finish("config changed")
instance = newCfg
instance.StartProxyProviders()
instance.Start()
return nil
}
func Value() types.Config {
return *instance.value
func (cfg *Config) Value() *types.Config {
return instance.value
}
func GetAutoCertProvider() *autocert.Provider {
func (cfg *Config) Reload() E.Error {
return Reload()
}
func (cfg *Config) AutoCertProvider() *autocert.Provider {
return instance.autocertProvider
}
@@ -138,6 +146,26 @@ func (cfg *Config) Task() *task.Task {
return cfg.task
}
func (cfg *Config) Start() {
cfg.StartAutoCert()
cfg.StartProxyProviders()
cfg.StartServers()
}
func (cfg *Config) StartAutoCert() {
autocert := cfg.autocertProvider
if autocert == nil {
logging.Info().Msg("autocert not configured")
return
}
if err := autocert.Setup(); err != nil {
E.LogFatal("autocert setup error", err)
} else {
autocert.ScheduleRenewal(cfg.task)
}
}
func (cfg *Config) StartProxyProviders() {
errs := cfg.providers.CollectErrorsParallel(
func(_ string, p *proxy.Provider) error {
@@ -149,6 +177,30 @@ func (cfg *Config) StartProxyProviders() {
}
}
func (cfg *Config) StartServers() {
server.StartServer(cfg.task, server.Options{
Name: "proxy",
CertProvider: cfg.AutoCertProvider(),
HTTPAddr: common.ProxyHTTPAddr,
HTTPSAddr: common.ProxyHTTPSAddr,
Handler: cfg.entrypoint,
})
server.StartServer(cfg.task, server.Options{
Name: "api",
CertProvider: cfg.AutoCertProvider(),
HTTPAddr: common.APIHTTPAddr,
Handler: api.NewHandler(cfg),
})
if common.PrometheusEnabled {
server.StartServer(cfg.task, server.Options{
Name: "metrics",
CertProvider: cfg.AutoCertProvider(),
HTTPAddr: common.MetricsHTTPAddr,
Handler: metrics.NewHandler(),
})
}
}
func (cfg *Config) load() E.Error {
const errMsg = "config load error"
@@ -164,8 +216,8 @@ func (cfg *Config) load() E.Error {
// errors are non fatal below
errs := E.NewBuilder(errMsg)
errs.Add(entrypoint.SetMiddlewares(model.Entrypoint.Middlewares))
errs.Add(entrypoint.SetAccessLogger(cfg.task, model.Entrypoint.AccessLog))
errs.Add(cfg.entrypoint.SetMiddlewares(model.Entrypoint.Middlewares))
errs.Add(cfg.entrypoint.SetAccessLogger(cfg.task, model.Entrypoint.AccessLog))
errs.Add(cfg.initNotification(model.Providers.Notification))
errs.Add(cfg.initAutoCert(model.AutoCert))
errs.Add(cfg.loadRouteProviders(&model.Providers))
@@ -176,7 +228,8 @@ func (cfg *Config) load() E.Error {
model.MatchDomains[i] = "." + domain
}
}
entrypoint.SetFindRouteDomains(model.MatchDomains)
cfg.entrypoint.SetFindRouteDomains(model.MatchDomains)
return errs.Error()
}

View File

@@ -1,20 +1,14 @@
package config
import (
"strings"
"github.com/yusing/go-proxy/internal/homepage"
route "github.com/yusing/go-proxy/internal/route"
"github.com/yusing/go-proxy/internal/route/entry"
proxy "github.com/yusing/go-proxy/internal/route/provider"
"github.com/yusing/go-proxy/internal/route/routes"
"github.com/yusing/go-proxy/internal/route/provider"
"github.com/yusing/go-proxy/internal/route/types"
"github.com/yusing/go-proxy/internal/utils/strutils"
)
func DumpEntries() map[string]*types.RawEntry {
func (cfg *Config) DumpEntries() map[string]*types.RawEntry {
entries := make(map[string]*types.RawEntry)
instance.providers.RangeAll(func(_ string, p *proxy.Provider) {
cfg.providers.RangeAll(func(_ string, p *provider.Provider) {
p.RangeRoutes(func(alias string, r *route.Route) {
entries[alias] = r.Entry
})
@@ -22,107 +16,20 @@ func DumpEntries() map[string]*types.RawEntry {
return entries
}
func DumpProviders() map[string]*proxy.Provider {
entries := make(map[string]*proxy.Provider)
instance.providers.RangeAll(func(name string, p *proxy.Provider) {
func (cfg *Config) DumpProviders() map[string]*provider.Provider {
entries := make(map[string]*provider.Provider)
cfg.providers.RangeAll(func(name string, p *provider.Provider) {
entries[name] = p
})
return entries
}
func HomepageConfig() homepage.Config {
hpCfg := homepage.NewHomePageConfig()
routes.GetHTTPRoutes().RangeAll(func(alias string, r types.HTTPRoute) {
en := r.RawEntry()
item := en.Homepage
if item == nil {
item = new(homepage.Item)
item.Show = true
}
if !item.IsEmpty() {
item.Show = true
}
if !item.Show {
return
}
item.Alias = alias
if item.Name == "" {
item.Name = strutils.Title(
strings.ReplaceAll(
strings.ReplaceAll(alias, "-", " "),
"_", " ",
),
)
}
if instance.value.Homepage.UseDefaultCategories {
if en.Container != nil && item.Category == "" {
if category, ok := homepage.PredefinedCategories[en.Container.ImageName]; ok {
item.Category = category
}
}
if item.Category == "" {
if category, ok := homepage.PredefinedCategories[strings.ToLower(alias)]; ok {
item.Category = category
}
}
}
switch {
case entry.IsDocker(r):
if item.Category == "" {
item.Category = "Docker"
}
item.SourceType = string(proxy.ProviderTypeDocker)
case entry.UseLoadBalance(r):
if item.Category == "" {
item.Category = "Load-balanced"
}
item.SourceType = "loadbalancer"
default:
if item.Category == "" {
item.Category = "Others"
}
item.SourceType = string(proxy.ProviderTypeFile)
}
item.AltURL = r.TargetURL().String()
hpCfg.Add(item)
})
return hpCfg
}
func RoutesByAlias(typeFilter ...route.RouteType) map[string]any {
rts := make(map[string]any)
if len(typeFilter) == 0 || typeFilter[0] == "" {
typeFilter = []route.RouteType{route.RouteTypeReverseProxy, route.RouteTypeStream}
}
for _, t := range typeFilter {
switch t {
case route.RouteTypeReverseProxy:
routes.GetHTTPRoutes().RangeAll(func(alias string, r types.HTTPRoute) {
rts[alias] = r
})
case route.RouteTypeStream:
routes.GetStreamRoutes().RangeAll(func(alias string, r types.StreamRoute) {
rts[alias] = r
})
}
}
return rts
}
func Statistics() map[string]any {
func (cfg *Config) Statistics() map[string]any {
nTotalStreams := 0
nTotalRPs := 0
providerStats := make(map[string]proxy.ProviderStats)
providerStats := make(map[string]provider.ProviderStats)
instance.providers.RangeAll(func(name string, p *proxy.Provider) {
cfg.providers.RangeAll(func(name string, p *provider.Provider) {
stats := p.Statistics()
providerStats[name] = stats

View File

@@ -3,6 +3,8 @@ package types
import (
"github.com/yusing/go-proxy/internal/net/http/accesslog"
"github.com/yusing/go-proxy/internal/utils"
E "github.com/yusing/go-proxy/internal/error"
)
type (
@@ -24,6 +26,12 @@ type (
AccessLog *accesslog.Config `json:"access_log" validate:"omitempty"`
}
NotificationConfig map[string]any
ConfigInstance interface {
Value() *Config
Reload() E.Error
Statistics() map[string]any
}
)
func DefaultConfig() *Config {
@@ -35,6 +43,11 @@ func DefaultConfig() *Config {
}
}
func Validate(data []byte) E.Error {
var model Config
return utils.DeserializeYAML(data, &model)
}
func init() {
utils.RegisterDefaultValueFactory(DefaultConfig)
}