mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-30 18:56:20 +08:00
feat: Nginx 配置支持 Lua 模块 (#3844)
This commit is contained in:
parent
4fc26a3061
commit
fb06e29aa3
15 changed files with 353 additions and 76 deletions
|
|
@ -37,7 +37,10 @@ func getNginxFull(website *model.Website) (dto.NginxFull, error) {
|
|||
if err != nil {
|
||||
return nginxFull, err
|
||||
}
|
||||
config := parser.NewStringParser(string(content)).Parse()
|
||||
config, err := parser.NewStringParser(string(content)).Parse()
|
||||
if err != nil {
|
||||
return dto.NginxFull{}, err
|
||||
}
|
||||
config.FilePath = nginxConfig.FilePath
|
||||
nginxConfig.OldContent = string(content)
|
||||
nginxConfig.Config = config
|
||||
|
|
@ -54,7 +57,10 @@ func getNginxFull(website *model.Website) (dto.NginxFull, error) {
|
|||
if err != nil {
|
||||
return nginxFull, err
|
||||
}
|
||||
siteConfig := parser.NewStringParser(string(siteNginxContent)).Parse()
|
||||
siteConfig, err := parser.NewStringParser(string(siteNginxContent)).Parse()
|
||||
if err != nil {
|
||||
return dto.NginxFull{}, err
|
||||
}
|
||||
siteConfig.FilePath = siteConfigPath
|
||||
siteNginxConfig.Config = siteConfig
|
||||
siteNginxConfig.OldContent = string(siteNginxContent)
|
||||
|
|
@ -156,15 +162,22 @@ func deleteNginxConfig(scope string, params []dto.NginxParam, website *model.Web
|
|||
}
|
||||
|
||||
func getNginxParamsFromStaticFile(scope dto.NginxKey, newParams []dto.NginxParam) []dto.NginxParam {
|
||||
newConfig := &components.Config{}
|
||||
var (
|
||||
newConfig = &components.Config{}
|
||||
err error
|
||||
)
|
||||
|
||||
updateScope := "in"
|
||||
switch scope {
|
||||
case dto.SSL:
|
||||
newConfig = parser.NewStringParser(string(nginx_conf.SSL)).Parse()
|
||||
newConfig, err = parser.NewStringParser(string(nginx_conf.SSL)).Parse()
|
||||
case dto.CACHE:
|
||||
newConfig = parser.NewStringParser(string(nginx_conf.Cache)).Parse()
|
||||
newConfig, err = parser.NewStringParser(string(nginx_conf.Cache)).Parse()
|
||||
case dto.ProxyCache:
|
||||
newConfig = parser.NewStringParser(string(nginx_conf.ProxyCache)).Parse()
|
||||
newConfig, err = parser.NewStringParser(string(nginx_conf.ProxyCache)).Parse()
|
||||
}
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
for _, dir := range newConfig.GetDirectives() {
|
||||
addParam := dto.NginxParam{
|
||||
|
|
|
|||
|
|
@ -1511,13 +1511,19 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
|
|||
|
||||
switch req.Operate {
|
||||
case "create":
|
||||
config = parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
||||
config, err = parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
case "edit":
|
||||
par, err = parser.NewParser(includePath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
config = par.Parse()
|
||||
config, err = par.Parse()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
oldContent, err = fileOp.GetContent(includePath)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -1533,6 +1539,7 @@ func (w WebsiteService) OperateProxy(req request.WebsiteProxyConfig) (err error)
|
|||
_ = fileOp.Rename(backPath, includePath)
|
||||
return updateNginxConfig(constant.NginxScopeServer, nil, &website)
|
||||
}
|
||||
|
||||
config.FilePath = includePath
|
||||
directives := config.Directives
|
||||
location, ok := directives[0].(*components.Location)
|
||||
|
|
@ -1610,7 +1617,10 @@ func (w WebsiteService) GetProxies(id uint) (res []request.WebsiteProxyConfig, e
|
|||
return
|
||||
}
|
||||
proxyConfig.Content = string(content)
|
||||
config = parser.NewStringParser(string(content)).Parse()
|
||||
config, err = parser.NewStringParser(string(content)).Parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
directives := config.GetDirectives()
|
||||
|
||||
location, ok := directives[0].(*components.Location)
|
||||
|
|
@ -2057,7 +2067,10 @@ func (w WebsiteService) OperateRedirect(req request.NginxRedirectReq) (err error
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
config = oldPar.Parse()
|
||||
config, err = oldPar.Parse()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
oldContent, err = fileOp.GetContent(includePath)
|
||||
if err != nil {
|
||||
return
|
||||
|
|
@ -2198,7 +2211,10 @@ func (w WebsiteService) GetRedirect(id uint) (res []response.NginxRedirectConfig
|
|||
return
|
||||
}
|
||||
redirectConfig.Content = string(content)
|
||||
config = parser.NewStringParser(string(content)).Parse()
|
||||
config, err = parser.NewStringParser(string(content)).Parse()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
dirs := config.GetDirectives()
|
||||
if len(dirs) > 0 {
|
||||
|
|
|
|||
|
|
@ -132,7 +132,10 @@ func createProxyFile(website *model.Website, runtime *model.Runtime) error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
config := parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
||||
config, err := parser.NewStringParser(string(nginx_conf.Proxy)).Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.FilePath = filePath
|
||||
directives := config.Directives
|
||||
location, ok := directives[0].(*components.Location)
|
||||
|
|
@ -208,7 +211,10 @@ func configDefaultNginx(website *model.Website, domains []model.WebsiteDomain, a
|
|||
nginxFileName := website.Alias + ".conf"
|
||||
configPath := path.Join(constant.AppInstallDir, constant.AppOpenresty, nginxInstall.Name, "conf", "conf.d", nginxFileName)
|
||||
nginxContent := string(nginx_conf.WebsiteDefault)
|
||||
config := parser.NewStringParser(nginxContent).Parse()
|
||||
config, err := parser.NewStringParser(nginxContent).Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
servers := config.FindServers()
|
||||
if len(servers) == 0 {
|
||||
return errors.New("nginx config is not valid")
|
||||
|
|
@ -872,7 +878,10 @@ func ChangeHSTSConfig(enable bool, nginxInstall model.AppInstall, website model.
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config := par.Parse()
|
||||
config, err := par.Parse()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.FilePath = path
|
||||
directives := config.Directives
|
||||
location, ok := directives[0].(*components.Location)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
package components
|
||||
|
||||
type Block struct {
|
||||
Line int
|
||||
Comment string
|
||||
Directives []IDirective
|
||||
Line int
|
||||
Comment string
|
||||
Directives []IDirective
|
||||
IsLuaBlock bool
|
||||
LiteralCode string
|
||||
}
|
||||
|
||||
func (b *Block) GetDirectives() []IDirective {
|
||||
|
|
@ -18,6 +20,10 @@ func (b *Block) GetLine() int {
|
|||
return b.Line
|
||||
}
|
||||
|
||||
func (b *Block) GetCodeBlock() string {
|
||||
return b.LiteralCode
|
||||
}
|
||||
|
||||
func (b *Block) FindDirectives(directiveName string) []IDirective {
|
||||
directives := make([]IDirective, 0)
|
||||
for _, directive := range b.GetDirectives() {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ type Http struct {
|
|||
Line int
|
||||
}
|
||||
|
||||
func (h *Http) GetCodeBlock() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (h *Http) GetComment() string {
|
||||
return h.Comment
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,10 @@ type Location struct {
|
|||
Replaces map[string]string
|
||||
}
|
||||
|
||||
func (l *Location) GetCodeBlock() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func NewLocation(directive IDirective) *Location {
|
||||
location := &Location{
|
||||
Modifier: "",
|
||||
|
|
|
|||
120
backend/utils/nginx/components/lua_block.go
Normal file
120
backend/utils/nginx/components/lua_block.go
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
package components
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type LuaBlock struct {
|
||||
Directives []IDirective
|
||||
Name string
|
||||
Comment string
|
||||
LuaCode string
|
||||
Line int
|
||||
}
|
||||
|
||||
func NewLuaBlock(directive IDirective) (*LuaBlock, error) {
|
||||
if block := directive.GetBlock(); block != nil {
|
||||
lb := &LuaBlock{
|
||||
Directives: []IDirective{},
|
||||
Name: directive.GetName(),
|
||||
LuaCode: block.GetCodeBlock(),
|
||||
}
|
||||
|
||||
lb.Directives = append(lb.Directives, block.GetDirectives()...)
|
||||
return lb, nil
|
||||
}
|
||||
return nil, fmt.Errorf("%s must have a block", directive.GetName())
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) GetName() string {
|
||||
return lb.Name
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) GetParameters() []string {
|
||||
return []string{}
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) GetDirectives() []IDirective {
|
||||
directives := make([]IDirective, 0)
|
||||
directives = append(directives, lb.Directives...)
|
||||
return directives
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) FindDirectives(directiveName string) []IDirective {
|
||||
directives := make([]IDirective, 0)
|
||||
for _, directive := range lb.GetDirectives() {
|
||||
if directive.GetName() == directiveName {
|
||||
directives = append(directives, directive)
|
||||
}
|
||||
if directive.GetBlock() != nil {
|
||||
directives = append(directives, directive.GetBlock().FindDirectives(directiveName)...)
|
||||
}
|
||||
}
|
||||
|
||||
return directives
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) GetCodeBlock() string {
|
||||
return lb.LuaCode
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) GetBlock() IBlock {
|
||||
return lb
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) GetComment() string {
|
||||
return lb.Comment
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) RemoveDirective(key string, params []string) {
|
||||
directives := lb.Directives
|
||||
var newDirectives []IDirective
|
||||
for _, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if len(params) > 0 {
|
||||
oldParams := dir.GetParameters()
|
||||
if oldParams[0] == params[0] {
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
newDirectives = append(newDirectives, dir)
|
||||
}
|
||||
lb.Directives = newDirectives
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) UpdateDirective(key string, params []string) {
|
||||
if key == "" || len(params) == 0 {
|
||||
return
|
||||
}
|
||||
directives := lb.Directives
|
||||
index := -1
|
||||
for i, dir := range directives {
|
||||
if dir.GetName() == key {
|
||||
if IsRepeatKey(key) {
|
||||
oldParams := dir.GetParameters()
|
||||
if !(len(oldParams) > 0 && oldParams[0] == params[0]) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
index = i
|
||||
break
|
||||
}
|
||||
}
|
||||
newDirective := &Directive{
|
||||
Name: key,
|
||||
Parameters: params,
|
||||
}
|
||||
if index > -1 {
|
||||
directives[index] = newDirective
|
||||
} else {
|
||||
directives = append(directives, newDirective)
|
||||
}
|
||||
lb.Directives = directives
|
||||
}
|
||||
|
||||
func (lb *LuaBlock) GetLine() int {
|
||||
return lb.Line
|
||||
}
|
||||
|
|
@ -11,6 +11,10 @@ type Server struct {
|
|||
Line int
|
||||
}
|
||||
|
||||
func (s *Server) GetCodeBlock() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func NewServer(directive IDirective) (*Server, error) {
|
||||
server := &Server{}
|
||||
if block := directive.GetBlock(); block != nil {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ type IBlock interface {
|
|||
UpdateDirective(name string, params []string)
|
||||
GetComment() string
|
||||
GetLine() int
|
||||
GetCodeBlock() string
|
||||
}
|
||||
|
||||
type IDirective interface {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,10 @@ type Upstream struct {
|
|||
Line int
|
||||
}
|
||||
|
||||
func (us *Upstream) GetCodeBlock() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (us *Upstream) GetName() string {
|
||||
return "upstream"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,6 +65,21 @@ func DumpDirective(d components.IDirective, style *Style) string {
|
|||
|
||||
func DumpBlock(b components.IBlock, style *Style, startLine int) string {
|
||||
var buf bytes.Buffer
|
||||
|
||||
if b.GetCodeBlock() != "" {
|
||||
luaLines := strings.Split(b.GetCodeBlock(), "\n")
|
||||
for i, line := range luaLines {
|
||||
if strings.Replace(line, " ", "", -1) == "" {
|
||||
continue
|
||||
}
|
||||
buf.WriteString(line)
|
||||
if i != len(luaLines)-1 {
|
||||
buf.WriteString("\n")
|
||||
}
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
line := startLine
|
||||
if b.GetLine() > startLine {
|
||||
for i := 0; i < b.GetLine()-startLine; i++ {
|
||||
|
|
|
|||
|
|
@ -10,5 +10,5 @@ func GetConfig(path string) (*components.Config, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.Parse(), nil
|
||||
return p.Parse()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ const (
|
|||
Comment
|
||||
Illegal
|
||||
Regex
|
||||
LuaCode
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
|||
|
|
@ -3,17 +3,18 @@ package parser
|
|||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser/flag"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type lexer struct {
|
||||
reader *bufio.Reader
|
||||
file string
|
||||
line int
|
||||
column int
|
||||
Latest flag.Flag
|
||||
reader *bufio.Reader
|
||||
file string
|
||||
line int
|
||||
column int
|
||||
inLuaBlock bool
|
||||
Latest flag.Flag
|
||||
}
|
||||
|
||||
func lex(content string) *lexer {
|
||||
|
|
@ -45,6 +46,11 @@ func (s *lexer) scan() flag.Flag {
|
|||
//}
|
||||
|
||||
func (s *lexer) getNextFlag() flag.Flag {
|
||||
if s.inLuaBlock {
|
||||
s.inLuaBlock = false
|
||||
flag := s.scanLuaCode()
|
||||
return flag
|
||||
}
|
||||
retoFlag:
|
||||
ch := s.peek()
|
||||
switch {
|
||||
|
|
@ -56,6 +62,9 @@ retoFlag:
|
|||
case ch == ';':
|
||||
return s.NewToken(flag.Semicolon).Lit(string(s.read()))
|
||||
case ch == '{':
|
||||
if isLuaBlock(s.Latest) {
|
||||
s.inLuaBlock = true
|
||||
}
|
||||
return s.NewToken(flag.BlockStart).Lit(string(s.read()))
|
||||
case ch == '}':
|
||||
return s.NewToken(flag.BlockEnd).Lit(string(s.read()))
|
||||
|
|
@ -70,6 +79,35 @@ retoFlag:
|
|||
}
|
||||
}
|
||||
|
||||
func (s *lexer) scanLuaCode() flag.Flag {
|
||||
ret := s.NewToken(flag.LuaCode)
|
||||
stack := make([]rune, 0, 50)
|
||||
code := strings.Builder{}
|
||||
|
||||
for {
|
||||
ch := s.read()
|
||||
if ch == rune(flag.EOF) {
|
||||
panic("unexpected end of file while scanning a string, maybe an unclosed lua code?")
|
||||
}
|
||||
if ch == '#' {
|
||||
code.WriteRune(ch)
|
||||
code.WriteString(s.readUntil(isEndOfLine))
|
||||
continue
|
||||
} else if ch == '}' {
|
||||
if len(stack) == 0 {
|
||||
_ = s.reader.UnreadRune()
|
||||
return ret.Lit(strings.TrimRight(strings.Trim(code.String(), "\n"), "\n "))
|
||||
}
|
||||
if stack[len(stack)-1] == '{' {
|
||||
stack = stack[0 : len(stack)-1]
|
||||
}
|
||||
} else if ch == '{' {
|
||||
stack = append(stack, ch)
|
||||
}
|
||||
code.WriteRune(ch)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *lexer) peek() rune {
|
||||
r, _, _ := s.reader.ReadRune()
|
||||
_ = s.reader.UnreadRune()
|
||||
|
|
@ -128,7 +166,7 @@ func (s *lexer) scanComment() flag.Flag {
|
|||
func (s *lexer) scanQuotedString(delimiter rune) flag.Flag {
|
||||
var buf bytes.Buffer
|
||||
tok := s.NewToken(flag.QuotedString)
|
||||
buf.WriteRune(s.read()) //consume delimiter
|
||||
_, _ = buf.WriteRune(s.read())
|
||||
for {
|
||||
ch := s.read()
|
||||
|
||||
|
|
@ -136,29 +174,13 @@ func (s *lexer) scanQuotedString(delimiter rune) flag.Flag {
|
|||
panic("unexpected end of file while scanning a string, maybe an unclosed quote?")
|
||||
}
|
||||
|
||||
if ch == '\\' {
|
||||
if needsEscape(s.peek(), delimiter) {
|
||||
nextch := s.read()
|
||||
switch nextch {
|
||||
case 'n':
|
||||
fmt.Println("n")
|
||||
buf.WriteRune('\n')
|
||||
case 'r':
|
||||
fmt.Println("r")
|
||||
buf.WriteRune('\r')
|
||||
case 't':
|
||||
fmt.Println("t")
|
||||
buf.WriteRune('\t')
|
||||
case '\\':
|
||||
buf.WriteRune('\\')
|
||||
default:
|
||||
buf.WriteRune('\\')
|
||||
buf.WriteRune(nextch)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if ch == '\\' && (s.peek() == delimiter) {
|
||||
buf.WriteRune(ch)
|
||||
buf.WriteRune(s.read())
|
||||
continue
|
||||
}
|
||||
buf.WriteRune(ch)
|
||||
|
||||
_, _ = buf.WriteRune(ch)
|
||||
if ch == delimiter {
|
||||
break
|
||||
}
|
||||
|
|
@ -168,7 +190,31 @@ func (s *lexer) scanQuotedString(delimiter rune) flag.Flag {
|
|||
}
|
||||
|
||||
func (s *lexer) scanKeyword() flag.Flag {
|
||||
return s.NewToken(flag.Keyword).Lit(s.readUntil(isKeywordTerminator))
|
||||
var buf bytes.Buffer
|
||||
tok := s.NewToken(flag.Keyword)
|
||||
prev := s.read()
|
||||
buf.WriteRune(prev)
|
||||
for {
|
||||
ch := s.peek()
|
||||
|
||||
if isSpace(ch) || isEOF(ch) || ch == ';' {
|
||||
break
|
||||
}
|
||||
|
||||
if ch == '{' {
|
||||
if prev == '$' {
|
||||
buf.WriteString(s.readUntil(func(r rune) bool {
|
||||
return r == '}'
|
||||
}))
|
||||
buf.WriteRune(s.read()) //consume latest '}'
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
buf.WriteRune(s.read())
|
||||
}
|
||||
|
||||
return tok.Lit(buf.String())
|
||||
}
|
||||
|
||||
func (s *lexer) scanVariable() flag.Flag {
|
||||
|
|
@ -198,10 +244,6 @@ 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)
|
||||
}
|
||||
|
|
@ -213,3 +255,7 @@ func isEOF(ch rune) bool {
|
|||
func isEndOfLine(ch rune) bool {
|
||||
return ch == '\r' || ch == '\n'
|
||||
}
|
||||
|
||||
func isLuaBlock(t flag.Flag) bool {
|
||||
return t.Type == flag.Keyword && strings.HasSuffix(t.Literal, "_by_lua_block")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,17 +2,19 @@ package parser
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
components "github.com/1Panel-dev/1Panel/backend/utils/nginx/components"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/nginx/parser/flag"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Parser struct {
|
||||
lexer *lexer
|
||||
currentToken flag.Flag
|
||||
followingToken flag.Flag
|
||||
blockWrappers map[string]func(*components.Directive) components.IDirective
|
||||
blockWrappers map[string]func(*components.Directive) (components.IDirective, error)
|
||||
directiveWrappers map[string]func(*components.Directive) components.IDirective
|
||||
}
|
||||
|
||||
|
|
@ -39,18 +41,21 @@ func NewParserFromLexer(lexer *lexer) *Parser {
|
|||
parser.nextToken()
|
||||
parser.nextToken()
|
||||
|
||||
parser.blockWrappers = map[string]func(*components.Directive) components.IDirective{
|
||||
"http": func(directive *components.Directive) components.IDirective {
|
||||
return parser.wrapHttp(directive)
|
||||
parser.blockWrappers = map[string]func(*components.Directive) (components.IDirective, error){
|
||||
"http": func(directive *components.Directive) (components.IDirective, error) {
|
||||
return parser.wrapHttp(directive), nil
|
||||
},
|
||||
"server": func(directive *components.Directive) components.IDirective {
|
||||
return parser.wrapServer(directive)
|
||||
"server": func(directive *components.Directive) (components.IDirective, error) {
|
||||
return parser.wrapServer(directive), nil
|
||||
},
|
||||
"location": func(directive *components.Directive) components.IDirective {
|
||||
return parser.wrapLocation(directive)
|
||||
"location": func(directive *components.Directive) (components.IDirective, error) {
|
||||
return parser.wrapLocation(directive), nil
|
||||
},
|
||||
"upstream": func(directive *components.Directive) components.IDirective {
|
||||
return parser.wrapUpstream(directive)
|
||||
"upstream": func(directive *components.Directive) (components.IDirective, error) {
|
||||
return parser.wrapUpstream(directive), nil
|
||||
},
|
||||
"_by_lua_block": func(directive *components.Directive) (components.IDirective, error) {
|
||||
return parser.wrapLuaBlock(directive)
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -76,14 +81,19 @@ 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) Parse() (*components.Config, error) {
|
||||
parsedBlock, err := p.parseBlock(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := &components.Config{
|
||||
FilePath: p.lexer.file,
|
||||
Block: parsedBlock,
|
||||
}
|
||||
return c, err
|
||||
}
|
||||
|
||||
func (p *Parser) parseBlock() *components.Block {
|
||||
func (p *Parser) parseBlock(inBlock bool) (*components.Block, error) {
|
||||
context := &components.Block{
|
||||
Comment: "",
|
||||
Directives: make([]components.IDirective, 0),
|
||||
|
|
@ -93,10 +103,22 @@ func (p *Parser) parseBlock() *components.Block {
|
|||
parsingloop:
|
||||
for {
|
||||
switch {
|
||||
case p.curTokenIs(flag.EOF) || p.curTokenIs(flag.BlockEnd):
|
||||
case p.curTokenIs(flag.EOF):
|
||||
if inBlock {
|
||||
return nil, errors.New("unexpected eof in block")
|
||||
}
|
||||
break parsingloop
|
||||
case p.curTokenIs(flag.BlockEnd):
|
||||
break parsingloop
|
||||
case p.curTokenIs(flag.LuaCode):
|
||||
context.IsLuaBlock = true
|
||||
context.LiteralCode = p.currentToken.Literal
|
||||
case p.curTokenIs(flag.Keyword):
|
||||
context.Directives = append(context.Directives, p.parseStatement())
|
||||
s, err := p.parseStatement()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
context.Directives = append(context.Directives, s)
|
||||
case p.curTokenIs(flag.Comment):
|
||||
context.Directives = append(context.Directives, &components.Comment{
|
||||
Detail: p.currentToken.Literal,
|
||||
|
|
@ -106,10 +128,10 @@ parsingloop:
|
|||
p.nextToken()
|
||||
}
|
||||
|
||||
return context
|
||||
return context, nil
|
||||
}
|
||||
|
||||
func (p *Parser) parseStatement() components.IDirective {
|
||||
func (p *Parser) parseStatement() (components.IDirective, error) {
|
||||
d := &components.Directive{
|
||||
Name: p.currentToken.Literal,
|
||||
Line: p.currentToken.Line,
|
||||
|
|
@ -121,30 +143,38 @@ func (p *Parser) parseStatement() components.IDirective {
|
|||
|
||||
if p.curTokenIs(flag.Semicolon) {
|
||||
if dw, ok := p.directiveWrappers[d.Name]; ok {
|
||||
return dw(d)
|
||||
return dw(d), nil
|
||||
}
|
||||
if p.followingTokenIs(flag.Comment) && p.currentToken.Line == p.followingToken.Line {
|
||||
d.Comment = p.followingToken.Literal
|
||||
p.nextToken()
|
||||
}
|
||||
return d
|
||||
return d, nil
|
||||
}
|
||||
|
||||
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, err := p.parseBlock(false)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
block.Comment = inLineComment
|
||||
d.Block = block
|
||||
|
||||
if strings.HasSuffix(d.Name, "_by_lua_block") {
|
||||
return p.blockWrappers["_by_lua_block"](d)
|
||||
}
|
||||
|
||||
if bw, ok := p.blockWrappers[d.Name]; ok {
|
||||
return bw(d)
|
||||
}
|
||||
return d
|
||||
return d, nil
|
||||
}
|
||||
|
||||
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))
|
||||
|
|
@ -169,6 +199,10 @@ func (p *Parser) wrapHttp(directive *components.Directive) *components.Http {
|
|||
return h
|
||||
}
|
||||
|
||||
func (p *Parser) wrapLuaBlock(directive *components.Directive) (*components.LuaBlock, error) {
|
||||
return components.NewLuaBlock(directive)
|
||||
}
|
||||
|
||||
func (p *Parser) parseUpstreamServer(directive *components.Directive) *components.UpstreamServer {
|
||||
return components.NewUpstreamServer(directive)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue