refactor(config): 重构配置处理逻辑

- 移除 config.json 中的 admin 配置,改为单独的配置文件
- 新增 Strings 类型处理服务器名称,支持字符串和字符串数组
- 优化服务器匹配逻辑,支持多域名配置
- 重构代码结构,提高可维护性和可扩展性
This commit is contained in:
kingecg 2025-06-23 23:12:03 +08:00
parent 949de14d47
commit 1b0db0e14b
7 changed files with 170 additions and 45 deletions

View File

@ -21,37 +21,8 @@
}
}
},
"admin": {
"name": "admin",
"server":"localhost",
"port": 8088,
"username": "admin",
"password": "admin",
"directives": [
"Set-Header Access-Control-Allow-Origin *",
"Set-Header Access-Control-Allow-Methods GET, POST, PUT, DELETE, OPTIONS",
"Set-Header Access-Control-Allow-Headers Content-Type, Authorization, Content-Length, X-Requested-With"
],
"paths": [
{
"path": "/",
"root": "./adminui",
"default": "index.html"
}
]
},
"includs":"./include",
"servers": [
{
"name": "teststatic",
"server":"www.teststatic.com",
"port": 8088,
"paths": [
{
"path": "/",
"root": "./example",
"default": "index.html"
}
]
}
]
}

View File

@ -30,14 +30,17 @@ func (g *GoHttp) Start() {
g.logger.Info("start gohttpd")
// if g.conf != nil {
if conf.Admin != nil {
// 设置管理员处理器并使用管理员服务配置
adminHandler := server.NewServeMux(conf.Admin)
admin.InitAdminApi(conf.Admin)
adminHandler.Handle("/api/", http.StripPrefix("/api", admin.AdminServerMux), []string{})
// 设置管理员处理器并使用管理员服务配置
adminHandler := server.NewServeMux(conf.Admin)
admin.InitAdminApi(conf.Admin)
adminHandler.Handle("/api/", http.StripPrefix("/api", admin.AdminServerMux), []string{})
// 创建并启动管理员服务器
g.makeServer(conf.Admin, adminHandler)
// 创建并启动管理员服务器
g.makeServer(conf.Admin, adminHandler)
} else {
g.logger.Info("no admin server config, skip admin server")
}
// 遍历配置中的服务器列表,为每个服务器设置处理器并启动
for _, s := range conf.Servers {
@ -101,7 +104,9 @@ func LoadConfig() {
}
// 规范化管理员服务器配置中的路径
normalizeServer(model.Config.Admin)
if model.Config.Admin != nil {
normalizeServer(model.Config.Admin)
}
if model.Config.IncludDir != "" {
model.Config.IncludDir = utils.NormalizePath(model.Config.IncludDir)

View File

@ -0,0 +1,12 @@
{
"name": "teststatic",
"server": "www.teststatic.com",
"port": 8088,
"paths": [
{
"path": "/",
"root": "./example",
"default": "index.html"
}
]
}

View File

@ -34,7 +34,7 @@ const (
// HttpServerConfig 定义HTTP服务器配置
type HttpServerConfig struct {
Name string `json:"name"`
ServerName string `json:"server"`
ServerName Strings `json:"server"`
Port int `json:"port"`
Host string `json:"host"`
Paths []HttpPath `json:"paths"`
@ -64,12 +64,12 @@ type JwtConfig struct {
type GoHttpdConfig struct {
Logging gologger.LoggersConfig `json:"logging"`
Admin *HttpServerConfig `json:"admin"`
IncludDir string `json:"includ_dir"`
IncludDir string `json:"includs"`
Servers []*HttpServerConfig `json:"servers"`
}
var DefaultAdminConfig HttpServerConfig = HttpServerConfig{
ServerName: "admin",
ServerName: Strings{"admin"},
Port: 8080,
}

53
model/names.go Normal file
View File

@ -0,0 +1,53 @@
package model
import (
"encoding/json"
"errors"
"strings"
)
type Strings struct {
Values interface{}
}
func (s *Strings) UnmarshalJSON(data []byte) error {
var raw interface{}
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
switch v := raw.(type) {
case string:
s.Values = v
return nil
case []interface{}:
for _, item := range v {
if _, ok := item.(string); !ok {
return errors.New("invalid type in array, expected string")
}
}
s.Values = v
return nil
default:
return errors.New("invalid type")
}
}
func (s *Strings) MarshalJSON() ([]byte, error) {
return json.Marshal(s.Values)
}
func (s *Strings) HasOrContainPrefix(value string) bool {
switch v := s.Values.(type) {
case []interface{}:
for _, item := range v {
if strings.HasPrefix(value, item.(string)) {
return true
}
}
return false
case string:
return strings.HasPrefix(value, v)
default:
return false
}
}

85
model/names_test.go Normal file
View File

@ -0,0 +1,85 @@
package model
import (
"testing"
)
func TestStrings_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
input string
want interface{}
wantErr bool
}{
{
name: "valid string",
input: `"test"`,
want: "test",
},
{
name: "valid array",
input: `["a","b"]`,
want: []string{"a", "b"},
},
{
name: "invalid type",
input: `123`,
wantErr: true,
},
{
name: "invalid array type",
input: `["a", 123]`,
wantErr: true,
},
}
for _, tt := range tests {
s := &Strings{}
err := s.UnmarshalJSON([]byte(tt.input))
if tt.wantErr {
if err == nil {
t.Errorf("%s: expected error but got none", tt.name)
}
continue
}
if err != nil {
t.Errorf("%s: unexpected error %v", tt.name, err)
continue
}
}
}
func TestStrings_HasOrContainPrefix(t *testing.T) {
tests := []struct {
name string
input string
value string
want bool
wantErr bool
}{
{
name: "valid string",
input: `"test"`,
value: "test",
want: true,
},
{
name: "valid array",
input: `["a","b"]`,
value: "a",
want: true,
},
}
for _, tt := range tests {
s := &Strings{}
err := s.UnmarshalJSON([]byte(tt.input))
if err != nil {
t.Errorf("%s: unexpected error %v", tt.name, err)
continue
}
got := s.HasOrContainPrefix(tt.value)
if got != tt.want {
t.Errorf("%s: expected %v, got %v", tt.name, tt.want, got)
}
}
}

View File

@ -5,7 +5,6 @@ import (
"fmt"
"net"
"net/http"
"strings"
"bufio"
"io"
@ -17,7 +16,7 @@ import (
var ServerManager map[string]*ServerListener = make(map[string]*ServerListener)
func makeMatcher(name string, s *ServerListener) cmux.Matcher {
func makeMatcher(name model.Strings, s *ServerListener) cmux.Matcher {
return func(r io.Reader) bool {
if s.ServerCount() == 1 {
return true
@ -26,7 +25,7 @@ func makeMatcher(name string, s *ServerListener) cmux.Matcher {
if err != nil {
return false
}
return strings.HasPrefix(req.Host, name)
return name.HasOrContainPrefix(req.Host) || name.HasOrContainPrefix(req.URL.Host)
}
}