mirror of
https://github.com/SagerNet/sing-box.git
synced 2024-11-23 17:11:29 +00:00
Migrate contentjson and badjson to library &
Add omitempty in format
This commit is contained in:
parent
3041f34dfa
commit
80cc0cd5db
|
@ -5,9 +5,10 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -37,6 +38,10 @@ func format() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, optionsEntry := range optionsList {
|
for _, optionsEntry := range optionsList {
|
||||||
|
optionsEntry.options, err = badjson.Omitempty(optionsEntry.options)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
encoder := json.NewEncoder(buffer)
|
encoder := json.NewEncoder(buffer)
|
||||||
encoder.SetIndent("", " ")
|
encoder.SetIndent("", " ")
|
||||||
|
|
|
@ -6,11 +6,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
|
|
||||||
"github.com/oschwald/maxminddb-golang"
|
"github.com/oschwald/maxminddb-golang"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
"github.com/sagernet/sing/common/rw"
|
"github.com/sagernet/sing/common/rw"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
|
@ -5,10 +5,10 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/common/srs"
|
"github.com/sagernet/sing-box/common/srs"
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,10 +6,10 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
|
@ -13,10 +13,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box"
|
"github.com/sagernet/sing-box"
|
||||||
"github.com/sagernet/sing-box/common/badjsonmerge"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
@ -108,7 +108,7 @@ func readConfigAndMerge() (option.Options, error) {
|
||||||
}
|
}
|
||||||
var mergedOptions option.Options
|
var mergedOptions option.Options
|
||||||
for _, options := range optionsList {
|
for _, options := range optionsList {
|
||||||
mergedOptions, err = badjsonmerge.MergeOptions(options.options, mergedOptions)
|
mergedOptions, err = badjson.Merge(options.options, mergedOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return option.Options{}, E.Cause(err, "merge config at ", options.path)
|
return option.Options{}, E.Cause(err, "merge config at ", options.path)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package badjson
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JSONArray []any
|
|
||||||
|
|
||||||
func (a JSONArray) MarshalJSON() ([]byte, error) {
|
|
||||||
return json.Marshal([]any(a))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *JSONArray) UnmarshalJSON(content []byte) error {
|
|
||||||
decoder := json.NewDecoder(bytes.NewReader(content))
|
|
||||||
arrayStart, err := decoder.Token()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if arrayStart != json.Delim('[') {
|
|
||||||
return E.New("excepted array start, but got ", arrayStart)
|
|
||||||
}
|
|
||||||
err = a.decodeJSON(decoder)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
arrayEnd, err := decoder.Token()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if arrayEnd != json.Delim(']') {
|
|
||||||
return E.New("excepted array end, but got ", arrayEnd)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *JSONArray) decodeJSON(decoder *json.Decoder) error {
|
|
||||||
for decoder.More() {
|
|
||||||
item, err := decodeJSON(decoder)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
*a = append(*a, item)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,54 +0,0 @@
|
||||||
package badjson
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Decode(content []byte) (any, error) {
|
|
||||||
decoder := json.NewDecoder(bytes.NewReader(content))
|
|
||||||
return decodeJSON(decoder)
|
|
||||||
}
|
|
||||||
|
|
||||||
func decodeJSON(decoder *json.Decoder) (any, error) {
|
|
||||||
rawToken, err := decoder.Token()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
switch token := rawToken.(type) {
|
|
||||||
case json.Delim:
|
|
||||||
switch token {
|
|
||||||
case '{':
|
|
||||||
var object JSONObject
|
|
||||||
err = object.decodeJSON(decoder)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rawToken, err = decoder.Token()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if rawToken != json.Delim('}') {
|
|
||||||
return nil, E.New("excepted object end, but got ", rawToken)
|
|
||||||
}
|
|
||||||
return &object, nil
|
|
||||||
case '[':
|
|
||||||
var array JSONArray
|
|
||||||
err = array.decodeJSON(decoder)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
rawToken, err = decoder.Token()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
} else if rawToken != json.Delim(']') {
|
|
||||||
return nil, E.New("excepted array end, but got ", rawToken)
|
|
||||||
}
|
|
||||||
return array, nil
|
|
||||||
default:
|
|
||||||
return nil, E.New("excepted object or array end: ", token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return rawToken, nil
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
package badjson
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
"github.com/sagernet/sing/common/x/linkedhashmap"
|
|
||||||
)
|
|
||||||
|
|
||||||
type JSONObject struct {
|
|
||||||
linkedhashmap.Map[string, any]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m JSONObject) MarshalJSON() ([]byte, error) {
|
|
||||||
buffer := new(bytes.Buffer)
|
|
||||||
buffer.WriteString("{")
|
|
||||||
items := m.Entries()
|
|
||||||
iLen := len(items)
|
|
||||||
for i, entry := range items {
|
|
||||||
keyContent, err := json.Marshal(entry.Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
buffer.WriteString(strings.TrimSpace(string(keyContent)))
|
|
||||||
buffer.WriteString(": ")
|
|
||||||
valueContent, err := json.Marshal(entry.Value)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
buffer.WriteString(strings.TrimSpace(string(valueContent)))
|
|
||||||
if i < iLen-1 {
|
|
||||||
buffer.WriteString(", ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buffer.WriteString("}")
|
|
||||||
return buffer.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *JSONObject) UnmarshalJSON(content []byte) error {
|
|
||||||
decoder := json.NewDecoder(bytes.NewReader(content))
|
|
||||||
m.Clear()
|
|
||||||
objectStart, err := decoder.Token()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if objectStart != json.Delim('{') {
|
|
||||||
return E.New("expected json object start, but starts with ", objectStart)
|
|
||||||
}
|
|
||||||
err = m.decodeJSON(decoder)
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "decode json object content")
|
|
||||||
}
|
|
||||||
objectEnd, err := decoder.Token()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else if objectEnd != json.Delim('}') {
|
|
||||||
return E.New("expected json object end, but ends with ", objectEnd)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *JSONObject) decodeJSON(decoder *json.Decoder) error {
|
|
||||||
for decoder.More() {
|
|
||||||
var entryKey string
|
|
||||||
keyToken, err := decoder.Token()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
entryKey = keyToken.(string)
|
|
||||||
var entryValue any
|
|
||||||
entryValue, err = decodeJSON(decoder)
|
|
||||||
if err != nil {
|
|
||||||
return E.Cause(err, "decode value for ", entryKey)
|
|
||||||
}
|
|
||||||
m.Put(entryKey, entryValue)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
package badjsonmerge
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/badjson"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
|
||||||
)
|
|
||||||
|
|
||||||
func MergeOptions(source option.Options, destination option.Options) (option.Options, error) {
|
|
||||||
rawSource, err := json.Marshal(source)
|
|
||||||
if err != nil {
|
|
||||||
return option.Options{}, E.Cause(err, "marshal source")
|
|
||||||
}
|
|
||||||
rawDestination, err := json.Marshal(destination)
|
|
||||||
if err != nil {
|
|
||||||
return option.Options{}, E.Cause(err, "marshal destination")
|
|
||||||
}
|
|
||||||
rawMerged, err := MergeJSON(rawSource, rawDestination)
|
|
||||||
if err != nil {
|
|
||||||
return option.Options{}, E.Cause(err, "merge options")
|
|
||||||
}
|
|
||||||
var merged option.Options
|
|
||||||
err = json.Unmarshal(rawMerged, &merged)
|
|
||||||
if err != nil {
|
|
||||||
return option.Options{}, E.Cause(err, "unmarshal merged options")
|
|
||||||
}
|
|
||||||
return merged, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func MergeJSON(rawSource json.RawMessage, rawDestination json.RawMessage) (json.RawMessage, error) {
|
|
||||||
source, err := badjson.Decode(rawSource)
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "decode source")
|
|
||||||
}
|
|
||||||
destination, err := badjson.Decode(rawDestination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "decode destination")
|
|
||||||
}
|
|
||||||
merged, err := mergeJSON(source, destination)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return json.Marshal(merged)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mergeJSON(anySource any, anyDestination any) (any, error) {
|
|
||||||
switch destination := anyDestination.(type) {
|
|
||||||
case badjson.JSONArray:
|
|
||||||
switch source := anySource.(type) {
|
|
||||||
case badjson.JSONArray:
|
|
||||||
destination = append(destination, source...)
|
|
||||||
default:
|
|
||||||
destination = append(destination, source)
|
|
||||||
}
|
|
||||||
return destination, nil
|
|
||||||
case *badjson.JSONObject:
|
|
||||||
switch source := anySource.(type) {
|
|
||||||
case *badjson.JSONObject:
|
|
||||||
for _, entry := range source.Entries() {
|
|
||||||
oldValue, loaded := destination.Get(entry.Key)
|
|
||||||
if loaded {
|
|
||||||
var err error
|
|
||||||
entry.Value, err = mergeJSON(entry.Value, oldValue)
|
|
||||||
if err != nil {
|
|
||||||
return nil, E.Cause(err, "merge object item ", entry.Key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
destination.Put(entry.Key, entry.Value)
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return nil, E.New("cannot merge json object into ", reflect.TypeOf(destination))
|
|
||||||
}
|
|
||||||
return destination, nil
|
|
||||||
default:
|
|
||||||
return destination, nil
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
package badjsonmerge
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
|
||||||
"github.com/sagernet/sing-box/option"
|
|
||||||
N "github.com/sagernet/sing/common/network"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestMergeJSON(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
options := option.Options{
|
|
||||||
Log: &option.LogOptions{
|
|
||||||
Level: "info",
|
|
||||||
},
|
|
||||||
Route: &option.RouteOptions{
|
|
||||||
Rules: []option.Rule{
|
|
||||||
{
|
|
||||||
Type: C.RuleTypeDefault,
|
|
||||||
DefaultOptions: option.DefaultRule{
|
|
||||||
Network: []string{N.NetworkTCP},
|
|
||||||
Outbound: "direct",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
anotherOptions := option.Options{
|
|
||||||
Outbounds: []option.Outbound{
|
|
||||||
{
|
|
||||||
Type: C.TypeDirect,
|
|
||||||
Tag: "direct",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
thirdOptions := option.Options{
|
|
||||||
Route: &option.RouteOptions{
|
|
||||||
Rules: []option.Rule{
|
|
||||||
{
|
|
||||||
Type: C.RuleTypeDefault,
|
|
||||||
DefaultOptions: option.DefaultRule{
|
|
||||||
Network: []string{N.NetworkUDP},
|
|
||||||
Outbound: "direct",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
mergeOptions, err := MergeOptions(options, anotherOptions)
|
|
||||||
require.NoError(t, err)
|
|
||||||
mergeOptions, err = MergeOptions(thirdOptions, mergeOptions)
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, "info", mergeOptions.Log.Level)
|
|
||||||
require.Equal(t, 2, len(mergeOptions.Route.Rules))
|
|
||||||
require.Equal(t, C.TypeDirect, mergeOptions.Outbounds[0].Type)
|
|
||||||
}
|
|
|
@ -1,6 +1,6 @@
|
||||||
package badversion
|
package badversion
|
||||||
|
|
||||||
import "github.com/sagernet/sing-box/common/json"
|
import "github.com/sagernet/sing/common/json"
|
||||||
|
|
||||||
func (v Version) MarshalJSON() ([]byte, error) {
|
func (v Version) MarshalJSON() ([]byte, error) {
|
||||||
return json.Marshal(v.String())
|
return json.Marshal(v.String())
|
||||||
|
|
|
@ -1,128 +0,0 @@
|
||||||
package json
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// kanged from v2ray
|
|
||||||
|
|
||||||
type commentFilterState = byte
|
|
||||||
|
|
||||||
const (
|
|
||||||
commentFilterStateContent commentFilterState = iota
|
|
||||||
commentFilterStateEscape
|
|
||||||
commentFilterStateDoubleQuote
|
|
||||||
commentFilterStateDoubleQuoteEscape
|
|
||||||
commentFilterStateSingleQuote
|
|
||||||
commentFilterStateSingleQuoteEscape
|
|
||||||
commentFilterStateComment
|
|
||||||
commentFilterStateSlash
|
|
||||||
commentFilterStateMultilineComment
|
|
||||||
commentFilterStateMultilineCommentStar
|
|
||||||
)
|
|
||||||
|
|
||||||
type CommentFilter struct {
|
|
||||||
br *bufio.Reader
|
|
||||||
state commentFilterState
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewCommentFilter(reader io.Reader) io.Reader {
|
|
||||||
return &CommentFilter{br: bufio.NewReader(reader)}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v *CommentFilter) Read(b []byte) (int, error) {
|
|
||||||
p := b[:0]
|
|
||||||
for len(p) < len(b)-2 {
|
|
||||||
x, err := v.br.ReadByte()
|
|
||||||
if err != nil {
|
|
||||||
if len(p) == 0 {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
switch v.state {
|
|
||||||
case commentFilterStateContent:
|
|
||||||
switch x {
|
|
||||||
case '"':
|
|
||||||
v.state = commentFilterStateDoubleQuote
|
|
||||||
p = append(p, x)
|
|
||||||
case '\'':
|
|
||||||
v.state = commentFilterStateSingleQuote
|
|
||||||
p = append(p, x)
|
|
||||||
case '\\':
|
|
||||||
v.state = commentFilterStateEscape
|
|
||||||
case '#':
|
|
||||||
v.state = commentFilterStateComment
|
|
||||||
case '/':
|
|
||||||
v.state = commentFilterStateSlash
|
|
||||||
default:
|
|
||||||
p = append(p, x)
|
|
||||||
}
|
|
||||||
case commentFilterStateEscape:
|
|
||||||
p = append(p, '\\', x)
|
|
||||||
v.state = commentFilterStateContent
|
|
||||||
case commentFilterStateDoubleQuote:
|
|
||||||
switch x {
|
|
||||||
case '"':
|
|
||||||
v.state = commentFilterStateContent
|
|
||||||
p = append(p, x)
|
|
||||||
case '\\':
|
|
||||||
v.state = commentFilterStateDoubleQuoteEscape
|
|
||||||
default:
|
|
||||||
p = append(p, x)
|
|
||||||
}
|
|
||||||
case commentFilterStateDoubleQuoteEscape:
|
|
||||||
p = append(p, '\\', x)
|
|
||||||
v.state = commentFilterStateDoubleQuote
|
|
||||||
case commentFilterStateSingleQuote:
|
|
||||||
switch x {
|
|
||||||
case '\'':
|
|
||||||
v.state = commentFilterStateContent
|
|
||||||
p = append(p, x)
|
|
||||||
case '\\':
|
|
||||||
v.state = commentFilterStateSingleQuoteEscape
|
|
||||||
default:
|
|
||||||
p = append(p, x)
|
|
||||||
}
|
|
||||||
case commentFilterStateSingleQuoteEscape:
|
|
||||||
p = append(p, '\\', x)
|
|
||||||
v.state = commentFilterStateSingleQuote
|
|
||||||
case commentFilterStateComment:
|
|
||||||
if x == '\n' {
|
|
||||||
v.state = commentFilterStateContent
|
|
||||||
p = append(p, '\n')
|
|
||||||
}
|
|
||||||
case commentFilterStateSlash:
|
|
||||||
switch x {
|
|
||||||
case '/':
|
|
||||||
v.state = commentFilterStateComment
|
|
||||||
case '*':
|
|
||||||
v.state = commentFilterStateMultilineComment
|
|
||||||
default:
|
|
||||||
p = append(p, '/', x)
|
|
||||||
}
|
|
||||||
case commentFilterStateMultilineComment:
|
|
||||||
switch x {
|
|
||||||
case '*':
|
|
||||||
v.state = commentFilterStateMultilineCommentStar
|
|
||||||
case '\n':
|
|
||||||
p = append(p, '\n')
|
|
||||||
}
|
|
||||||
case commentFilterStateMultilineCommentStar:
|
|
||||||
switch x {
|
|
||||||
case '/':
|
|
||||||
v.state = commentFilterStateContent
|
|
||||||
case '*':
|
|
||||||
// Stay
|
|
||||||
case '\n':
|
|
||||||
p = append(p, '\n')
|
|
||||||
default:
|
|
||||||
v.state = commentFilterStateMultilineComment
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
panic("Unknown state.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package json
|
|
||||||
|
|
||||||
import "encoding/json"
|
|
||||||
|
|
||||||
var (
|
|
||||||
Marshal = json.Marshal
|
|
||||||
Unmarshal = json.Unmarshal
|
|
||||||
NewEncoder = json.NewEncoder
|
|
||||||
NewDecoder = json.NewDecoder
|
|
||||||
)
|
|
||||||
|
|
||||||
type (
|
|
||||||
Encoder = json.Encoder
|
|
||||||
Decoder = json.Decoder
|
|
||||||
Token = json.Token
|
|
||||||
Delim = json.Delim
|
|
||||||
SyntaxError = json.SyntaxError
|
|
||||||
)
|
|
|
@ -6,12 +6,12 @@ import (
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/badjson"
|
|
||||||
"github.com/sagernet/sing-box/common/humanize"
|
"github.com/sagernet/sing-box/common/humanize"
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/log"
|
"github.com/sagernet/sing-box/log"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
|
"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
"github.com/sagernet/ws"
|
"github.com/sagernet/ws"
|
||||||
"github.com/sagernet/ws/wsutil"
|
"github.com/sagernet/ws/wsutil"
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/badjson"
|
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
"github.com/sagernet/sing-box/outbound"
|
"github.com/sagernet/sing-box/outbound"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/batch"
|
"github.com/sagernet/sing/common/batch"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/render"
|
"github.com/go-chi/render"
|
||||||
|
|
|
@ -7,8 +7,8 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
|
"github.com/sagernet/sing-box/experimental/clashapi/trafficontrol"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
"github.com/sagernet/ws"
|
"github.com/sagernet/ws"
|
||||||
"github.com/sagernet/ws/wsutil"
|
"github.com/sagernet/ws/wsutil"
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,12 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/badjson"
|
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/outbound"
|
"github.com/sagernet/sing-box/outbound"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
|
|
|
@ -11,7 +11,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/common/urltest"
|
"github.com/sagernet/sing-box/common/urltest"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/experimental"
|
"github.com/sagernet/sing-box/experimental"
|
||||||
|
@ -21,6 +20,7 @@ import (
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
"github.com/sagernet/sing/service"
|
"github.com/sagernet/sing/service"
|
||||||
"github.com/sagernet/sing/service/filemanager"
|
"github.com/sagernet/sing/service/filemanager"
|
||||||
|
|
|
@ -4,8 +4,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _Options struct {
|
type _Options struct {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _Inbound struct {
|
type _Inbound struct {
|
||||||
|
@ -114,7 +114,7 @@ func (h *Inbound) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_Inbound)(h), v)
|
err = UnmarshallExcluded(bytes, (*_Inbound)(h), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "inbound options")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ package option
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/badjson"
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
|
"github.com/sagernet/sing/common/json/badjson"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ToMap(v any) (*badjson.JSONObject, error) {
|
func ToMap(v any) (*badjson.JSONObject, error) {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ func (h *Outbound) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_Outbound)(h), v)
|
err = UnmarshallExcluded(bytes, (*_Outbound)(h), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "outbound options")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type OnDemandOptions struct {
|
type OnDemandOptions struct {
|
||||||
|
|
|
@ -3,10 +3,10 @@ package option
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _Rule struct {
|
type _Rule struct {
|
||||||
|
@ -48,7 +48,7 @@ func (r *Rule) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_Rule)(r), v)
|
err = UnmarshallExcluded(bytes, (*_Rule)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "route rule")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,10 +3,10 @@ package option
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _DNSRule struct {
|
type _DNSRule struct {
|
||||||
|
@ -48,7 +48,7 @@ func (r *DNSRule) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_DNSRule)(r), v)
|
err = UnmarshallExcluded(bytes, (*_DNSRule)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "dns route rule")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,12 @@ package option
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing/common"
|
"github.com/sagernet/sing/common"
|
||||||
"github.com/sagernet/sing/common/domain"
|
"github.com/sagernet/sing/common/domain"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
|
|
||||||
"go4.org/netipx"
|
"go4.org/netipx"
|
||||||
)
|
)
|
||||||
|
@ -64,7 +64,7 @@ func (r *RuleSet) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_RuleSet)(r), v)
|
err = UnmarshallExcluded(bytes, (*_RuleSet)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "rule set")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ func (r *HeadlessRule) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_HeadlessRule)(r), v)
|
err = UnmarshallExcluded(bytes, (*_HeadlessRule)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "route rule-set rule")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ func (r *PlainRuleSetCompat) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_PlainRuleSetCompat)(r), v)
|
err = UnmarshallExcluded(bytes, (*_PlainRuleSetCompat)(r), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "rule set")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type InboundACMEOptions struct {
|
type InboundACMEOptions struct {
|
||||||
|
@ -62,7 +62,7 @@ func (o *ACMEDNS01ChallengeOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_ACMEDNS01ChallengeOptions)(o), v)
|
err = UnmarshallExcluded(bytes, (*_ACMEDNS01ChallengeOptions)(o), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "DNS01 challenge options")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-dns"
|
"github.com/sagernet/sing-dns"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
F "github.com/sagernet/sing/common/format"
|
F "github.com/sagernet/sing/common/format"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
||||||
mDNS "github.com/miekg/dns"
|
mDNS "github.com/miekg/dns"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sagernet/sing-box/common/json"
|
"github.com/sagernet/sing/common/json"
|
||||||
"github.com/sagernet/sing/common/uot"
|
"github.com/sagernet/sing/common/uot"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package option
|
package option
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
type _V2RayTransportOptions struct {
|
type _V2RayTransportOptions struct {
|
||||||
|
@ -60,7 +60,7 @@ func (o *V2RayTransportOptions) UnmarshalJSON(bytes []byte) error {
|
||||||
}
|
}
|
||||||
err = UnmarshallExcluded(bytes, (*_V2RayTransportOptions)(o), v)
|
err = UnmarshallExcluded(bytes, (*_V2RayTransportOptions)(o), v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return E.Cause(err, "vmess transport options")
|
return err
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,11 @@ import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/common/srs"
|
"github.com/sagernet/sing-box/common/srs"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.RuleSet = (*LocalRuleSet)(nil)
|
var _ adapter.RuleSet = (*LocalRuleSet)(nil)
|
||||||
|
|
|
@ -10,11 +10,11 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sagernet/sing-box/adapter"
|
"github.com/sagernet/sing-box/adapter"
|
||||||
"github.com/sagernet/sing-box/common/json"
|
|
||||||
"github.com/sagernet/sing-box/common/srs"
|
"github.com/sagernet/sing-box/common/srs"
|
||||||
C "github.com/sagernet/sing-box/constant"
|
C "github.com/sagernet/sing-box/constant"
|
||||||
"github.com/sagernet/sing-box/option"
|
"github.com/sagernet/sing-box/option"
|
||||||
E "github.com/sagernet/sing/common/exceptions"
|
E "github.com/sagernet/sing/common/exceptions"
|
||||||
|
"github.com/sagernet/sing/common/json"
|
||||||
"github.com/sagernet/sing/common/logger"
|
"github.com/sagernet/sing/common/logger"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
N "github.com/sagernet/sing/common/network"
|
N "github.com/sagernet/sing/common/network"
|
||||||
|
|
Loading…
Reference in a new issue