mirror of
https://github.com/wyx2685/V2bX.git
synced 2025-01-22 09:58:14 -05:00
support notes for config
This commit is contained in:
parent
0fce6588da
commit
c3bb809c71
@ -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
112
common/json5/json5.go
Normal 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}
|
||||||
|
}
|
@ -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)
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
@ -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",
|
||||||
|
// API密钥,即Token
|
||||||
"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
|
||||||
|
}*/
|
||||||
]
|
]
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user