mirror of
				https://github.com/1Panel-dev/1Panel.git
				synced 2025-11-04 07:17:39 +08:00 
			
		
		
		
	feat: 增加nginx config 格式化工具
This commit is contained in:
		
							parent
							
								
									7dad47464d
								
							
						
					
					
						commit
						a1ac689a5e
					
				
					 17 changed files with 1232 additions and 0 deletions
				
			
		| 
						 | 
				
			
			@ -99,3 +99,8 @@ func ExistWithStrArray(str string, arr []string) bool {
 | 
			
		|||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func IsNum(s string) bool {
 | 
			
		||||
	_, err := strconv.ParseFloat(s, 64)
 | 
			
		||||
	return err == nil
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										50
									
								
								backend/utils/nginx/components/block.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								backend/utils/nginx/components/block.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,50 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
type Block struct {
 | 
			
		||||
	Comment    string
 | 
			
		||||
	Directives []IDirective
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Block) GetDirectives() []IDirective {
 | 
			
		||||
	return b.Directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Block) GetComment() string {
 | 
			
		||||
	return b.Comment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Block) FindDirectives(directiveName string) []IDirective {
 | 
			
		||||
	directives := make([]IDirective, 0)
 | 
			
		||||
	for _, directive := range b.GetDirectives() {
 | 
			
		||||
		if directive.GetName() == directiveName {
 | 
			
		||||
			directives = append(directives, directive)
 | 
			
		||||
		}
 | 
			
		||||
		if directive.GetBlock() != nil {
 | 
			
		||||
			directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Block) UpdateDirectives(directiveName string, directive Directive) {
 | 
			
		||||
	directives := make([]IDirective, len(b.GetDirectives()))
 | 
			
		||||
	index := -1
 | 
			
		||||
	for i, dir := range b.GetDirectives() {
 | 
			
		||||
		if dir.GetName() == directiveName {
 | 
			
		||||
			index = i
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if index > -1 {
 | 
			
		||||
		directives[index] = &directive
 | 
			
		||||
	} else {
 | 
			
		||||
		directives = append(directives, &directive)
 | 
			
		||||
	}
 | 
			
		||||
	b.Directives = directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (b *Block) AddDirectives(directive Directive) {
 | 
			
		||||
	directives := append(b.GetDirectives(), &directive)
 | 
			
		||||
	b.Directives = directives
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										21
									
								
								backend/utils/nginx/components/comment.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								backend/utils/nginx/components/comment.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,21 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
type Comment struct {
 | 
			
		||||
	Detail string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Comment) GetName() string {
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Comment) GetParameters() []string {
 | 
			
		||||
	return []string{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Comment) GetBlock() IBlock {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Comment) GetComment() string {
 | 
			
		||||
	return c.Detail
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										28
									
								
								backend/utils/nginx/components/config.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								backend/utils/nginx/components/config.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
type Config struct {
 | 
			
		||||
	*Block
 | 
			
		||||
	FilePath string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) FindDirectives(directiveName string) []IDirective {
 | 
			
		||||
	return c.Block.FindDirectives(directiveName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) FindUpstreams() []*Upstream {
 | 
			
		||||
	var upstreams []*Upstream
 | 
			
		||||
	directives := c.Block.FindDirectives("upstream")
 | 
			
		||||
	for _, directive := range directives {
 | 
			
		||||
		upstreams = append(upstreams, directive.(*Upstream))
 | 
			
		||||
	}
 | 
			
		||||
	return upstreams
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (c *Config) FindServers() []*Server {
 | 
			
		||||
	var servers []*Server
 | 
			
		||||
	directives := c.Block.FindDirectives("server")
 | 
			
		||||
	for _, directive := range directives {
 | 
			
		||||
		servers = append(servers, directive.(*Server))
 | 
			
		||||
	}
 | 
			
		||||
	return servers
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								backend/utils/nginx/components/directive.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								backend/utils/nginx/components/directive.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
type Directive struct {
 | 
			
		||||
	Block      IBlock
 | 
			
		||||
	Name       string
 | 
			
		||||
	Comment    string
 | 
			
		||||
	Parameters []string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Directive) GetComment() string {
 | 
			
		||||
	return d.Comment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Directive) GetName() string {
 | 
			
		||||
	return d.Name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Directive) GetParameters() []string {
 | 
			
		||||
	return d.Parameters
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (d *Directive) GetBlock() IBlock {
 | 
			
		||||
	return d.Block
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										93
									
								
								backend/utils/nginx/components/http.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								backend/utils/nginx/components/http.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,93 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Http struct {
 | 
			
		||||
	Comment    string
 | 
			
		||||
	Servers    []*Server
 | 
			
		||||
	Directives []IDirective
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Http) GetComment() string {
 | 
			
		||||
	return h.Comment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewHttp(directive IDirective) (*Http, error) {
 | 
			
		||||
	if block := directive.GetBlock(); block != nil {
 | 
			
		||||
		http := &Http{
 | 
			
		||||
			Servers:    []*Server{},
 | 
			
		||||
			Directives: []IDirective{},
 | 
			
		||||
			Comment:    block.GetComment(),
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		for _, directive := range block.GetDirectives() {
 | 
			
		||||
			if server, ok := directive.(*Server); ok {
 | 
			
		||||
				http.Servers = append(http.Servers, server)
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
			http.Directives = append(http.Directives, directive)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return http, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, errors.New("http directive must have a block")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Http) GetName() string {
 | 
			
		||||
	return "http"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Http) GetParameters() []string {
 | 
			
		||||
	return []string{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Http) GetDirectives() []IDirective {
 | 
			
		||||
	directives := make([]IDirective, 0)
 | 
			
		||||
	directives = append(directives, h.Directives...)
 | 
			
		||||
	for _, directive := range h.Servers {
 | 
			
		||||
		directives = append(directives, directive)
 | 
			
		||||
	}
 | 
			
		||||
	return directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Http) FindDirectives(directiveName string) []IDirective {
 | 
			
		||||
	directives := make([]IDirective, 0)
 | 
			
		||||
	for _, directive := range h.GetDirectives() {
 | 
			
		||||
		if directive.GetName() == directiveName {
 | 
			
		||||
			directives = append(directives, directive)
 | 
			
		||||
		}
 | 
			
		||||
		if directive.GetBlock() != nil {
 | 
			
		||||
			directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Http) UpdateDirectives(directiveName string, directive Directive) {
 | 
			
		||||
	directives := make([]IDirective, len(h.GetDirectives()))
 | 
			
		||||
	index := -1
 | 
			
		||||
	for i, dir := range h.GetDirectives() {
 | 
			
		||||
		if dir.GetName() == directiveName {
 | 
			
		||||
			index = i
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if index > -1 {
 | 
			
		||||
		directives[index] = &directive
 | 
			
		||||
	} else {
 | 
			
		||||
		directives = append(directives, &directive)
 | 
			
		||||
	}
 | 
			
		||||
	h.Directives = directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Http) AddDirectives(directive Directive) {
 | 
			
		||||
	directives := append(h.GetDirectives(), &directive)
 | 
			
		||||
	h.Directives = directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (h *Http) GetBlock() IBlock {
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								backend/utils/nginx/components/location.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								backend/utils/nginx/components/location.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
type Location struct {
 | 
			
		||||
	*Directive
 | 
			
		||||
	Modifier string
 | 
			
		||||
	Match    string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewLocation(directive *Directive) *Location {
 | 
			
		||||
	location := &Location{
 | 
			
		||||
		Modifier:  "",
 | 
			
		||||
		Match:     "",
 | 
			
		||||
		Directive: directive,
 | 
			
		||||
	}
 | 
			
		||||
	if directive.GetBlock() != nil {
 | 
			
		||||
		directive.Comment = directive.GetBlock().GetComment()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(directive.Parameters) == 0 {
 | 
			
		||||
		panic("no enough parameter for location")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(directive.Parameters) == 1 {
 | 
			
		||||
		location.Match = directive.Parameters[0]
 | 
			
		||||
		return location
 | 
			
		||||
	} else if len(directive.Parameters) == 2 {
 | 
			
		||||
		location.Modifier = directive.Parameters[0]
 | 
			
		||||
		location.Match = directive.Parameters[1]
 | 
			
		||||
		return location
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										107
									
								
								backend/utils/nginx/components/server.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								backend/utils/nginx/components/server.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,107 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Server struct {
 | 
			
		||||
	Comment    string
 | 
			
		||||
	Listens    []*ServerListen
 | 
			
		||||
	Directives []IDirective
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewServer(directive IDirective) (*Server, error) {
 | 
			
		||||
	server := &Server{}
 | 
			
		||||
	if block := directive.GetBlock(); block != nil {
 | 
			
		||||
		server.Comment = block.GetComment()
 | 
			
		||||
		directives := block.GetDirectives()
 | 
			
		||||
		for _, dir := range directives {
 | 
			
		||||
			if dir.GetName() == "listen" {
 | 
			
		||||
				server.Listens = append(server.Listens, NewServerListen(dir.GetParameters()))
 | 
			
		||||
			} else {
 | 
			
		||||
				server.Directives = append(server.Directives, dir)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return server, nil
 | 
			
		||||
	}
 | 
			
		||||
	return nil, errors.New("server directive must have a block")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) GetName() string {
 | 
			
		||||
	return "server"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) GetParameters() []string {
 | 
			
		||||
	return []string{}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) GetBlock() IBlock {
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) GetComment() string {
 | 
			
		||||
	return s.Comment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) GetDirectives() []IDirective {
 | 
			
		||||
	directives := make([]IDirective, 0)
 | 
			
		||||
	for _, ls := range s.Listens {
 | 
			
		||||
		directives = append(directives, ls)
 | 
			
		||||
	}
 | 
			
		||||
	directives = append(directives, s.Directives...)
 | 
			
		||||
	return directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) AddListen(bind string, defaultServer bool, params ...string) {
 | 
			
		||||
	listen := &ServerListen{
 | 
			
		||||
		Bind:       bind,
 | 
			
		||||
		Parameters: params,
 | 
			
		||||
	}
 | 
			
		||||
	if defaultServer {
 | 
			
		||||
		listen.DefaultServer = DefaultServer
 | 
			
		||||
	}
 | 
			
		||||
	s.Listens = append(s.Listens, listen)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) RemoveListenByBind(bind string) {
 | 
			
		||||
	index := 0
 | 
			
		||||
	listens := s.Listens
 | 
			
		||||
	for _, listen := range s.Listens {
 | 
			
		||||
		if listen.Bind != bind || len(listen.Parameters) > 0 {
 | 
			
		||||
			listens[index] = listen
 | 
			
		||||
			index++
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	s.Listens = listens
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) FindDirectives(directiveName string) []IDirective {
 | 
			
		||||
	directives := make([]IDirective, 0)
 | 
			
		||||
	for _, directive := range s.Directives {
 | 
			
		||||
		if directive.GetName() == directiveName {
 | 
			
		||||
			directives = append(directives, directive)
 | 
			
		||||
		}
 | 
			
		||||
		if directive.GetBlock() != nil {
 | 
			
		||||
			directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) UpdateDirectives(directiveName string, directive Directive) {
 | 
			
		||||
	directives := make([]IDirective, 0)
 | 
			
		||||
	for _, dir := range s.Directives {
 | 
			
		||||
		if dir.GetName() == directiveName {
 | 
			
		||||
			directives = append(directives, &directive)
 | 
			
		||||
		} else {
 | 
			
		||||
			directives = append(directives, dir)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	s.Directives = directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Server) AddDirectives(directive Directive) {
 | 
			
		||||
	directives := append(s.Directives, &directive)
 | 
			
		||||
	s.Directives = directives
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										68
									
								
								backend/utils/nginx/components/server_listen.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								backend/utils/nginx/components/server_listen.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,68 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/1Panel-dev/1Panel/backend/utils/common"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const DefaultServer = "default_server"
 | 
			
		||||
 | 
			
		||||
type ServerListen struct {
 | 
			
		||||
	Bind          string
 | 
			
		||||
	DefaultServer string
 | 
			
		||||
	Parameters    []string
 | 
			
		||||
	Comment       string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewServerListen(params []string) *ServerListen {
 | 
			
		||||
	server := &ServerListen{
 | 
			
		||||
		Parameters: []string{},
 | 
			
		||||
	}
 | 
			
		||||
	for _, param := range params {
 | 
			
		||||
		if isBind(param) {
 | 
			
		||||
			server.Bind = param
 | 
			
		||||
		} else if param == DefaultServer {
 | 
			
		||||
			server.DefaultServer = DefaultServer
 | 
			
		||||
		} else {
 | 
			
		||||
			server.Parameters = append(server.Parameters, param)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return server
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isBind(param string) bool {
 | 
			
		||||
	if common.IsNum(param) {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	if strings.Contains(param, "*") || strings.Contains(param, ":") || strings.Contains(param, ".") {
 | 
			
		||||
		return true
 | 
			
		||||
	}
 | 
			
		||||
	return false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sl *ServerListen) GetName() string {
 | 
			
		||||
	return "listen"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sl *ServerListen) GetBlock() IBlock {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sl *ServerListen) GetParameters() []string {
 | 
			
		||||
	params := []string{sl.Bind}
 | 
			
		||||
	params = append(params, sl.DefaultServer)
 | 
			
		||||
	params = append(params, sl.Parameters...)
 | 
			
		||||
	return params
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sl *ServerListen) GetComment() string {
 | 
			
		||||
	return sl.Comment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sl *ServerListen) AddDefaultServer() {
 | 
			
		||||
	sl.DefaultServer = DefaultServer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (sl *ServerListen) RemoveDefaultServe() {
 | 
			
		||||
	sl.DefaultServer = ""
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										24
									
								
								backend/utils/nginx/components/statement.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								backend/utils/nginx/components/statement.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,24 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
type IBlock interface {
 | 
			
		||||
	GetDirectives() []IDirective
 | 
			
		||||
	FindDirectives(directiveName string) []IDirective
 | 
			
		||||
	UpdateDirectives(directiveName string, directive Directive)
 | 
			
		||||
	AddDirectives(directive Directive)
 | 
			
		||||
	GetComment() string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type IDirective interface {
 | 
			
		||||
	GetName() string
 | 
			
		||||
	GetParameters() []string
 | 
			
		||||
	GetBlock() IBlock
 | 
			
		||||
	GetComment() string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type FileDirective interface {
 | 
			
		||||
	isFileDirective()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type IncludeDirective interface {
 | 
			
		||||
	FileDirective
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										94
									
								
								backend/utils/nginx/components/upstream.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								backend/utils/nginx/components/upstream.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,94 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Upstream struct {
 | 
			
		||||
	UpstreamName    string
 | 
			
		||||
	UpstreamServers []*UpstreamServer
 | 
			
		||||
	Directives      []IDirective
 | 
			
		||||
	Comment         string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (us *Upstream) GetName() string {
 | 
			
		||||
	return "upstream"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (us *Upstream) GetParameters() []string {
 | 
			
		||||
	return []string{us.UpstreamName}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (us *Upstream) GetBlock() IBlock {
 | 
			
		||||
	return us
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (us *Upstream) GetComment() string {
 | 
			
		||||
	return us.Comment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (us *Upstream) GetDirectives() []IDirective {
 | 
			
		||||
	directives := make([]IDirective, 0)
 | 
			
		||||
	directives = append(directives, us.Directives...)
 | 
			
		||||
	for _, uss := range us.UpstreamServers {
 | 
			
		||||
		directives = append(directives, uss)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUpstream(directive IDirective) (*Upstream, error) {
 | 
			
		||||
	parameters := directive.GetParameters()
 | 
			
		||||
	us := &Upstream{
 | 
			
		||||
		UpstreamName: parameters[0],
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if block := directive.GetBlock(); block != nil {
 | 
			
		||||
		us.Comment = block.GetComment()
 | 
			
		||||
		for _, d := range block.GetDirectives() {
 | 
			
		||||
			if d.GetName() == "server" {
 | 
			
		||||
				us.UpstreamServers = append(us.UpstreamServers, NewUpstreamServer(d))
 | 
			
		||||
			} else {
 | 
			
		||||
				us.Directives = append(us.Directives, d)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return us, nil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return nil, errors.New("missing upstream block")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (us *Upstream) AddServer(server *UpstreamServer) {
 | 
			
		||||
	us.UpstreamServers = append(us.UpstreamServers, server)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (us *Upstream) FindDirectives(directiveName string) []IDirective {
 | 
			
		||||
	directives := make([]IDirective, 0)
 | 
			
		||||
	for _, directive := range us.Directives {
 | 
			
		||||
		if directive.GetName() == directiveName {
 | 
			
		||||
			directives = append(directives, directive)
 | 
			
		||||
		}
 | 
			
		||||
		if directive.GetBlock() != nil {
 | 
			
		||||
			directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (us *Upstream) UpdateDirectives(directiveName string, directive Directive) {
 | 
			
		||||
	directives := make([]IDirective, 0)
 | 
			
		||||
	for _, dir := range us.GetDirectives() {
 | 
			
		||||
		if dir.GetName() == directiveName {
 | 
			
		||||
			directives = append(directives, &directive)
 | 
			
		||||
		} else {
 | 
			
		||||
			directives = append(directives, dir)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	us.Directives = directives
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (us *Upstream) AddDirectives(directive Directive) {
 | 
			
		||||
	directives := append(us.GetDirectives(), &directive)
 | 
			
		||||
	us.Directives = directives
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										77
									
								
								backend/utils/nginx/components/upstream_server.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								backend/utils/nginx/components/upstream_server.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,77 @@
 | 
			
		|||
package components
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type UpstreamServer struct {
 | 
			
		||||
	Comment    string
 | 
			
		||||
	Address    string
 | 
			
		||||
	Flags      []string
 | 
			
		||||
	Parameters map[string]string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (uss *UpstreamServer) GetName() string {
 | 
			
		||||
	return "server"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (uss *UpstreamServer) GetBlock() IBlock {
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (uss *UpstreamServer) GetParameters() []string {
 | 
			
		||||
	return uss.GetDirective().Parameters
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (uss *UpstreamServer) GetComment() string {
 | 
			
		||||
	return uss.Comment
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (uss *UpstreamServer) GetDirective() *Directive {
 | 
			
		||||
	directive := &Directive{
 | 
			
		||||
		Name:       "server",
 | 
			
		||||
		Parameters: make([]string, 0),
 | 
			
		||||
		Block:      nil,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	directive.Parameters = append(directive.Parameters, uss.Address)
 | 
			
		||||
 | 
			
		||||
	paramNames := make([]string, 0)
 | 
			
		||||
	for k := range uss.Parameters {
 | 
			
		||||
		paramNames = append(paramNames, k)
 | 
			
		||||
	}
 | 
			
		||||
	sort.Strings(paramNames)
 | 
			
		||||
 | 
			
		||||
	for _, k := range paramNames {
 | 
			
		||||
		directive.Parameters = append(directive.Parameters, fmt.Sprintf("%s=%s", k, uss.Parameters[k]))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	directive.Parameters = append(directive.Parameters, uss.Flags...)
 | 
			
		||||
 | 
			
		||||
	return directive
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewUpstreamServer(directive IDirective) *UpstreamServer {
 | 
			
		||||
	uss := &UpstreamServer{
 | 
			
		||||
		Comment:    directive.GetComment(),
 | 
			
		||||
		Flags:      make([]string, 0),
 | 
			
		||||
		Parameters: make(map[string]string, 0),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, parameter := range directive.GetParameters() {
 | 
			
		||||
		if i == 0 {
 | 
			
		||||
			uss.Address = parameter
 | 
			
		||||
			continue
 | 
			
		||||
		}
 | 
			
		||||
		if strings.Contains(parameter, "=") {
 | 
			
		||||
			s := strings.SplitN(parameter, "=", 2)
 | 
			
		||||
			uss.Parameters[s[0]] = s[1]
 | 
			
		||||
		} else {
 | 
			
		||||
			uss.Flags = append(uss.Flags, parameter)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return uss
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										132
									
								
								backend/utils/nginx/dumper.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								backend/utils/nginx/dumper.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,132 @@
 | 
			
		|||
package nginx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	components "github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"sort"
 | 
			
		||||
	"strings"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	//NoIndentStyle default style
 | 
			
		||||
	NoIndentStyle = &Style{
 | 
			
		||||
		SortDirectives: false,
 | 
			
		||||
		StartIndent:    0,
 | 
			
		||||
		Indent:         0,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//IndentedStyle default style
 | 
			
		||||
	IndentedStyle = &Style{
 | 
			
		||||
		SortDirectives: false,
 | 
			
		||||
		StartIndent:    0,
 | 
			
		||||
		Indent:         4,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//NoIndentSortedStyle default style
 | 
			
		||||
	NoIndentSortedStyle = &Style{
 | 
			
		||||
		SortDirectives: true,
 | 
			
		||||
		StartIndent:    0,
 | 
			
		||||
		Indent:         0,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//NoIndentSortedSpaceStyle default style
 | 
			
		||||
	NoIndentSortedSpaceStyle = &Style{
 | 
			
		||||
		SortDirectives:    true,
 | 
			
		||||
		SpaceBeforeBlocks: true,
 | 
			
		||||
		StartIndent:       0,
 | 
			
		||||
		Indent:            0,
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Style struct {
 | 
			
		||||
	SortDirectives    bool
 | 
			
		||||
	SpaceBeforeBlocks bool
 | 
			
		||||
	StartIndent       int
 | 
			
		||||
	Indent            int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewStyle() *Style {
 | 
			
		||||
	style := &Style{
 | 
			
		||||
		SortDirectives: false,
 | 
			
		||||
		StartIndent:    0,
 | 
			
		||||
		Indent:         4,
 | 
			
		||||
	}
 | 
			
		||||
	return style
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *Style) Iterate() *Style {
 | 
			
		||||
	newStyle := &Style{
 | 
			
		||||
		SortDirectives:    s.SortDirectives,
 | 
			
		||||
		SpaceBeforeBlocks: s.SpaceBeforeBlocks,
 | 
			
		||||
		StartIndent:       s.StartIndent + s.Indent,
 | 
			
		||||
		Indent:            s.Indent,
 | 
			
		||||
	}
 | 
			
		||||
	return newStyle
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DumpDirective(d components.IDirective, style *Style) string {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
 | 
			
		||||
	if style.SpaceBeforeBlocks && d.GetBlock() != nil {
 | 
			
		||||
		buf.WriteString("\n")
 | 
			
		||||
	}
 | 
			
		||||
	buf.WriteString(fmt.Sprintf("%s%s", strings.Repeat(" ", style.StartIndent), d.GetName()))
 | 
			
		||||
	if len(d.GetParameters()) > 0 {
 | 
			
		||||
		buf.WriteString(fmt.Sprintf(" %s", strings.Join(d.GetParameters(), " ")))
 | 
			
		||||
	}
 | 
			
		||||
	if d.GetBlock() == nil {
 | 
			
		||||
		if d.GetName() != "" {
 | 
			
		||||
			buf.WriteRune(';')
 | 
			
		||||
			buf.WriteString(" ")
 | 
			
		||||
		}
 | 
			
		||||
		if d.GetComment() != "" {
 | 
			
		||||
			buf.WriteString(d.GetComment())
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		buf.WriteString(" {")
 | 
			
		||||
		if d.GetComment() != "" {
 | 
			
		||||
			buf.WriteString(" ")
 | 
			
		||||
			buf.WriteString(d.GetComment())
 | 
			
		||||
		}
 | 
			
		||||
		buf.WriteString("\n")
 | 
			
		||||
		buf.WriteString(DumpBlock(d.GetBlock(), style.Iterate()))
 | 
			
		||||
		buf.WriteString(fmt.Sprintf("\n%s}", strings.Repeat(" ", style.StartIndent)))
 | 
			
		||||
	}
 | 
			
		||||
	return buf.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DumpBlock(b components.IBlock, style *Style) string {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
 | 
			
		||||
	directives := b.GetDirectives()
 | 
			
		||||
	if style.SortDirectives {
 | 
			
		||||
		sort.SliceStable(directives, func(i, j int) bool {
 | 
			
		||||
			return directives[i].GetName() < directives[j].GetName()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for i, directive := range directives {
 | 
			
		||||
		buf.WriteString(DumpDirective(directive, style))
 | 
			
		||||
		if i != len(directives)-1 {
 | 
			
		||||
			buf.WriteString("\n")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return buf.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func DumpConfig(c *components.Config, style *Style) string {
 | 
			
		||||
	return DumpBlock(c.Block, style)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func WriteConfig(c *components.Config, style *Style) error {
 | 
			
		||||
	dir, _ := filepath.Split(c.FilePath)
 | 
			
		||||
	err := os.MkdirAll(dir, 0755)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return ioutil.WriteFile(c.FilePath, []byte(DumpConfig(c, style)), 0644)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										14
									
								
								backend/utils/nginx/nginx.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								backend/utils/nginx/nginx.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
package nginx
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
 | 
			
		||||
	"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func GetConfig(path string) (*components.Config, error) {
 | 
			
		||||
	p, err := parser.NewParser(path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return p.Parse(), nil
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										82
									
								
								backend/utils/nginx/parser/flag/flag.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								backend/utils/nginx/parser/flag/flag.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,82 @@
 | 
			
		|||
package flag
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Type int
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	EOF Type = iota
 | 
			
		||||
	Eol
 | 
			
		||||
	Keyword
 | 
			
		||||
	QuotedString
 | 
			
		||||
	Variable
 | 
			
		||||
	BlockStart
 | 
			
		||||
	BlockEnd
 | 
			
		||||
	Semicolon
 | 
			
		||||
	Comment
 | 
			
		||||
	Illegal
 | 
			
		||||
	Regex
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	FlagName = map[Type]string{
 | 
			
		||||
		QuotedString: "QuotedString",
 | 
			
		||||
		EOF:          "Eof",
 | 
			
		||||
		Keyword:      "Keyword",
 | 
			
		||||
		Variable:     "Variable",
 | 
			
		||||
		BlockStart:   "BlockStart",
 | 
			
		||||
		BlockEnd:     "BlockEnd",
 | 
			
		||||
		Semicolon:    "Semicolon",
 | 
			
		||||
		Comment:      "Comment",
 | 
			
		||||
		Illegal:      "Illegal",
 | 
			
		||||
		Regex:        "Regex",
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (tt Type) String() string {
 | 
			
		||||
	return FlagName[tt]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Flag struct {
 | 
			
		||||
	Type    Type
 | 
			
		||||
	Literal string
 | 
			
		||||
	Line    int
 | 
			
		||||
	Column  int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t Flag) String() string {
 | 
			
		||||
	return fmt.Sprintf("{Type:%s,Literal:\"%s\",Line:%d,Column:%d}", t.Type, t.Literal, t.Line, t.Column)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t Flag) Lit(literal string) Flag {
 | 
			
		||||
	t.Literal = literal
 | 
			
		||||
	return t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t Flag) EqualTo(t2 Flag) bool {
 | 
			
		||||
	return t.Type == t2.Type && t.Literal == t2.Literal
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Flags []Flag
 | 
			
		||||
 | 
			
		||||
func (fs Flags) EqualTo(flags Flags) bool {
 | 
			
		||||
	if len(fs) != len(flags) {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	for i, t := range fs {
 | 
			
		||||
		if !t.EqualTo(flags[i]) {
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t Flag) Is(typ Type) bool {
 | 
			
		||||
	return t.Type == typ
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t Flag) IsParameterEligible() bool {
 | 
			
		||||
	return t.Is(Keyword) || t.Is(QuotedString) || t.Is(Variable) || t.Is(Regex)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										209
									
								
								backend/utils/nginx/parser/lexer.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										209
									
								
								backend/utils/nginx/parser/lexer.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,209 @@
 | 
			
		|||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser/flag"
 | 
			
		||||
	"io"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type lexer struct {
 | 
			
		||||
	reader *bufio.Reader
 | 
			
		||||
	file   string
 | 
			
		||||
	line   int
 | 
			
		||||
	column int
 | 
			
		||||
	Latest flag.Flag
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func lex(content string) *lexer {
 | 
			
		||||
	return newLexer(bytes.NewBuffer([]byte(content)))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newLexer(r io.Reader) *lexer {
 | 
			
		||||
	return &lexer{
 | 
			
		||||
		line:   1,
 | 
			
		||||
		reader: bufio.NewReader(r),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) scan() flag.Flag {
 | 
			
		||||
	s.Latest = s.getNextFlag()
 | 
			
		||||
	return s.Latest
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//func (s *lexer) all() flag.Flags {
 | 
			
		||||
//	tokens := make([]flag.Flag, 0)
 | 
			
		||||
//	for {
 | 
			
		||||
//		v := s.scan()
 | 
			
		||||
//		if v.Type == flag.EOF || v.Type == -1 {
 | 
			
		||||
//			break
 | 
			
		||||
//		}
 | 
			
		||||
//		tokens = append(tokens, v)
 | 
			
		||||
//	}
 | 
			
		||||
//	return tokens
 | 
			
		||||
//}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) getNextFlag() flag.Flag {
 | 
			
		||||
retoFlag:
 | 
			
		||||
	ch := s.peek()
 | 
			
		||||
	switch {
 | 
			
		||||
	case isSpace(ch):
 | 
			
		||||
		s.skipWhitespace()
 | 
			
		||||
		goto retoFlag
 | 
			
		||||
	case isEOF(ch):
 | 
			
		||||
		return s.NewToken(flag.EOF).Lit(string(s.read()))
 | 
			
		||||
	case ch == ';':
 | 
			
		||||
		return s.NewToken(flag.Semicolon).Lit(string(s.read()))
 | 
			
		||||
	case ch == '{':
 | 
			
		||||
		return s.NewToken(flag.BlockStart).Lit(string(s.read()))
 | 
			
		||||
	case ch == '}':
 | 
			
		||||
		return s.NewToken(flag.BlockEnd).Lit(string(s.read()))
 | 
			
		||||
	case ch == '#':
 | 
			
		||||
		return s.scanComment()
 | 
			
		||||
	case ch == '$':
 | 
			
		||||
		return s.scanVariable()
 | 
			
		||||
	case isQuote(ch):
 | 
			
		||||
		return s.scanQuotedString(ch)
 | 
			
		||||
	default:
 | 
			
		||||
		return s.scanKeyword()
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) peek() rune {
 | 
			
		||||
	r, _, _ := s.reader.ReadRune()
 | 
			
		||||
	_ = s.reader.UnreadRune()
 | 
			
		||||
	return r
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type runeCheck func(rune) bool
 | 
			
		||||
 | 
			
		||||
func (s *lexer) readUntil(until runeCheck) string {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	buf.WriteRune(s.read())
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		if ch := s.peek(); isEOF(ch) {
 | 
			
		||||
			break
 | 
			
		||||
		} else if until(ch) {
 | 
			
		||||
			break
 | 
			
		||||
		} else {
 | 
			
		||||
			buf.WriteRune(s.read())
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return buf.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) NewToken(tokenType flag.Type) flag.Flag {
 | 
			
		||||
	return flag.Flag{
 | 
			
		||||
		Type:   tokenType,
 | 
			
		||||
		Line:   s.line,
 | 
			
		||||
		Column: s.column,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) readWhile(while runeCheck) string {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	buf.WriteRune(s.read())
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		if ch := s.peek(); while(ch) {
 | 
			
		||||
			buf.WriteRune(s.read())
 | 
			
		||||
		} else {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return buf.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) skipWhitespace() {
 | 
			
		||||
	s.readWhile(isSpace)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) scanComment() flag.Flag {
 | 
			
		||||
	return s.NewToken(flag.Comment).Lit(s.readUntil(isEndOfLine))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) scanQuotedString(delimiter rune) flag.Flag {
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	tok := s.NewToken(flag.QuotedString)
 | 
			
		||||
	buf.WriteRune(s.read()) //consume delimiter
 | 
			
		||||
	for {
 | 
			
		||||
		ch := s.read()
 | 
			
		||||
 | 
			
		||||
		if ch == rune(flag.EOF) {
 | 
			
		||||
			panic("unexpected end of file while scanning a string, maybe an unclosed quote?")
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ch == '\\' {
 | 
			
		||||
			if needsEscape(s.peek(), delimiter) {
 | 
			
		||||
				switch s.read() {
 | 
			
		||||
				case 'n':
 | 
			
		||||
					buf.WriteRune('\n')
 | 
			
		||||
				case 'r':
 | 
			
		||||
					buf.WriteRune('\r')
 | 
			
		||||
				case 't':
 | 
			
		||||
					buf.WriteRune('\t')
 | 
			
		||||
				case '\\':
 | 
			
		||||
					buf.WriteRune('\\')
 | 
			
		||||
				case delimiter:
 | 
			
		||||
					buf.WriteRune(delimiter)
 | 
			
		||||
				}
 | 
			
		||||
				continue
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		buf.WriteRune(ch)
 | 
			
		||||
		if ch == delimiter {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return tok.Lit(buf.String())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) scanKeyword() flag.Flag {
 | 
			
		||||
	return s.NewToken(flag.Keyword).Lit(s.readUntil(isKeywordTerminator))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) scanVariable() flag.Flag {
 | 
			
		||||
	return s.NewToken(flag.Variable).Lit(s.readUntil(isKeywordTerminator))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *lexer) read() rune {
 | 
			
		||||
	ch, _, err := s.reader.ReadRune()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return rune(flag.EOF)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if ch == '\n' {
 | 
			
		||||
		s.column = 1
 | 
			
		||||
		s.line++
 | 
			
		||||
	} else {
 | 
			
		||||
		s.column++
 | 
			
		||||
	}
 | 
			
		||||
	return ch
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isQuote(ch rune) bool {
 | 
			
		||||
	return ch == '"' || ch == '\'' || ch == '`'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isKeywordTerminator(ch rune) bool {
 | 
			
		||||
	return isSpace(ch) || isEndOfLine(ch) || ch == '{' || ch == ';'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func needsEscape(ch, delimiter rune) bool {
 | 
			
		||||
	return ch == delimiter || ch == 'n' || ch == 't' || ch == '\\' || ch == 'r'
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isSpace(ch rune) bool {
 | 
			
		||||
	return ch == ' ' || ch == '\t' || isEndOfLine(ch)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isEOF(ch rune) bool {
 | 
			
		||||
	return ch == rune(flag.EOF)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func isEndOfLine(ch rune) bool {
 | 
			
		||||
	return ch == '\r' || ch == '\n'
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										172
									
								
								backend/utils/nginx/parser/parser.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								backend/utils/nginx/parser/parser.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,172 @@
 | 
			
		|||
package parser
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	components "github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
 | 
			
		||||
	"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser/flag"
 | 
			
		||||
	"os"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
type Parser struct {
 | 
			
		||||
	lexer             *lexer
 | 
			
		||||
	currentToken      flag.Flag
 | 
			
		||||
	followingToken    flag.Flag
 | 
			
		||||
	blockWrappers     map[string]func(*components.Directive) components.IDirective
 | 
			
		||||
	directiveWrappers map[string]func(*components.Directive) components.IDirective
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewStringParser(str string) *Parser {
 | 
			
		||||
	return NewParserFromLexer(lex(str))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewParser(filePath string) (*Parser, error) {
 | 
			
		||||
	f, err := os.Open(filePath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	l := newLexer(bufio.NewReader(f))
 | 
			
		||||
	l.file = filePath
 | 
			
		||||
	p := NewParserFromLexer(l)
 | 
			
		||||
	return p, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func NewParserFromLexer(lexer *lexer) *Parser {
 | 
			
		||||
	parser := &Parser{
 | 
			
		||||
		lexer: lexer,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	parser.nextToken()
 | 
			
		||||
	parser.nextToken()
 | 
			
		||||
 | 
			
		||||
	parser.blockWrappers = map[string]func(*components.Directive) components.IDirective{
 | 
			
		||||
		"http": func(directive *components.Directive) components.IDirective {
 | 
			
		||||
			return parser.wrapHttp(directive)
 | 
			
		||||
		},
 | 
			
		||||
		"server": func(directive *components.Directive) components.IDirective {
 | 
			
		||||
			return parser.wrapServer(directive)
 | 
			
		||||
		},
 | 
			
		||||
		"location": func(directive *components.Directive) components.IDirective {
 | 
			
		||||
			return parser.wrapLocation(directive)
 | 
			
		||||
		},
 | 
			
		||||
		"upstream": func(directive *components.Directive) components.IDirective {
 | 
			
		||||
			return parser.wrapUpstream(directive)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	parser.directiveWrappers = map[string]func(*components.Directive) components.IDirective{
 | 
			
		||||
		"server": func(directive *components.Directive) components.IDirective {
 | 
			
		||||
			return parser.parseUpstreamServer(directive)
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return parser
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) nextToken() {
 | 
			
		||||
	p.currentToken = p.followingToken
 | 
			
		||||
	p.followingToken = p.lexer.scan()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) curTokenIs(t flag.Type) bool {
 | 
			
		||||
	return p.currentToken.Type == t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) followingTokenIs(t flag.Type) bool {
 | 
			
		||||
	return p.followingToken.Type == t
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) Parse() *components.Config {
 | 
			
		||||
	return &components.Config{
 | 
			
		||||
		FilePath: p.lexer.file,
 | 
			
		||||
		Block:    p.parseBlock(),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) parseBlock() *components.Block {
 | 
			
		||||
 | 
			
		||||
	context := &components.Block{
 | 
			
		||||
		Comment:    "",
 | 
			
		||||
		Directives: make([]components.IDirective, 0),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
parsingloop:
 | 
			
		||||
	for {
 | 
			
		||||
		switch {
 | 
			
		||||
		case p.curTokenIs(flag.EOF) || p.curTokenIs(flag.BlockEnd):
 | 
			
		||||
			break parsingloop
 | 
			
		||||
		case p.curTokenIs(flag.Keyword):
 | 
			
		||||
			context.Directives = append(context.Directives, p.parseStatement())
 | 
			
		||||
		case p.curTokenIs(flag.Comment):
 | 
			
		||||
			context.Directives = append(context.Directives, &components.Comment{
 | 
			
		||||
				Detail: p.currentToken.Literal,
 | 
			
		||||
			})
 | 
			
		||||
		}
 | 
			
		||||
		p.nextToken()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return context
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) parseStatement() components.IDirective {
 | 
			
		||||
	d := &components.Directive{
 | 
			
		||||
		Name: p.currentToken.Literal,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for p.nextToken(); p.currentToken.IsParameterEligible(); p.nextToken() {
 | 
			
		||||
		d.Parameters = append(d.Parameters, p.currentToken.Literal)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if p.curTokenIs(flag.Semicolon) {
 | 
			
		||||
		if dw, ok := p.directiveWrappers[d.Name]; ok {
 | 
			
		||||
			return dw(d)
 | 
			
		||||
		}
 | 
			
		||||
		if p.followingTokenIs(flag.Comment) && p.currentToken.Line == p.followingToken.Line {
 | 
			
		||||
			d.Comment = p.followingToken.Literal
 | 
			
		||||
			p.nextToken()
 | 
			
		||||
		}
 | 
			
		||||
		return d
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if p.curTokenIs(flag.BlockStart) {
 | 
			
		||||
 | 
			
		||||
		inLineComment := ""
 | 
			
		||||
		if p.followingTokenIs(flag.Comment) && p.currentToken.Line == p.followingToken.Line {
 | 
			
		||||
			inLineComment = p.followingToken.Literal
 | 
			
		||||
			p.nextToken()
 | 
			
		||||
			p.nextToken()
 | 
			
		||||
		}
 | 
			
		||||
		block := p.parseBlock()
 | 
			
		||||
		block.Comment = inLineComment
 | 
			
		||||
		d.Block = block
 | 
			
		||||
		if bw, ok := p.blockWrappers[d.Name]; ok {
 | 
			
		||||
			return bw(d)
 | 
			
		||||
		}
 | 
			
		||||
		return d
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	panic(fmt.Errorf("unexpected token %s (%s) on line %d, column %d", p.currentToken.Type.String(), p.currentToken.Literal, p.currentToken.Line, p.currentToken.Column))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) wrapLocation(directive *components.Directive) *components.Location {
 | 
			
		||||
	return components.NewLocation(directive)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) wrapServer(directive *components.Directive) *components.Server {
 | 
			
		||||
	s, _ := components.NewServer(directive)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) wrapUpstream(directive *components.Directive) *components.Upstream {
 | 
			
		||||
	s, _ := components.NewUpstream(directive)
 | 
			
		||||
	return s
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) wrapHttp(directive *components.Directive) *components.Http {
 | 
			
		||||
	h, _ := components.NewHttp(directive)
 | 
			
		||||
	return h
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (p *Parser) parseUpstreamServer(directive *components.Directive) *components.UpstreamServer {
 | 
			
		||||
	return components.NewUpstreamServer(directive)
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	Add table
		
		Reference in a new issue