support notes for config

This commit is contained in:
yuzuki999 2023-08-20 22:24:57 +08:00
parent 0fce6588da
commit c3bb809c71
5 changed files with 170 additions and 35 deletions

View File

@ -2,6 +2,7 @@ package panel
import ( import (
"fmt" "fmt"
log "github.com/sirupsen/logrus"
"github.com/goccy/go-json" "github.com/goccy/go-json"
) )
@ -66,5 +67,6 @@ func (c *Client) ReportUserTraffic(userTraffic []UserTraffic) error {
if err != nil { if err != nil {
return err return err
} }
log.Println(r.String())
return nil return nil
} }

112
common/json5/json5.go Normal file
View File

@ -0,0 +1,112 @@
package json5
import (
"bytes"
"io"
)
type TrimNodeReader struct {
r io.Reader
br *bytes.Reader
}
func isNL(c byte) bool {
return c == '\n' || c == '\r'
}
func isWS(c byte) bool {
return c == ' ' || c == '\t' || isNL(c)
}
func consumeComment(s []byte, i int) int {
if i < len(s) && s[i] == '/' {
s[i-1] = ' '
for ; i < len(s) && !isNL(s[i]); i += 1 {
s[i] = ' '
}
}
if i < len(s) && s[i] == '*' {
s[i-1] = ' '
s[i] = ' '
for ; i < len(s); i += 1 {
if s[i] != '*' {
s[i] = ' '
} else {
s[i] = ' '
i++
if i < len(s) {
if s[i] == '/' {
s[i] = ' '
break
}
}
}
}
}
return i
}
func prep(r io.Reader) (s []byte, err error) {
buf := &bytes.Buffer{}
_, err = io.Copy(buf, r)
s = buf.Bytes()
if err != nil {
return
}
i := 0
for i < len(s) {
switch s[i] {
case '"':
i += 1
for i < len(s) {
if s[i] == '"' {
i += 1
break
} else if s[i] == '\\' {
i += 1
}
i += 1
}
case '/':
i = consumeComment(s, i+1)
case ',':
j := i
for {
i += 1
if i >= len(s) {
break
} else if s[i] == '}' || s[i] == ']' {
s[j] = ' '
break
} else if s[i] == '/' {
i = consumeComment(s, i+1)
} else if !isWS(s[i]) {
break
}
}
default:
i += 1
}
}
return
}
// Read acts as a proxy for the underlying reader and cleans p
// of comments and trailing commas preceeding ] and }
// comments are delimitted by // up until the end the line
func (st *TrimNodeReader) Read(p []byte) (n int, err error) {
if st.br == nil {
var s []byte
if s, err = prep(st.r); err != nil {
return
}
st.br = bytes.NewReader(s)
}
return st.br.Read(p)
}
// NewTrimNodeReader New returns an io.Reader acting as proxy to r
func NewTrimNodeReader(r io.Reader) io.Reader {
return &TrimNodeReader{r: r}
}

View File

@ -2,6 +2,7 @@ package conf
import ( import (
"fmt" "fmt"
"github.com/InazumaV/V2bX/common/json5"
"os" "os"
"github.com/goccy/go-json" "github.com/goccy/go-json"
@ -28,5 +29,5 @@ func (p *Conf) LoadFromPath(filePath string) error {
return fmt.Errorf("open config file error: %s", err) return fmt.Errorf("open config file error: %s", err)
} }
defer f.Close() defer f.Close()
return json.NewDecoder(f).Decode(p) return json.NewDecoder(json5.NewTrimNodeReader(f)).Decode(p)
} }

View File

@ -6,7 +6,7 @@ import (
func TestConf_LoadFromPath(t *testing.T) { func TestConf_LoadFromPath(t *testing.T) {
c := New() c := New()
t.Log(c.LoadFromPath("./config.json"), c.NodeConfig) t.Log(c.LoadFromPath("../example/config.json"), c.NodeConfig)
} }
func TestConf_Watch(t *testing.T) { func TestConf_Watch(t *testing.T) {

View File

@ -1,65 +1,85 @@
{ {
"Log": { "Log": {
// V2bX Core log
"Level": "error" "Level": "error"
}, },
"Cores": [ "Cores": [
{ {
"Type": "sing", "Type": "sing",
// Core
"Log": { "Log": {
// SingBox log
"Level": "error", "Level": "error",
"Timestamp": true "Timestamp": true
} }
},{ // More
},
{
"Type": "xray", "Type": "xray",
"Log": { "Log": {
// Xray-core log
"Level": "error" "Level": "error"
}, },
"DnsConfigPath": "", "DnsConfigPath": ""
... // More
} }
], ],
"Nodes": [ "Nodes": [
// Node
{ {
// 1
"Core": "sing", "Core": "sing",
// Core
"ApiHost": "http://127.0.0.1", "ApiHost": "http://127.0.0.1",
// API
"ApiKey": "test", "ApiKey": "test",
// APIToken
"NodeID": 33, "NodeID": 33,
// ID
"NodeType": "shadowsocks", "NodeType": "shadowsocks",
//
"Timeout": 30, "Timeout": 30,
//
"RuleListPath": "", "RuleListPath": "",
//
"ListenIP": "0.0.0.0", "ListenIP": "0.0.0.0",
// IP
"SendIP": "0.0.0.0", "SendIP": "0.0.0.0",
// IP
"EnableProxyProtocol": true, "EnableProxyProtocol": true,
"EnableTFO": true, // Proxy Protocol https://github.com/haproxy/haproxy/blob/master/doc/proxy-protocol.txt
... "EnableTFO": true
},{ // TCP Fast Open
"ApiConfig": { // More
"ApiHost": "http://127.0.0.1",
"ApiKey": "test",
"NodeID": 33,
"Timeout": 30,
"RuleListPath": ""
},
"Options": {
"Core": "sing",
"EnableProxyProtocol": true,
"EnableTFO": true,
...
}
},
{
"Core": "xray",
"ApiHost": "http://127.0.0.1",
"ApiKey": "test",
"NodeID": 33,
"NodeType": "shadowsocks",
"Timeout": 30,
"RuleListPath": "",
"ListenIP": "0.0.0.0",
"SendIP": "0.0.0.0",
"EnableProxyProtocol": true,
"EnableTFO": true,
...
} }
/*,
{
// 2
"ApiConfig": {
"ApiHost": "http://127.0.0.1",
"ApiKey": "test",
"NodeID": 33,
"Timeout": 30,
"RuleListPath": ""
},
"Options": {
"Core": "sing",
"EnableProxyProtocol": true,
"EnableTFO": true
}
},
{
"Core": "xray",
"ApiHost": "http://127.0.0.1",
"ApiKey": "test",
"NodeID": 33,
"NodeType": "shadowsocks",
"Timeout": 30,
"RuleListPath": "",
"ListenIP": "0.0.0.0",
"SendIP": "0.0.0.0",
"EnableProxyProtocol": true,
"EnableTFO": true
}*/
] ]
} }