mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2026-06-19 07:36:59 +00:00
feat: add support for root block configuration in NgxConfig and implement parsing logic
This commit is contained in:
@@ -3,6 +3,7 @@ import { http } from '@uozi-admin/request'
|
||||
export interface NgxConfig {
|
||||
file_name?: string
|
||||
name: string
|
||||
root_block?: 'http' | 'stream'
|
||||
upstreams?: NgxUpstream[]
|
||||
servers: NgxServer[]
|
||||
custom?: string
|
||||
|
||||
@@ -17,6 +17,32 @@ func buildComments(orig string, indent int) (content string) {
|
||||
return
|
||||
}
|
||||
|
||||
func wrapRootBlock(name, content string) string {
|
||||
trimmedContent := strings.TrimSpace(content)
|
||||
if trimmedContent == "" {
|
||||
return fmt.Sprintf("%s {\n}\n", name)
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
builder.WriteString(name)
|
||||
builder.WriteString(" {\n")
|
||||
|
||||
scanner := bufio.NewScanner(strings.NewReader(strings.TrimRight(content, "\n")))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if line == "" {
|
||||
builder.WriteByte('\n')
|
||||
continue
|
||||
}
|
||||
builder.WriteByte('\t')
|
||||
builder.WriteString(line)
|
||||
builder.WriteByte('\n')
|
||||
}
|
||||
|
||||
builder.WriteString("}\n")
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func (c *NgxConfig) BuildConfig() (content string, err error) {
|
||||
// Custom
|
||||
if c.Custom != "" {
|
||||
@@ -82,6 +108,11 @@ func (c *NgxConfig) BuildConfig() (content string, err error) {
|
||||
|
||||
content += fmt.Sprintf("%sserver {\n%s}\n\n", comments, server)
|
||||
}
|
||||
|
||||
if c.RootBlock != "" {
|
||||
content = wrapRootBlock(c.RootBlock, content)
|
||||
}
|
||||
|
||||
p := parser.NewStringParser(content, parser.WithSkipValidDirectivesErr())
|
||||
cfg, err := p.Parse()
|
||||
if err != nil {
|
||||
|
||||
@@ -13,6 +13,8 @@ const (
|
||||
Server = "server"
|
||||
Location = "location"
|
||||
Upstream = "upstream"
|
||||
Http = "http"
|
||||
Stream = "stream"
|
||||
)
|
||||
|
||||
func (s *NgxServer) ParseServer(directive config.IDirective) {
|
||||
@@ -170,11 +172,40 @@ func buildComment(c []string) string {
|
||||
return strings.ReplaceAll(strings.Join(c, "\n"), "#", "")
|
||||
}
|
||||
|
||||
func shouldUnwrapRootBlock(block config.IBlock) config.IDirective {
|
||||
if block == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
directives := block.GetDirectives()
|
||||
if len(directives) != 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
directive := directives[0]
|
||||
if directive.GetBlock() == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
switch directive.GetName() {
|
||||
case Http, Stream:
|
||||
return directive
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func parse(block config.IBlock, ngxConfig *NgxConfig) (err error) {
|
||||
if block == nil {
|
||||
err = ErrBlockIsNil
|
||||
return
|
||||
}
|
||||
|
||||
if rootBlock := shouldUnwrapRootBlock(block); rootBlock != nil {
|
||||
ngxConfig.RootBlock = rootBlock.GetName()
|
||||
return parse(rootBlock.GetBlock(), ngxConfig)
|
||||
}
|
||||
|
||||
for _, v := range block.GetDirectives() {
|
||||
comments := buildComment(v.GetComment())
|
||||
switch v.GetName() {
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
package nginx
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseNgxConfigByContent_UnwrapsRootStreamBlock(t *testing.T) {
|
||||
content := `stream {
|
||||
log_format vless_lb '$remote_addr:$remote_port [$time_local] '
|
||||
'$protocol $status '
|
||||
'connect=$upstream_connect_time '
|
||||
'session=$session_time '
|
||||
'sent=$bytes_sent recv=$bytes_received '
|
||||
'upstream=$upstream_addr';
|
||||
access_log /var/log/nginx/xray_stream_access.log vless_lb;
|
||||
error_log /var/log/nginx/xray_stream_error.log warn;
|
||||
|
||||
upstream xray_vless_449 {
|
||||
least_conn;
|
||||
server 1.1.1.1:449 fail_timeout=15s max_fails=3;
|
||||
server 1.1.1.1:449 fail_timeout=15s max_fails=3;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 449;
|
||||
proxy_connect_timeout 5s;
|
||||
proxy_timeout 15m;
|
||||
proxy_pass xray_vless_449;
|
||||
}
|
||||
|
||||
include /etc/nginx/streams-enabled/*;
|
||||
}`
|
||||
|
||||
ngxConfig, err := ParseNgxConfigByContent(content)
|
||||
if err != nil {
|
||||
t.Fatalf("ParseNgxConfigByContent() error = %v", err)
|
||||
}
|
||||
|
||||
if ngxConfig.RootBlock != Stream {
|
||||
t.Fatalf("RootBlock = %q, want %q", ngxConfig.RootBlock, Stream)
|
||||
}
|
||||
|
||||
if len(ngxConfig.Upstreams) != 1 {
|
||||
t.Fatalf("len(Upstreams) = %d, want 1", len(ngxConfig.Upstreams))
|
||||
}
|
||||
|
||||
if len(ngxConfig.Servers) != 1 {
|
||||
t.Fatalf("len(Servers) = %d, want 1", len(ngxConfig.Servers))
|
||||
}
|
||||
|
||||
if !strings.Contains(ngxConfig.Custom, "log_format vless_lb") {
|
||||
t.Fatalf("Custom = %q, want log_format directive", ngxConfig.Custom)
|
||||
}
|
||||
|
||||
if !strings.Contains(ngxConfig.Custom, "include /etc/nginx/streams-enabled/*;") {
|
||||
t.Fatalf("Custom = %q, want include directive", ngxConfig.Custom)
|
||||
}
|
||||
|
||||
builtContent, err := ngxConfig.BuildConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("BuildConfig() error = %v", err)
|
||||
}
|
||||
|
||||
if !strings.Contains(builtContent, "stream {") {
|
||||
t.Fatalf("built content = %q, want stream root block", builtContent)
|
||||
}
|
||||
|
||||
if !strings.Contains(builtContent, "upstream xray_vless_449 {") {
|
||||
t.Fatalf("built content = %q, want upstream block", builtContent)
|
||||
}
|
||||
|
||||
if !strings.Contains(builtContent, "least_conn;") {
|
||||
t.Fatalf("built content = %q, want least_conn directive", builtContent)
|
||||
}
|
||||
|
||||
if !strings.Contains(builtContent, "server {") {
|
||||
t.Fatalf("built content = %q, want server block", builtContent)
|
||||
}
|
||||
|
||||
if !strings.Contains(builtContent, "proxy_pass xray_vless_449;") {
|
||||
t.Fatalf("built content = %q, want proxy_pass directive", builtContent)
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
type NgxConfig struct {
|
||||
FileName string `json:"file_name"`
|
||||
Name string `json:"name"`
|
||||
RootBlock string `json:"root_block,omitempty"`
|
||||
Upstreams []*NgxUpstream `json:"upstreams"`
|
||||
Servers []*NgxServer `json:"servers"`
|
||||
Custom string `json:"custom"`
|
||||
|
||||
Reference in New Issue
Block a user