2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-05 01:48:43 +08:00
Files
panel/pkg/webserver/nginx/parser.go
2025-12-04 00:35:12 +08:00

258 lines
6.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package nginx
import (
"errors"
"fmt"
"os"
"slices"
"strings"
"github.com/tufanbarisyildirim/gonginx/config"
"github.com/tufanbarisyildirim/gonginx/dumper"
"github.com/tufanbarisyildirim/gonginx/parser"
)
// Parser Nginx vhost 配置解析器
type Parser struct {
cfg *config.Config
cfgPath string // 配置文件路径
}
func NewParser(website ...string) (*Parser, error) {
str := DefaultConf
cfgPath := ""
if len(website) != 0 && website[0] != "" {
cfgPath = fmt.Sprintf("/opt/ace/sites/%s/config/nginx.conf", website[0])
if cfg, err := os.ReadFile(cfgPath); err == nil {
str = string(cfg)
} else {
return nil, err
}
}
p := parser.NewStringParser(str, parser.WithSkipIncludeParsingErr(), parser.WithSkipValidDirectivesErr())
cfg, err := p.Parse()
if err != nil {
return nil, err
}
return &Parser{cfg: cfg, cfgPath: cfgPath}, nil
}
// NewParserFromFile 从指定文件路径创建解析器
func NewParserFromFile(filePath string) (*Parser, error) {
content, err := os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("failed to read config file: %w", err)
}
p := parser.NewStringParser(string(content), parser.WithSkipIncludeParsingErr(), parser.WithSkipValidDirectivesErr())
cfg, err := p.Parse()
if err != nil {
return nil, fmt.Errorf("failed to parse config file: %w", err)
}
return &Parser{cfg: cfg, cfgPath: filePath}, nil
}
func (p *Parser) Config() *config.Config {
return p.cfg
}
// Find 查找指令,如: Find("server.listen")
func (p *Parser) Find(key string) ([]config.IDirective, error) {
parts := strings.Split(key, ".")
var block *config.Block
var ok bool
block = p.cfg.Block
for i := 0; i < len(parts)-1; i++ {
key = parts[i]
directives := block.FindDirectives(key)
if len(directives) == 0 {
return nil, fmt.Errorf("given key %s not found", key)
}
if len(directives) > 1 {
return nil, errors.New("multiple directives found")
}
block, ok = directives[0].GetBlock().(*config.Block)
if !ok {
return nil, errors.New("block is not *config.Block")
}
}
var result []config.IDirective
for _, dir := range block.GetDirectives() {
if dir.GetName() == parts[len(parts)-1] {
result = append(result, dir)
}
}
return result, nil
}
// FindOne 查找单个指令,如: FindOne("server.server_name")
func (p *Parser) FindOne(key string) (config.IDirective, error) {
directives, err := p.Find(key)
if err != nil {
return nil, err
}
if len(directives) == 0 {
return nil, fmt.Errorf("given key %s not found", key)
}
if len(directives) > 1 {
return nil, fmt.Errorf("multiple directives found for %s", key)
}
return directives[0], nil
}
// Clear 移除指令,如: Clear("server.server_name")
func (p *Parser) Clear(key string) error {
parts := strings.Split(key, ".")
last := parts[len(parts)-1]
parts = parts[:len(parts)-1]
var block *config.Block
var ok bool
block = p.cfg.Block
for i := 0; i < len(parts); i++ {
directives := block.FindDirectives(parts[i])
if len(directives) == 0 {
return fmt.Errorf("given key %s not found", parts[i])
}
if len(directives) > 1 {
return fmt.Errorf("multiple directives found for %s", parts[i])
}
block, ok = directives[0].GetBlock().(*config.Block)
if !ok {
return errors.New("block is not *config.Block")
}
}
var newDirectives []config.IDirective
for _, directive := range block.GetDirectives() {
if directive.GetName() != last {
newDirectives = append(newDirectives, directive)
}
}
block.Directives = newDirectives
return nil
}
// Set 设置指令,如: Set("server.index", []Directive{...})
func (p *Parser) Set(key string, directives []*config.Directive, after ...string) error {
parts := strings.Split(key, ".")
var block *config.Block
var blockDirective config.IDirective
var ok bool
block = p.cfg.Block
for i := 0; i < len(parts); i++ {
sub := block.FindDirectives(parts[i])
if len(sub) == 0 {
return fmt.Errorf("given key %s not found", parts[i])
}
if len(sub) > 1 {
return fmt.Errorf("multiple directives found for %s", parts[i])
}
block, ok = sub[0].GetBlock().(*config.Block)
if !ok {
return errors.New("block is not *config.Block")
}
blockDirective = sub[0]
}
iDirectives := make([]config.IDirective, 0, len(directives))
for _, directive := range directives {
directive.SetParent(blockDirective)
iDirectives = append(iDirectives, directive)
}
if len(after) == 0 {
block.Directives = append(block.Directives, iDirectives...)
} else {
insertIndex := -1
for i, d := range block.Directives {
if d.GetName() == after[0] {
insertIndex = i + 1
break
}
}
if insertIndex == -1 {
return fmt.Errorf("after directive %s not found", after[0])
}
block.Directives = append(
block.Directives[:insertIndex],
append(iDirectives, block.Directives[insertIndex:]...)...,
)
}
return nil
}
// Dump 将指令结构导出为配置内容
func (p *Parser) Dump() string {
return dumper.DumpConfig(p.cfg, dumper.IndentedStyle)
}
// Save 保存配置到文件
func (p *Parser) Save() error {
p.sortDirectives(p.cfg.Directives, order)
content := p.Dump() + "\n"
if err := os.WriteFile(p.cfgPath, []byte(content), 0644); err != nil {
return fmt.Errorf("failed to save config file: %w", err)
}
return nil
}
// SetConfigPath 设置配置文件路径
func (p *Parser) SetConfigPath(path string) {
p.cfgPath = path
}
func (p *Parser) sortDirectives(directives []config.IDirective, orderIndex map[string]int) {
slices.SortFunc(directives, func(a config.IDirective, b config.IDirective) int {
// 块指令(如 server、location应该排在普通指令如 include后面
aIsBlock := a.GetBlock() != nil && len(a.GetBlock().GetDirectives()) > 0
bIsBlock := b.GetBlock() != nil && len(b.GetBlock().GetDirectives()) > 0
if aIsBlock != bIsBlock {
if aIsBlock {
return 1 // a 是块指令,排在后面
}
return -1 // b 是块指令,排在前面
}
// 同类指令,按 order 排序
if orderIndex[a.GetName()] != orderIndex[b.GetName()] {
return orderIndex[a.GetName()] - orderIndex[b.GetName()]
}
return slices.Compare(p.parameters2Slices(a.GetParameters()), p.parameters2Slices(b.GetParameters()))
})
for _, directive := range directives {
if block, ok := directive.GetBlock().(*config.Block); ok {
p.sortDirectives(block.Directives, orderIndex)
}
}
}
func (p *Parser) slices2Parameters(slices []string) []config.Parameter {
var parameters []config.Parameter
for _, slice := range slices {
parameters = append(parameters, config.Parameter{Value: slice})
}
return parameters
}
func (p *Parser) parameters2Slices(parameters []config.Parameter) []string {
var s []string
for _, parameter := range parameters {
s = append(s, parameter.Value)
}
return s
}