瀏覽代碼

更新配置文件监听和默认值设置

移除了全局配置参数依赖,更新了配置文件监听功能,并对多个配置结构体的字段名称进行了统一调整。
SongZihuan 3 月之前
父節點
當前提交
9391aa53c5

+ 2 - 1
go.mod

@@ -5,12 +5,13 @@ go 1.21.0
 toolchain go1.23.2
 
 require (
+	github.com/fsnotify/fsnotify v1.8.0
 	github.com/gabriel-vasile/mimetype v1.4.7
+	github.com/mattn/go-isatty v0.0.20
 	gopkg.in/yaml.v3 v3.0.1
 )
 
 require (
-	github.com/mattn/go-isatty v0.0.20 // indirect
 	golang.org/x/net v0.33.0 // indirect
 	golang.org/x/sys v0.28.0 // indirect
 )

+ 3 - 0
go.sum

@@ -1,3 +1,5 @@
+github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
+github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
 github.com/gabriel-vasile/mimetype v1.4.7 h1:SKFKl7kD0RiPdbht0s7hFtjl489WcQ1VyPW8ZzUMYCA=
 github.com/gabriel-vasile/mimetype v1.4.7/go.mod h1:GDlAgAyIRT27BhFl53XNAFtfjzOkLaF35JdEG0P7LtU=
 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -7,6 +9,7 @@ golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
 golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 122 - 45
src/config/config.go

@@ -3,58 +3,38 @@ package config
 import (
 	"github.com/SongZihuan/huan-proxy/src/config/configerr"
 	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
+	"github.com/fsnotify/fsnotify"
 	"os"
+	"sync"
 )
 
 type ConfigStruct struct {
+	ConfigLock sync.Mutex
+
 	configReady   bool
 	yamlHasParser bool
-	sigChan       chan os.Signal
+	sigchan       chan os.Signal
 	configPath    string
+	watcher       *fsnotify.Watcher
 
-	Yaml  YamlConfig
+	Yaml  *YamlConfig
 	Rules *rulescompile.RuleListCompileConfig
 }
 
-func (c *ConfigStruct) Parser(filepath string) configerr.ParserError {
-	err := c.Yaml.Parser(filepath)
-	if err != nil {
-		return err
+func newConfig(configPath string) ConfigStruct {
+	return ConfigStruct{
+		// Lock不用初始化
+		configReady:   false,
+		yamlHasParser: false,
+		sigchan:       make(chan os.Signal),
+		configPath:    configPath,
+		Yaml:          nil,
+		Rules:         nil,
 	}
-
-	c.yamlHasParser = true
-	return nil
-}
-
-func (c *ConfigStruct) SetDefault() {
-	if !c.yamlHasParser {
-		panic("yaml must parser first")
-	}
-
-	c.Yaml.SetDefault()
-}
-
-func (c *ConfigStruct) Check() (err configerr.ConfigError) {
-	err = c.Yaml.Check()
-	if err != nil && err.IsError() {
-		return err
-	}
-
-	return nil
-}
-
-func (c *ConfigStruct) CompileRule() configerr.ConfigError {
-	res, err := rulescompile.NewRuleListConfig(&c.Yaml.RuleListConfig)
-	if err != nil {
-		return configerr.NewConfigError("compile rule error: " + err.Error())
-	}
-
-	c.Rules = res
-	return nil
 }
 
 func (c *ConfigStruct) Init() (err configerr.ConfigError) {
-	if c.configReady {
+	if c.IsReady() { // 使用IsReady而不是isReady,确保上锁
 		return c.Reload()
 	}
 
@@ -87,18 +67,39 @@ func (c *ConfigStruct) Init() (err configerr.ConfigError) {
 }
 
 func (c *ConfigStruct) Reload() (err configerr.ConfigError) {
-	if !c.configReady {
+	if !c.IsReady() { // 使用IsReady而不是isReady,确保上锁
 		return c.Init()
 	}
 
-	bak := *c
+	bak := ConfigStruct{
+		configReady:   c.configReady,
+		yamlHasParser: c.yamlHasParser,
+		sigchan:       c.sigchan,
+		configPath:    c.configPath,
+		watcher:       c.watcher,
+		Yaml:          c.Yaml,
+		Rules:         c.Rules,
+		// 新建类型
+	}
 
 	defer func() {
 		if err != nil {
-			*c = bak
+			*c = ConfigStruct{
+				configReady:   bak.configReady,
+				yamlHasParser: bak.yamlHasParser,
+				sigchan:       bak.sigchan,
+				configPath:    bak.configPath,
+				watcher:       c.watcher,
+				Yaml:          bak.Yaml,
+				Rules:         bak.Rules,
+				// 新建类型 Lock不需要复制
+			}
 		}
 	}()
 
+	c.ConfigLock.Lock()
+	defer c.ConfigLock.Unlock()
+
 	reloadErr := c.reload()
 	if reloadErr != nil {
 		return configerr.NewConfigError("reload error: " + reloadErr.Error())
@@ -130,21 +131,63 @@ func (c *ConfigStruct) Reload() (err configerr.ConfigError) {
 func (c *ConfigStruct) clear() error {
 	c.configReady = false
 	c.yamlHasParser = false
-	// sigChan 不变
-	c.Yaml = YamlConfig{}
+	// sigchan和watcher 不变
+	c.Yaml = nil
+	c.Rules = nil
+	return nil
+}
+
+func (c *ConfigStruct) Parser(filepath string) configerr.ParserError {
+	err := c.Yaml.Parser(filepath)
+	if err != nil {
+		return err
+	}
+
+	c.yamlHasParser = true
 	return nil
 }
 
+func (c *ConfigStruct) SetDefault() {
+	if !c.yamlHasParser {
+		panic("yaml must parser first")
+	}
+
+	c.Yaml.SetDefault()
+}
+
+func (c *ConfigStruct) Check() (err configerr.ConfigError) {
+	err = c.Yaml.Check()
+	if err != nil && err.IsError() {
+		return err
+	}
+
+	return nil
+}
+
+func (c *ConfigStruct) CompileRule() configerr.ConfigError {
+	res, err := rulescompile.NewRuleListConfig(&c.Yaml.RuleListConfig)
+	if err != nil {
+		return configerr.NewConfigError("compile rule error: " + err.Error())
+	}
+
+	c.Rules = res
+	return nil
+}
+
+func (c *ConfigStruct) isReady() bool {
+	return c.yamlHasParser && c.configReady
+}
+
 func (c *ConfigStruct) init() error {
 	c.configReady = false
 	c.yamlHasParser = false
 
-	c.sigChan = make(chan os.Signal)
-	err := initSignal(c.sigChan)
+	err := initSignal(c.sigchan)
 	if err != nil {
 		return err
 	}
 
+	c.Yaml = new(YamlConfig)
 	err = c.Yaml.Init()
 	if err != nil {
 		return err
@@ -159,6 +202,7 @@ func (c *ConfigStruct) reload() error {
 		return err
 	}
 
+	c.Yaml = new(YamlConfig)
 	err = c.Yaml.Init()
 	if err != nil {
 		return err
@@ -167,6 +211,39 @@ func (c *ConfigStruct) reload() error {
 	return nil
 }
 
+// export func
+
+func (c *ConfigStruct) IsReady() bool {
+	c.ConfigLock.Lock()
+	defer c.ConfigLock.Unlock()
+	return c.isReady()
+}
+
 func (c *ConfigStruct) GetSignalChan() chan os.Signal {
-	return c.sigChan
+	c.ConfigLock.Lock()
+	defer c.ConfigLock.Unlock()
+
+	return c.sigchan
+}
+
+func (c *ConfigStruct) GetConfig() *YamlConfig {
+	c.ConfigLock.Lock()
+	defer c.ConfigLock.Unlock()
+
+	if !c.isReady() {
+		panic("config is not ready")
+	}
+
+	return c.Yaml
+}
+
+func (c *ConfigStruct) GetRulesList() *rulescompile.RuleListCompileConfig {
+	c.ConfigLock.Lock()
+	defer c.ConfigLock.Unlock()
+
+	if !c.isReady() {
+		panic("config is not ready")
+	}
+
+	return c.Rules
 }

+ 20 - 15
src/config/ctrl.go → src/config/export.go

@@ -2,17 +2,11 @@ package config
 
 import (
 	"github.com/SongZihuan/huan-proxy/src/config/configerr"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
 	"github.com/SongZihuan/huan-proxy/src/flagparser"
+	"os"
 )
 
-func newConfig(configPath string) ConfigStruct {
-	return ConfigStruct{
-		configReady:   false,
-		yamlHasParser: false,
-		configPath:    configPath,
-	}
-}
-
 func InitConfig(configPath string) configerr.ConfigError {
 	if !flagparser.IsReady() {
 		return configerr.NewConfigError("flag not ready")
@@ -32,16 +26,27 @@ func InitConfig(configPath string) configerr.ConfigError {
 }
 
 func IsReady() bool {
-	return config.yamlHasParser && config.configReady
+	return config.IsReady()
 }
 
-func Config() *ConfigStruct {
-	if !IsReady() {
-		panic("config not ready")
-	}
+func GetConfig() *YamlConfig {
+	return config.GetConfig()
+}
+
+func GetRules() *rulescompile.RuleListCompileConfig {
+	return config.GetRulesList()
+}
+
+func GetSignalChan() chan os.Signal {
+	return config.GetSignalChan()
+}
+
+func NotifyConfigFile() error {
+	return config.NotifyConfigFile()
+}
 
-	tmp := config
-	return &tmp
+func CloseNotifyConfigFile() {
+	config.CloseNotifyConfigFile()
 }
 
 var config ConfigStruct

+ 1 - 1
src/config/httpconfig.go

@@ -11,7 +11,7 @@ type HttpConfig struct {
 	StopWaitSecond int    `yaml:"stopwaitsecond"`
 }
 
-func (h *HttpConfig) SetDefault(global *GlobalConfig) {
+func (h *HttpConfig) SetDefault() {
 	if h.Address == "" {
 		h.Address = "localhost:2689"
 	}

+ 64 - 0
src/config/notifyconfig.go

@@ -0,0 +1,64 @@
+package config
+
+import (
+	"fmt"
+	"github.com/fsnotify/fsnotify"
+)
+
+func (c *ConfigStruct) NotifyConfigFile() error {
+	if c.watcher != nil {
+		return nil
+	}
+
+	watcher, err := fsnotify.NewWatcher()
+	if err != nil {
+		return err
+	}
+
+	// Add a path.
+	err = watcher.Add(c.configPath)
+	if err != nil {
+		return err
+	}
+
+	var stop = make(chan error)
+
+	// Start listening for events.
+	go func() {
+		for {
+			select {
+			case event, ok := <-watcher.Events:
+				if !ok {
+					stop <- nil
+					return
+				}
+				if event.Has(fsnotify.Write) || event.Has(fsnotify.Create) {
+					err := c.Reload()
+					if err != nil {
+						fmt.Printf("Config file reload error: %s\n", err.Error())
+					} else {
+						fmt.Printf("Config file reload success\n")
+					}
+				} else if event.Has(fsnotify.Remove) || event.Has(fsnotify.Rename) {
+					fmt.Printf("Config file has been remove\n")
+				}
+			case err, ok := <-watcher.Errors:
+				if !ok {
+					stop <- nil
+					return
+				}
+				fmt.Printf("Config file notify error: %s\n", err.Error())
+			}
+		}
+	}()
+
+	return nil
+}
+
+func (c *ConfigStruct) CloseNotifyConfigFile() {
+	if c.watcher == nil {
+		return
+	}
+
+	_ = c.watcher.Close()
+}

+ 13 - 13
src/config/rules/action/api/api.go

@@ -10,22 +10,22 @@ import (
 )
 
 type RuleAPIConfig struct {
-	Address       string                `yaml:"address"`
-	AddPrefixPath string                `yaml:"addpath"`
-	SubPrefixPath string                `yaml:"subpath"`
-	Rewrite       rewrite.RewriteConfig `yaml:"rewrite"`
-	HeaderSet     []*HeaderConfig       `yaml:"headerset"`
-	HeaderAdd     []*HeaderConfig       `yaml:"headeradd"`
-	HeaderDel     []*HeaderDelConfig    `yaml:"headerdel"`
-	QuerySet      []*QueryConfig        `yaml:"queryset"`
-	QueryAdd      []*QueryConfig        `yaml:"queryadd"`
-	QueryDel      []*QueryDelConfig     `yaml:"querydel"`
-	Via           string                `yaml:"via"`
+	Address   string                `yaml:"address"`
+	AddPath   string                `yaml:"addpath"`
+	SubPath   string                `yaml:"subpath"`
+	Rewrite   rewrite.RewriteConfig `yaml:"rewrite"`
+	HeaderSet []*HeaderConfig       `yaml:"headerset"`
+	HeaderAdd []*HeaderConfig       `yaml:"headeradd"`
+	HeaderDel []*HeaderDelConfig    `yaml:"headerdel"`
+	QuerySet  []*QueryConfig        `yaml:"queryset"`
+	QueryAdd  []*QueryConfig        `yaml:"queryadd"`
+	QueryDel  []*QueryDelConfig     `yaml:"querydel"`
+	Via       string                `yaml:"via"`
 }
 
 func (r *RuleAPIConfig) SetDefault() {
-	r.AddPrefixPath = utils.ProcessURLPath(r.AddPrefixPath)
-	r.SubPrefixPath = utils.ProcessURLPath(r.SubPrefixPath)
+	r.AddPath = utils.ProcessURLPath(r.AddPath)
+	r.SubPath = utils.ProcessURLPath(r.SubPath)
 
 	r.Rewrite.SetDefault()
 

+ 7 - 7
src/config/rules/action/dir/dirconfig.go

@@ -7,13 +7,13 @@ import (
 )
 
 type RuleDirConfig struct {
-	BasePath      string                `yaml:"basepath"`
-	IndexFile     []*IndexFileConfig    `yaml:"indexfile"`
-	IgnoreFile    []*IgnoreFileConfig   `yaml:"ignorefile"`
-	AddPrefixPath string                `yaml:"addpath"`
-	SubPrefixPath string                `yaml:"subpath"`
-	Rewrite       rewrite.RewriteConfig `yaml:"rewrite"`
-	Cors          cors.CorsConfig       `yaml:"cors"`
+	BasePath   string                `yaml:"basepath"`
+	IndexFile  []*IndexFileConfig    `yaml:"indexfile"`
+	IgnoreFile []*IgnoreFileConfig   `yaml:"ignorefile"`
+	AddPath    string                `yaml:"addpath"`
+	SubPath    string                `yaml:"subpath"`
+	Rewrite    rewrite.RewriteConfig `yaml:"rewrite"`
+	Cors       cors.CorsConfig       `yaml:"cors"`
 }
 
 func (r *RuleDirConfig) SetDefault() {

+ 25 - 25
src/config/rulescompile/actioncompile/apicompile/api.go

@@ -11,19 +11,19 @@ const XHuanProxyHeaer = api.XHuanProxyHeaer
 const ViaHeader = api.ViaHeader
 
 type RuleAPICompileConfig struct {
-	Address       string
-	TargetURL     *url.URL
-	Server        *httputil.ReverseProxy
-	AddPrefixPath string
-	SubPrefixPath string
-	Rewrite       *rewritecompile.RewriteCompileConfig
-	HeaderSet     []*HeaderCompileConfig
-	HeaderAdd     []*HeaderCompileConfig
-	HeaderDel     []*HeaderDelCompileConfig
-	QuerySet      []*QueryCompileConfig
-	QueryAdd      []*QueryCompileConfig
-	QueryDel      []*QueryDelCompileConfig
-	Via           string
+	Address   string
+	TargetURL *url.URL
+	Server    *httputil.ReverseProxy
+	AddPath   string
+	SubPath   string
+	Rewrite   *rewritecompile.RewriteCompileConfig
+	HeaderSet []*HeaderCompileConfig
+	HeaderAdd []*HeaderCompileConfig
+	HeaderDel []*HeaderDelCompileConfig
+	QuerySet  []*QueryCompileConfig
+	QueryAdd  []*QueryCompileConfig
+	QueryDel  []*QueryDelCompileConfig
+	Via       string
 }
 
 func NewRuleAPICompileConfig(r *api.RuleAPIConfig) (*RuleAPICompileConfig, error) {
@@ -94,17 +94,17 @@ func NewRuleAPICompileConfig(r *api.RuleAPIConfig) (*RuleAPICompileConfig, error
 	}
 
 	return &RuleAPICompileConfig{
-		Address:       r.Address,
-		TargetURL:     targetURL,
-		Server:        server,
-		AddPrefixPath: r.AddPrefixPath,
-		SubPrefixPath: r.SubPrefixPath,
-		Rewrite:       rewrite,
-		HeaderSet:     HeaderSet,
-		HeaderAdd:     HeaderAdd,
-		HeaderDel:     HeaderDel,
-		QuerySet:      QuerySet,
-		QueryAdd:      QueryAdd,
-		Via:           r.Via,
+		Address:   r.Address,
+		TargetURL: targetURL,
+		Server:    server,
+		AddPath:   r.AddPath,
+		SubPath:   r.SubPath,
+		Rewrite:   rewrite,
+		HeaderSet: HeaderSet,
+		HeaderAdd: HeaderAdd,
+		HeaderDel: HeaderDel,
+		QuerySet:  QuerySet,
+		QueryAdd:  QueryAdd,
+		Via:       r.Via,
 	}, nil
 }

+ 14 - 14
src/config/rulescompile/actioncompile/dircompile/dirconfig.go

@@ -7,13 +7,13 @@ import (
 )
 
 type RuleDirCompileConfig struct {
-	BasePath      string
-	IndexFile     []*IndexFileCompileConfig
-	IgnoreFile    []*IgnoreFileCompileConfig
-	AddPrefixPath string
-	SubPrefixPath string
-	Rewrite       *rewritecompile.RewriteCompileConfig
-	Cors          *corscompile.CorsCompileConfig
+	BasePath   string
+	IndexFile  []*IndexFileCompileConfig
+	IgnoreFile []*IgnoreFileCompileConfig
+	AddPath    string
+	SubPath    string
+	Rewrite    *rewritecompile.RewriteCompileConfig
+	Cors       *corscompile.CorsCompileConfig
 }
 
 func NewRuleDirCompileConfig(r *dir.RuleDirConfig) (*RuleDirCompileConfig, error) {
@@ -46,13 +46,13 @@ func NewRuleDirCompileConfig(r *dir.RuleDirConfig) (*RuleDirCompileConfig, error
 	}
 
 	return &RuleDirCompileConfig{
-		BasePath:      r.BasePath,
-		IndexFile:     Index,
-		IgnoreFile:    Ignore,
-		AddPrefixPath: r.AddPrefixPath,
-		SubPrefixPath: r.SubPrefixPath,
-		Rewrite:       rewrite,
-		Cors:          cors,
+		BasePath:   r.BasePath,
+		IndexFile:  Index,
+		IgnoreFile: Ignore,
+		AddPath:    r.AddPath,
+		SubPath:    r.SubPath,
+		Rewrite:    rewrite,
+		Cors:       cors,
 	}, nil
 }
 

+ 1 - 1
src/config/yamlconfig.go

@@ -19,7 +19,7 @@ func (y *YamlConfig) Init() error {
 
 func (y *YamlConfig) SetDefault() {
 	y.GlobalConfig.SetDefault()
-	y.Http.SetDefault(&y.GlobalConfig)
+	y.Http.SetDefault()
 	y.RuleListConfig.SetDefault()
 }
 

+ 2 - 2
src/logger/logger.go

@@ -59,7 +59,7 @@ func InitLogger(warnWriter, errWriter io.Writer) error {
 		panic("config is not ready")
 	}
 
-	level := LoggerLevel(config.Config().Yaml.GlobalConfig.LogLevel)
+	level := LoggerLevel(config.GetConfig().GlobalConfig.LogLevel)
 	logLevel, ok := levelMap[level]
 	if !ok {
 		return fmt.Errorf("invalid log level: %s", level)
@@ -76,7 +76,7 @@ func InitLogger(warnWriter, errWriter io.Writer) error {
 	logger := &Logger{
 		level:      level,
 		logLevel:   logLevel,
-		logTag:     config.Config().Yaml.LogTag.ToBool(true),
+		logTag:     config.GetConfig().LogTag.ToBool(true),
 		warnWriter: os.Stdout,
 		errWriter:  os.Stderr,
 		args0:      utils.GetArgs0(),

+ 8 - 3
src/mainfunc/v1.go

@@ -38,7 +38,12 @@ func MainV1() int {
 		return utils.ExitByErrorMsg("config parser unknown error")
 	}
 
-	cfg := config.Config()
+	cfg := config.GetConfig()
+	err = config.NotifyConfigFile()
+	if err != nil {
+		return utils.ExitByError(err)
+	}
+	defer config.CloseNotifyConfigFile()
 
 	err = logger.InitLogger(os.Stdout, os.Stderr)
 	if err != nil {
@@ -50,7 +55,7 @@ func MainV1() int {
 	}
 
 	logger.Executable()
-	logger.Infof("run mode: %s", cfg.Yaml.GlobalConfig.GetRunMode())
+	logger.Infof("run mode: %s", cfg.GlobalConfig.GetRunMode())
 
 	ser := server.NewServer()
 
@@ -69,7 +74,7 @@ func MainV1() int {
 	}()
 
 	select {
-	case <-cfg.GetSignalChan():
+	case <-config.GetSignalChan():
 		break
 	case err := <-sererror:
 		return utils.ExitByError(err)

+ 1 - 1
src/server/api.go

@@ -23,7 +23,7 @@ func (s *HTTPServer) apiServer(rule *rulescompile.RuleCompileConfig, w http.Resp
 
 	s.processProxyHeader(r)
 
-	r.URL.Path = s.apiRewrite(utils.ProcessURLPath(r.URL.Path), rule.Api.AddPrefixPath, rule.Api.SubPrefixPath, rule.Api.Rewrite)
+	r.URL.Path = s.apiRewrite(utils.ProcessURLPath(r.URL.Path), rule.Api.AddPath, rule.Api.SubPath, rule.Api.Rewrite)
 
 	for _, h := range rule.Api.HeaderSet {
 		r.Header.Set(h.Header, h.Value)

+ 3 - 3
src/server/dir.go

@@ -31,14 +31,14 @@ func (s *HTTPServer) dirServer(rule *rulescompile.RuleCompileConfig, w http.Resp
 
 	url := utils.ProcessURLPath(r.URL.Path)
 	if rule.MatchType == matchcompile.RegexMatch {
-		fileAccess = s.dirRewrite("", rule.Dir.AddPrefixPath, rule.Dir.SubPrefixPath, rule.Dir.Rewrite)
+		fileAccess = s.dirRewrite("", rule.Dir.AddPath, rule.Dir.SubPath, rule.Dir.Rewrite)
 		filePath = path.Join(dirBasePath, fileAccess)
 	} else {
 		if url == rule.MatchPath {
-			fileAccess = s.dirRewrite("", rule.Dir.AddPrefixPath, rule.Dir.SubPrefixPath, rule.Dir.Rewrite)
+			fileAccess = s.dirRewrite("", rule.Dir.AddPath, rule.Dir.SubPath, rule.Dir.Rewrite)
 			filePath = path.Join(dirBasePath, fileAccess)
 		} else if strings.HasPrefix(url, rule.MatchPath+"/") {
-			fileAccess = s.dirRewrite(url[len(rule.MatchPath+"/"):], rule.Dir.AddPrefixPath, rule.Dir.SubPrefixPath, rule.Dir.Rewrite)
+			fileAccess = s.dirRewrite(url[len(rule.MatchPath+"/"):], rule.Dir.AddPath, rule.Dir.SubPath, rule.Dir.Rewrite)
 			filePath = path.Join(dirBasePath, fileAccess)
 		} else {
 			s.abortNotFound(w)

+ 17 - 3
src/server/server.go

@@ -4,6 +4,7 @@ import (
 	"errors"
 	"fmt"
 	"github.com/SongZihuan/huan-proxy/src/config"
+	"github.com/SongZihuan/huan-proxy/src/config/rulescompile"
 	"github.com/SongZihuan/huan-proxy/src/flagparser"
 	"github.com/SongZihuan/huan-proxy/src/logger"
 	"net/http"
@@ -13,7 +14,6 @@ var ServerStop = fmt.Errorf("server stop")
 
 type HTTPServer struct {
 	address string
-	cfg     *config.ConfigStruct
 	skip    map[string]struct{}
 	isTerm  bool
 	writer  func(msg string)
@@ -27,14 +27,28 @@ func NewServer() *HTTPServer {
 	var skip = make(map[string]struct{}, 10)
 
 	return &HTTPServer{
-		address: config.Config().Yaml.Http.Address,
-		cfg:     config.Config(),
+		address: config.GetConfig().Http.Address,
 		skip:    skip,
 		isTerm:  logger.IsInfoTermNotDumb(),
 		writer:  logger.InfoWrite,
 	}
 }
 
+func (s *HTTPServer) GetConfig() *config.YamlConfig {
+	// 不用检查Ready,因为在NewServer的时候已经检查过了
+	return config.GetConfig()
+}
+
+func (s *HTTPServer) GetRules() *rulescompile.RuleListCompileConfig {
+	// 不用检查Ready,因为在NewServer的时候已经检查过了
+	return config.GetRules()
+}
+
+func (s *HTTPServer) GetRulesList() []*rulescompile.RuleCompileConfig {
+	// 不用检查Ready,因为在NewServer的时候已经检查过了
+	return s.GetRules().Rules
+}
+
 func (s *HTTPServer) Run() error {
 	err := s.run()
 	if errors.Is(err, http.ErrServerClosed) {

+ 1 - 1
src/server/serverhttp.go

@@ -9,7 +9,7 @@ func (s *HTTPServer) NormalServeHTTP(w http.ResponseWriter, r *http.Request) {
 	s.writeHuanProxyHeader(r)
 
 	func() {
-		for _, rule := range s.cfg.Rules.Rules {
+		for _, rule := range s.GetRulesList() {
 			if !s.matchURL(rule, r) {
 				continue
 			}