2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 10:17:17 +08:00

feat: 优化上游设置

This commit is contained in:
2026-01-09 20:59:34 +08:00
parent cdb1296462
commit 77cb594ee4
9 changed files with 227 additions and 160 deletions

View File

@@ -44,6 +44,6 @@ type WebsiteSetting struct {
OpenBasedir bool `json:"open_basedir"`
// 反向代理
Upstreams map[string]types.Upstream `json:"upstreams"`
Proxies []types.Proxy `json:"proxies"`
Upstreams []types.Upstream `json:"upstreams"`
Proxies []types.Proxy `json:"proxies"`
}

View File

@@ -252,7 +252,7 @@ func generateProxyConfig(proxy types.Proxy) string {
}
// parseBalancerFiles 从 shared 目录解析所有负载均衡配置Apache 的 upstream 等价物)
func parseBalancerFiles(sharedDir string) (map[string]types.Upstream, error) {
func parseBalancerFiles(sharedDir string) ([]types.Upstream, error) {
entries, err := os.ReadDir(sharedDir)
if err != nil {
if os.IsNotExist(err) {
@@ -261,7 +261,7 @@ func parseBalancerFiles(sharedDir string) (map[string]types.Upstream, error) {
return nil, err
}
upstreams := make(map[string]types.Upstream)
var upstreams []types.Upstream
for _, entry := range entries {
if entry.IsDir() {
continue
@@ -272,14 +272,13 @@ func parseBalancerFiles(sharedDir string) (map[string]types.Upstream, error) {
continue
}
name := matches[2]
filePath := filepath.Join(sharedDir, entry.Name())
upstream, err := parseBalancerFile(filePath)
upstream, err := parseBalancerFile(filePath, matches[2])
if err != nil {
continue // 跳过解析失败的文件
}
if upstream != nil {
upstreams[name] = *upstream
upstreams = append(upstreams, *upstream)
}
}
@@ -287,7 +286,7 @@ func parseBalancerFiles(sharedDir string) (map[string]types.Upstream, error) {
}
// parseBalancerFile 解析单个负载均衡配置文件
func parseBalancerFile(filePath string) (*types.Upstream, error) {
func parseBalancerFile(filePath string, name string) (*types.Upstream, error) {
content, err := os.ReadFile(filePath)
if err != nil {
return nil, err
@@ -295,6 +294,7 @@ func parseBalancerFile(filePath string) (*types.Upstream, error) {
contentStr := string(content)
upstream := &types.Upstream{
Name: name,
Servers: make(map[string]string),
}
@@ -342,23 +342,22 @@ func parseBalancerFile(filePath string) (*types.Upstream, error) {
}
// writeBalancerFiles 将负载均衡配置写入文件
func writeBalancerFiles(sharedDir string, upstreams map[string]types.Upstream) error {
func writeBalancerFiles(sharedDir string, upstreams []types.Upstream) error {
// 删除现有的负载均衡配置文件
if err := clearBalancerFiles(sharedDir); err != nil {
return err
}
// 写入新的配置文件
num := 100
for name, upstream := range upstreams {
fileName := fmt.Sprintf("%03d-balancer-%s.conf", num, name)
// 写入新的配置文件,保持顺序
for i, upstream := range upstreams {
num := 100 + i
fileName := fmt.Sprintf("%03d-balancer-%s.conf", num, upstream.Name)
filePath := filepath.Join(sharedDir, fileName)
content := generateBalancerConfig(name, upstream)
content := generateBalancerConfig(upstream)
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
return fmt.Errorf("failed to write balancer config: %w", err)
}
num++
}
return nil
@@ -391,12 +390,12 @@ func clearBalancerFiles(sharedDir string) error {
}
// generateBalancerConfig 生成负载均衡配置内容
func generateBalancerConfig(name string, upstream types.Upstream) string {
func generateBalancerConfig(upstream types.Upstream) string {
var sb strings.Builder
sb.WriteString(fmt.Sprintf("# Load balancer: %s\n", name))
sb.WriteString(fmt.Sprintf("# Load balancer: %s\n", upstream.Name))
sb.WriteString("<IfModule mod_proxy_balancer.c>\n")
sb.WriteString(fmt.Sprintf(" <Proxy balancer://%s>\n", name))
sb.WriteString(fmt.Sprintf(" <Proxy balancer://%s>\n", upstream.Name))
// 服务器列表
for addr, options := range upstream.Servers {

View File

@@ -679,13 +679,13 @@ func (v *ProxyVhost) ClearProxies() error {
return clearProxyFiles(siteDir)
}
func (v *ProxyVhost) Upstreams() map[string]types.Upstream {
func (v *ProxyVhost) Upstreams() []types.Upstream {
sharedDir := filepath.Join(v.configDir, "shared")
upstreams, _ := parseBalancerFiles(sharedDir)
return upstreams
}
func (v *ProxyVhost) SetUpstreams(upstreams map[string]types.Upstream) error {
func (v *ProxyVhost) SetUpstreams(upstreams []types.Upstream) error {
sharedDir := filepath.Join(v.configDir, "shared")
return writeBalancerFiles(sharedDir, upstreams)
}

View File

@@ -7,6 +7,7 @@ import (
"regexp"
"strconv"
"strings"
"time"
"github.com/acepanel/panel/pkg/webserver/types"
)
@@ -15,7 +16,7 @@ import (
var upstreamFilePattern = regexp.MustCompile(`^(\d{3})-(.+)\.conf$`)
// parseUpstreamFiles 从 shared 目录解析所有 upstream 配置
func parseUpstreamFiles(sharedDir string) (map[string]types.Upstream, error) {
func parseUpstreamFiles(sharedDir string) ([]types.Upstream, error) {
entries, err := os.ReadDir(sharedDir)
if err != nil {
if os.IsNotExist(err) {
@@ -24,7 +25,7 @@ func parseUpstreamFiles(sharedDir string) (map[string]types.Upstream, error) {
return nil, err
}
upstreams := make(map[string]types.Upstream)
var upstreams []types.Upstream
for _, entry := range entries {
if entry.IsDir() {
continue
@@ -40,14 +41,13 @@ func parseUpstreamFiles(sharedDir string) (map[string]types.Upstream, error) {
continue
}
name := matches[2]
filePath := filepath.Join(sharedDir, entry.Name())
upstream, err := parseUpstreamFile(filePath, name)
upstream, err := parseUpstreamFile(filePath, matches[2])
if err != nil {
continue // 跳过解析失败的文件
}
if upstream != nil {
upstreams[name] = *upstream
upstreams = append(upstreams, *upstream)
}
}
@@ -82,7 +82,9 @@ func parseUpstreamFile(filePath string, expectedName string) (*types.Upstream, e
blockContent := matches[2]
upstream := &types.Upstream{
Servers: make(map[string]string),
Name: name,
Servers: make(map[string]string),
Resolver: []string{},
}
// 解析负载均衡算法
@@ -95,7 +97,8 @@ func parseUpstreamFile(filePath string, expectedName string) (*types.Upstream, e
}
// 解析 server 指令
serverPattern := regexp.MustCompile(`server\s+(\S+)(?:\s+([^;]+))?;`)
// 匹配: server 127.0.0.1:8080; 或 server 127.0.0.1:8080 weight=5;
serverPattern := regexp.MustCompile(`server\s+([^\s;]+)(?:\s+([^;]+))?;`)
serverMatches := serverPattern.FindAllStringSubmatch(blockContent, -1)
for _, sm := range serverMatches {
addr := sm[1]
@@ -112,27 +115,48 @@ func parseUpstreamFile(filePath string, expectedName string) (*types.Upstream, e
upstream.Keepalive, _ = strconv.Atoi(km[1])
}
// 解析 resolver
resolverPattern := regexp.MustCompile(`resolver\s+([^;]+);`)
if rm := resolverPattern.FindStringSubmatch(blockContent); rm != nil {
parts := strings.Fields(rm[1])
upstream.Resolver = parts
}
// 解析 resolver_timeout
resolverTimeoutPattern := regexp.MustCompile(`resolver_timeout\s+(\d+)([smh]?);`)
if rtm := resolverTimeoutPattern.FindStringSubmatch(blockContent); rtm != nil {
value, _ := strconv.Atoi(rtm[1])
unit := rtm[2]
switch unit {
case "m":
upstream.ResolverTimeout = time.Duration(value) * time.Minute
case "h":
upstream.ResolverTimeout = time.Duration(value) * time.Hour
default:
upstream.ResolverTimeout = time.Duration(value) * time.Second
}
}
return upstream, nil
}
// writeUpstreamFiles 将 upstream 配置写入文件
func writeUpstreamFiles(sharedDir string, upstreams map[string]types.Upstream) error {
func writeUpstreamFiles(sharedDir string, upstreams []types.Upstream) error {
// 删除现有的 upstream 配置文件
if err := clearUpstreamFiles(sharedDir); err != nil {
return err
}
// 写入新的配置文件
num := UpstreamStartNum
for name, upstream := range upstreams {
fileName := fmt.Sprintf("%03d-%s.conf", num, name)
// 写入新的配置文件,保持顺序
for i, upstream := range upstreams {
num := UpstreamStartNum + i
fileName := fmt.Sprintf("%03d-%s.conf", num, upstream.Name)
filePath := filepath.Join(sharedDir, fileName)
content := generateUpstreamConfig(name, upstream)
content := generateUpstreamConfig(upstream)
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
return fmt.Errorf("failed to write upstream config: %w", err)
}
num++
}
return nil
@@ -171,17 +195,25 @@ func clearUpstreamFiles(sharedDir string) error {
}
// generateUpstreamConfig 生成 upstream 配置内容
func generateUpstreamConfig(name string, upstream types.Upstream) string {
func generateUpstreamConfig(upstream types.Upstream) string {
var sb strings.Builder
sb.WriteString(fmt.Sprintf("# Upstream: %s\n", name))
sb.WriteString(fmt.Sprintf("upstream %s {\n", name))
sb.WriteString(fmt.Sprintf("# Upstream: %s\n", upstream.Name))
sb.WriteString(fmt.Sprintf("upstream %s {\n", upstream.Name))
// 负载均衡算法
if upstream.Algo != "" {
sb.WriteString(fmt.Sprintf(" %s;\n", upstream.Algo))
}
// resolver 配置
if len(upstream.Resolver) > 0 {
sb.WriteString(fmt.Sprintf(" resolver %s;\n", strings.Join(upstream.Resolver, " ")))
if upstream.ResolverTimeout > 0 {
sb.WriteString(fmt.Sprintf(" resolver_timeout %ds;\n", int(upstream.ResolverTimeout.Seconds())))
}
}
// 服务器列表
for addr, options := range upstream.Servers {
if options != "" {

View File

@@ -730,13 +730,13 @@ func (v *ProxyVhost) ClearProxies() error {
return clearProxyFiles(siteDir)
}
func (v *ProxyVhost) Upstreams() map[string]types.Upstream {
func (v *ProxyVhost) Upstreams() []types.Upstream {
sharedDir := filepath.Join(v.configDir, "shared")
upstreams, _ := parseUpstreamFiles(sharedDir)
return upstreams
}
func (v *ProxyVhost) SetUpstreams(upstreams map[string]types.Upstream) error {
func (v *ProxyVhost) SetUpstreams(upstreams []types.Upstream) error {
sharedDir := filepath.Join(v.configDir, "shared")
return writeUpstreamFiles(sharedDir, upstreams)
}

View File

@@ -17,6 +17,7 @@ type Proxy struct {
// Upstream 上游服务器配置
type Upstream struct {
Name string `form:"name" json:"name" validate:"required"` // 上游名称,如: "backend"
Servers map[string]string `form:"servers" json:"servers" validate:"required"` // 上游服务器及配置,如: map["server1"] = "weight=5 resolve"
Algo string `form:"algo" json:"algo"` // 负载均衡算法,如: "least_conn", "ip_hash"
Keepalive int `form:"keepalive" json:"keepalive"` // 保持连接数,如: 32

View File

@@ -133,9 +133,9 @@ type VhostProxy interface {
ClearProxies() error
// Upstreams 取上游服务器配置
Upstreams() map[string]Upstream
Upstreams() []Upstream
// SetUpstreams 设置上游服务器配置
SetUpstreams(upstreams map[string]Upstream) error
SetUpstreams(upstreams []Upstream) error
// ClearUpstreams 清除所有上游服务器配置
ClearUpstreams() error
}