mirror of
https://github.com/daeuniverse/dae.git
synced 2025-01-03 13:31:00 +07:00
241 lines
5.0 KiB
Go
241 lines
5.0 KiB
Go
/*
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
* Copyright (c) 2022-2024, daeuniverse Organization <dae@v2raya.org>
|
|
*/
|
|
|
|
package config_parser
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type ItemType int
|
|
|
|
const (
|
|
ItemType_RoutingRule ItemType = iota
|
|
ItemType_Param
|
|
ItemType_Section
|
|
)
|
|
|
|
func (t ItemType) String() string {
|
|
switch t {
|
|
case ItemType_RoutingRule:
|
|
return "RoutingRule"
|
|
case ItemType_Param:
|
|
return "Param"
|
|
case ItemType_Section:
|
|
return "Section"
|
|
default:
|
|
return "<Unknown>"
|
|
}
|
|
}
|
|
|
|
func NewRoutingRuleItem(rule *RoutingRule) *Item {
|
|
return &Item{
|
|
Type: ItemType_RoutingRule,
|
|
Value: rule,
|
|
}
|
|
}
|
|
|
|
func NewParamItem(param *Param) *Item {
|
|
return &Item{
|
|
Type: ItemType_Param,
|
|
Value: param,
|
|
}
|
|
}
|
|
|
|
func NewSectionItem(section *Section) *Item {
|
|
return &Item{
|
|
Type: ItemType_Param,
|
|
Value: section,
|
|
}
|
|
}
|
|
|
|
type Item struct {
|
|
Type ItemType
|
|
Value interface{}
|
|
}
|
|
|
|
func (i *Item) String(compact bool, quoteVal bool) string {
|
|
var builder strings.Builder
|
|
builder.WriteString("type: " + i.Type.String() + "\n")
|
|
var content string
|
|
switch val := i.Value.(type) {
|
|
case *RoutingRule:
|
|
content = val.String(false, compact, quoteVal)
|
|
case *Param:
|
|
content = val.String(false, quoteVal)
|
|
case *Section:
|
|
content = val.String(compact, quoteVal)
|
|
default:
|
|
return "<Unknown>\n"
|
|
}
|
|
lines := strings.Split(content, "\n")
|
|
for i := range lines {
|
|
lines[i] = "\t" + lines[i]
|
|
}
|
|
builder.WriteString(strings.Join(lines, "\n"))
|
|
return builder.String()
|
|
}
|
|
|
|
type Section struct {
|
|
Name string
|
|
Items []*Item
|
|
}
|
|
|
|
func (s *Section) String(compact bool, quoteVal bool) string {
|
|
var builder strings.Builder
|
|
builder.WriteString("section: " + s.Name + "\n")
|
|
var strItemList []string
|
|
for _, item := range s.Items {
|
|
lines := strings.Split(item.String(compact, quoteVal), "\n")
|
|
for i := range lines {
|
|
lines[i] = "\t" + lines[i]
|
|
}
|
|
strItemList = append(strItemList, strings.Join(lines, "\n"))
|
|
}
|
|
builder.WriteString(strings.Join(strItemList, "\n"))
|
|
return builder.String()
|
|
}
|
|
|
|
type Param struct {
|
|
// Key may be empty.
|
|
Key string
|
|
|
|
// Either Val or AndFunctions is empty.
|
|
Val string
|
|
AndFunctions []*Function
|
|
|
|
// Annotation is optional
|
|
Annotation []*Param
|
|
}
|
|
|
|
func (p *Param) String(compact bool, quoteVal bool) string {
|
|
// FIXME: annotation
|
|
var quote func(string) string
|
|
if quoteVal {
|
|
quote = strconv.Quote
|
|
} else {
|
|
quote = func(s string) string { return s }
|
|
}
|
|
if p.Key == "" {
|
|
return quote(p.Val)
|
|
}
|
|
if p.AndFunctions != nil {
|
|
a := paramAndFunctions{
|
|
Key: p.Key,
|
|
AndFunctions: p.AndFunctions,
|
|
}
|
|
return a.String(compact, quoteVal)
|
|
}
|
|
if compact {
|
|
return p.Key + ":" + quote(p.Val)
|
|
} else {
|
|
return p.Key + ": " + quote(p.Val)
|
|
}
|
|
}
|
|
|
|
type Function struct {
|
|
Name string
|
|
Not bool
|
|
Params []*Param
|
|
}
|
|
|
|
func (f *Function) String(compact bool, quoteVal bool, omitEmpty bool) string {
|
|
var builder strings.Builder
|
|
if f.Not {
|
|
builder.WriteString("!")
|
|
}
|
|
builder.WriteString(f.Name)
|
|
if !(omitEmpty && len(f.Params) == 0) {
|
|
builder.WriteString("(")
|
|
var strParamList []string
|
|
for i, p := range f.Params {
|
|
if i >= 5 {
|
|
strParamList = append(strParamList, "...")
|
|
break
|
|
}
|
|
strParamList = append(strParamList, p.String(compact, quoteVal))
|
|
}
|
|
if compact {
|
|
builder.WriteString(strings.Join(strParamList, ","))
|
|
} else {
|
|
builder.WriteString(strings.Join(strParamList, ", "))
|
|
}
|
|
builder.WriteString(")")
|
|
}
|
|
return builder.String()
|
|
}
|
|
|
|
type paramAndFunctions struct {
|
|
Key string
|
|
AndFunctions []*Function
|
|
}
|
|
|
|
func (p *paramAndFunctions) String(compact bool, quoteVal bool) string {
|
|
var builder strings.Builder
|
|
if compact {
|
|
builder.WriteString(p.Key + ":")
|
|
} else {
|
|
builder.WriteString(p.Key + ": ")
|
|
}
|
|
var strFunctionList []string
|
|
for _, f := range p.AndFunctions {
|
|
strFunctionList = append(strFunctionList, f.String(compact, quoteVal, false))
|
|
}
|
|
if compact {
|
|
builder.WriteString(strings.Join(strFunctionList, "&&"))
|
|
} else {
|
|
builder.WriteString(strings.Join(strFunctionList, " && "))
|
|
}
|
|
return builder.String()
|
|
}
|
|
|
|
type RoutingRule struct {
|
|
AndFunctions []*Function
|
|
Outbound Function
|
|
}
|
|
|
|
func (r *RoutingRule) String(replaceParamWithN bool, compact bool, quoteVal bool) string {
|
|
var builder strings.Builder
|
|
var n int
|
|
for i, f := range r.AndFunctions {
|
|
if i != 0 {
|
|
if compact {
|
|
builder.WriteString("&&")
|
|
} else {
|
|
builder.WriteString(" && ")
|
|
}
|
|
}
|
|
var paramBuilder strings.Builder
|
|
n = len(f.Params)
|
|
if replaceParamWithN {
|
|
paramBuilder.WriteString("[n = " + strconv.Itoa(n) + "]")
|
|
} else {
|
|
for j, param := range f.Params {
|
|
if j != 0 {
|
|
if compact {
|
|
paramBuilder.WriteString(",")
|
|
} else {
|
|
paramBuilder.WriteString(", ")
|
|
}
|
|
}
|
|
paramBuilder.WriteString(param.String(compact, quoteVal))
|
|
}
|
|
}
|
|
symNot := ""
|
|
if f.Not {
|
|
symNot = "!"
|
|
}
|
|
builder.WriteString(fmt.Sprintf("%v%v(%v)", symNot, f.Name, paramBuilder.String()))
|
|
}
|
|
if compact {
|
|
builder.WriteString("->" + r.Outbound.String(compact, quoteVal, true))
|
|
} else {
|
|
builder.WriteString(" -> " + r.Outbound.String(compact, quoteVal, true))
|
|
}
|
|
return builder.String()
|
|
}
|