1
0
mirror of https://github.com/nitezs/sub2sing-box.git synced 2024-12-23 14:44:42 -05:00

♻️ Refactor

This commit is contained in:
Nite07 2024-10-03 01:24:54 +08:00
parent 573d0056d0
commit 3729675031
32 changed files with 284 additions and 829 deletions

View File

@ -15,6 +15,7 @@ import (
"github.com/nitezs/sub2sing-box/model" "github.com/nitezs/sub2sing-box/model"
"github.com/nitezs/sub2sing-box/parser" "github.com/nitezs/sub2sing-box/parser"
"github.com/nitezs/sub2sing-box/util" "github.com/nitezs/sub2sing-box/util"
"github.com/sagernet/sing-box/option"
) )
func Convert( func Convert(
@ -99,7 +100,7 @@ func Convert(
if reg.MatchString(templateDate) || strings.Contains(templateDate, constant.AllCountryTags) || group { if reg.MatchString(templateDate) || strings.Contains(templateDate, constant.AllCountryTags) || group {
outbounds = AddCountryGroup(outbounds, groupType, sortKey, sortType) outbounds = AddCountryGroup(outbounds, groupType, sortKey, sortType)
} }
var template model.Config var template model.Options
if err = json.Unmarshal([]byte(templateDate), &template); err != nil { if err = json.Unmarshal([]byte(templateDate), &template); err != nil {
return "", err return "", err
} }
@ -129,20 +130,24 @@ func AddCountryGroup(proxies []model.Outbound, groupType string, sortKey string,
} else { } else {
if groupType == C.TypeSelector || groupType == "" { if groupType == C.TypeSelector || groupType == "" {
newGroup[country] = model.Outbound{ newGroup[country] = model.Outbound{
Tag: country, Outbound: option.Outbound{
Type: groupType, Tag: country,
SelectorOptions: model.SelectorOutboundOptions{ Type: groupType,
Outbounds: []string{p.Tag}, SelectorOptions: option.SelectorOutboundOptions{
InterruptExistConnections: true, Outbounds: []string{p.Tag},
InterruptExistConnections: true,
},
}, },
} }
} else if groupType == C.TypeURLTest { } else if groupType == C.TypeURLTest {
newGroup[country] = model.Outbound{ newGroup[country] = model.Outbound{
Tag: country, Outbound: option.Outbound{
Type: groupType, Tag: country,
URLTestOptions: model.URLTestOutboundOptions{ Type: groupType,
Outbounds: []string{p.Tag}, URLTestOptions: option.URLTestOutboundOptions{
InterruptExistConnections: true, Outbounds: []string{p.Tag},
InterruptExistConnections: true,
},
}, },
} }
} }
@ -200,7 +205,7 @@ func ReadTemplate(template string) (string, error) {
} }
} }
func MergeTemplate(outbounds []model.Outbound, template *model.Config) (string, error) { func MergeTemplate(outbounds []model.Outbound, template *model.Options) (string, error) {
var err error var err error
proxyTags := make([]string, 0) proxyTags := make([]string, 0)
groupTags := make([]string, 0) groupTags := make([]string, 0)

47
go.mod
View File

@ -3,38 +3,49 @@ module github.com/nitezs/sub2sing-box
go 1.21.5 go 1.21.5
require ( require (
github.com/spf13/cobra v1.8.0 github.com/sagernet/sing-box v1.10.0-beta.11
golang.org/x/text v0.9.0 github.com/spf13/cobra v1.8.1
golang.org/x/text v0.18.0
) )
require ( require (
github.com/bytedance/sonic v1.9.1 // indirect github.com/bytedance/sonic v1.12.3 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/bytedance/sonic/loader v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.5 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.14.0 // indirect github.com/go-playground/validator/v10 v10.22.1 // indirect
github.com/goccy/go-json v0.10.2 // indirect github.com/goccy/go-json v0.10.3 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/klauspost/cpuid/v2 v2.2.8 // indirect
github.com/leodido/go-urn v1.2.4 // indirect github.com/kr/text v0.2.0 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/miekg/dns v1.1.61 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.8 // indirect github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/sagernet/sing v0.5.0-beta.2 // indirect
github.com/sagernet/sing-dns v0.3.0-beta.14 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.11 // indirect github.com/ugorji/go/codec v1.2.12 // indirect
golang.org/x/arch v0.3.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect
golang.org/x/crypto v0.9.0 // indirect golang.org/x/arch v0.10.0 // indirect
golang.org/x/net v0.10.0 // indirect golang.org/x/crypto v0.27.0 // indirect
golang.org/x/sys v0.8.0 // indirect golang.org/x/mod v0.19.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect golang.org/x/net v0.29.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/tools v0.23.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )
require ( require (
github.com/gin-gonic/gin v1.9.1 github.com/gin-gonic/gin v1.10.0
github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
) )

138
go.sum
View File

@ -1,56 +1,84 @@
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.12.3 h1:W2MGa7RCU1QTeYRTPE3+88mVC0yXmsRQRChiyVocVjU=
github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s= github.com/bytedance/sonic v1.12.3/go.mod h1:B8Gt/XvtZ3Fqj+iSKMypzymZxw/FVwgIGKzMzT9r/rk=
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/bytedance/sonic/loader v0.2.0 h1:zNprn+lsIP06C/IqCHs3gPQIvnvpKbbxyXQP1iU4kWM=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/bytedance/sonic/loader v0.2.0/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU= github.com/gabriel-vasile/mimetype v1.4.5 h1:J7wGKdGu33ocBOhGy0z653k/lFKLFDPJMG8Gql0kxn4=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA= github.com/gabriel-vasile/mimetype v1.4.5/go.mod h1:ibHel+/kbxn9x2407k1izTA1S81ku1z/DlgOW2QE0M4=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.22.1 h1:40JcKH+bBNGFczGuoBYgX4I6m/i27HYW8P9FDk5PbgA=
github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-playground/validator/v10 v10.22.1/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a h1:fEBsGL/sjAuJrgah5XqmmYsTLzJp/TO9Lhy39gkverk=
github.com/google/pprof v0.0.0-20231101202521-4ca4178f5c7a/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk= github.com/klauspost/cpuid/v2 v2.2.8 h1:+StwCXwm9PdpiEkPyzBXIy+M9KUb4ODm0Zarf1kS5BM=
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= github.com/klauspost/cpuid/v2 v2.2.8/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/miekg/dns v1.1.61 h1:nLxbwF3XxhwVSm8g9Dghm9MHPaUZuqhPiGL+675ZmEs=
github.com/miekg/dns v1.1.61/go.mod h1:mnAarhS3nWaW+NVP2wTkYVIZyHNJ098SJZUki3eykwQ=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo/v2 v2.9.7 h1:06xGQy5www2oN160RtEZoTvnP2sPhEfePYmCDc2szss=
github.com/onsi/ginkgo/v2 v2.9.7/go.mod h1:cxrmXWykAwTwhQsJOPfdIDiJ+l2RYq7U8hFU+M/1uw0=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo=
github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A=
github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs=
github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= github.com/sagernet/quic-go v0.47.0-beta.2 h1:1tCGWFOSaXIeuQaHrwOMJIYvlupjTcaVInGQw5ArULU=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= github.com/sagernet/quic-go v0.47.0-beta.2/go.mod h1:bLVKvElSEMNv7pu7SZHscW02TYigzQ5lQu3Nh4wNh8Q=
github.com/sagernet/sing v0.5.0-beta.2 h1:V12EpwtsgYo5OLGjAiGoJobDJZeUsKv0b5y+yGAM6W0=
github.com/sagernet/sing v0.5.0-beta.2/go.mod h1:ARkL0gM13/Iv5VCZmci/NuoOlePoIsW0m7BWfln/Hak=
github.com/sagernet/sing-box v1.10.0-beta.11 h1:SBQtW1WPoNEmTvBCwzngSaFrYfYCqjO/J6CHLZd5S/Q=
github.com/sagernet/sing-box v1.10.0-beta.11/go.mod h1:VkzoxRgxB87Z0F2vR00qjmezphU/GG9TtgaUYrAzdY8=
github.com/sagernet/sing-dns v0.3.0-beta.14 h1:/s+fJzYKsvLaNDt/2rjpsrDcN8wmCO2JbX6OFrl8Nww=
github.com/sagernet/sing-dns v0.3.0-beta.14/go.mod h1:rscgSr5ixOPk8XM9ZMLuMXCyldEQ1nLvdl0nfv+lp00=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@ -61,34 +89,40 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBseWJUpBw5I82+2U4M=
golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y=
golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.10.0 h1:S3huipmSclq3PJMNe76NGwkBR504WFkQ5dhzWzP8ZW8=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/arch v0.10.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=

View File

@ -1,102 +0,0 @@
package model
import "encoding/json"
type Listable[T any] []T
func (l *Listable[T]) UnmarshalJSON(data []byte) error {
var arr []T
if err := json.Unmarshal(data, &arr); err == nil {
*l = arr
return nil
}
var v T
if err := json.Unmarshal(data, &v); err == nil {
*l = []T{v}
return nil
}
return nil
}
type Config struct {
Log any `json:"log,omitempty"`
DNS any `json:"dns,omitempty"`
NTP any `json:"ntp,omitempty"`
Inbounds any `json:"inbounds,omitempty"`
Outbounds []Outbound `json:"outbounds,omitempty"`
Route *RouteOptions `json:"route,omitempty"`
Experimental any `json:"experimental,omitempty"`
}
type RouteOptions struct {
GeoIP *GeoIPOptions `json:"geoip,omitempty"`
Geosite *GeositeOptions `json:"geosite,omitempty"`
Rules Listable[Rule] `json:"rules,omitempty"`
RuleSet Listable[RuleSet] `json:"rule_set,omitempty"`
Final string `json:"final,omitempty"`
FindProcess bool `json:"find_process,omitempty"`
AutoDetectInterface bool `json:"auto_detect_interface,omitempty"`
OverrideAndroidVPN bool `json:"override_android_vpn,omitempty"`
DefaultInterface string `json:"default_interface,omitempty"`
DefaultMark int `json:"default_mark,omitempty"`
}
type Rule struct {
Type string `json:"type,omitempty"`
Inbound Listable[string] `json:"inbound,omitempty"`
IPVersion int `json:"ip_version,omitempty"`
Network Listable[string] `json:"network,omitempty"`
AuthUser Listable[string] `json:"auth_user,omitempty"`
Protocol string `json:"protocol,omitempty"`
Domain Listable[string] `json:"domain,omitempty"`
DomainSuffix Listable[string] `json:"domain_suffix,omitempty"`
DomainKeyword Listable[string] `json:"domain_keyword,omitempty"`
DomainRegex Listable[string] `json:"domain_regex,omitempty"`
Geosite Listable[string] `json:"geosite,omitempty"`
SourceGeoIP Listable[string] `json:"source_geoip,omitempty"`
GeoIP Listable[string] `json:"geoip,omitempty"`
SourceIPCIDR Listable[string] `json:"source_ip_cidr,omitempty"`
SourceIPIsPrivate bool `json:"source_ip_is_private,omitempty"`
IPCIDR Listable[string] `json:"ip_cidr,omitempty"`
IPIsPrivate bool `json:"ip_is_private,omitempty"`
SourcePort Listable[uint16] `json:"source_port,omitempty"`
SourcePortRange Listable[string] `json:"source_port_range,omitempty"`
Port Listable[uint16] `json:"port,omitempty"`
PortRange Listable[string] `json:"port_range,omitempty"`
ProcessName Listable[string] `json:"process_name,omitempty"`
ProcessPath Listable[string] `json:"process_path,omitempty"`
PackageName Listable[string] `json:"package_name,omitempty"`
User Listable[string] `json:"user,omitempty"`
UserID Listable[int32] `json:"user_id,omitempty"`
ClashMode string `json:"clash_mode,omitempty"`
WIFISSID Listable[string] `json:"wifi_ssid,omitempty"`
WIFIBSSID Listable[string] `json:"wifi_bssid,omitempty"`
RuleSet Listable[string] `json:"rule_set,omitempty"`
RuleSetIPCIDRMatchSource bool `json:"rule_set_ipcidr_match_source,omitempty"`
Invert bool `json:"invert,omitempty"`
Outbound string `json:"outbound,omitempty"`
Mode string `json:"mode,omitempty"`
Rules Listable[Rule] `json:"rules,omitempty"`
}
type GeoIPOptions struct {
Path string `json:"path,omitempty"`
DownloadURL string `json:"download_url,omitempty"`
DownloadDetour string `json:"download_detour,omitempty"`
}
type GeositeOptions struct {
Path string `json:"path,omitempty"`
DownloadURL string `json:"download_url,omitempty"`
DownloadDetour string `json:"download_detour,omitempty"`
}
type RuleSet struct {
Type string `json:"type"`
Tag string `json:"tag"`
Format string `json:"format"`
Path string `json:"path,omitempty"`
URL string `json:"url"`
DownloadDetour string `json:"download_detour,omitempty"`
UpdateInterval string `json:"update_interval,omitempty"`
}

View File

@ -1,8 +0,0 @@
package model
type DirectOutboundOptions struct {
DialerOptions
OverrideAddress string `json:"override_address,omitempty"`
OverridePort uint16 `json:"override_port,omitempty"`
ProxyProtocol uint8 `json:"proxy_protocol,omitempty"`
}

View File

@ -1,16 +0,0 @@
package model
type SelectorOutboundOptions struct {
Outbounds []string `json:"outbounds"`
Default string `json:"default,omitempty"`
InterruptExistConnections bool `json:"interrupt_exist_connections,omitempty"`
}
type URLTestOutboundOptions struct {
Outbounds []string `json:"outbounds"`
URL string `json:"url,omitempty"`
Interval string `json:"interval,omitempty"`
Tolerance uint16 `json:"tolerance,omitempty"`
IdleTimeout string `json:"idle_timeout,omitempty"`
InterruptExistConnections bool `json:"interrupt_exist_connections,omitempty"`
}

View File

@ -1,18 +0,0 @@
package model
type HysteriaOutboundOptions struct {
DialerOptions
ServerOptions
Up string `json:"up,omitempty"`
UpMbps int `json:"up_mbps,omitempty"`
Down string `json:"down,omitempty"`
DownMbps int `json:"down_mbps,omitempty"`
Obfs string `json:"obfs,omitempty"`
Auth []byte `json:"auth,omitempty"`
AuthString string `json:"auth_str,omitempty"`
ReceiveWindowConn uint64 `json:"recv_window_conn,omitempty"`
ReceiveWindow uint64 `json:"recv_window,omitempty"`
DisableMTUDiscovery bool `json:"disable_mtu_discovery,omitempty"`
Network string `json:"network,omitempty"`
OutboundTLSOptionsContainer
}

View File

@ -1,18 +0,0 @@
package model
type Hysteria2Obfs struct {
Type string `json:"type,omitempty"`
Password string `json:"password,omitempty"`
}
type Hysteria2OutboundOptions struct {
DialerOptions
ServerOptions
UpMbps int `json:"up_mbps,omitempty"`
DownMbps int `json:"down_mbps,omitempty"`
Obfs *Hysteria2Obfs `json:"obfs,omitempty"`
Password string `json:"password,omitempty"`
Network string `json:"network,omitempty"`
OutboundTLSOptionsContainer
BrutalDebug bool `json:"brutal_debug,omitempty"`
}

View File

@ -1,17 +0,0 @@
package model
type OutboundMultiplexOptions struct {
Enabled bool `json:"enabled,omitempty"`
Protocol string `json:"protocol,omitempty"`
MaxConnections int `json:"max_connections,omitempty"`
MinStreams int `json:"min_streams,omitempty"`
MaxStreams int `json:"max_streams,omitempty"`
Padding bool `json:"padding,omitempty"`
Brutal *BrutalOptions `json:"brutal,omitempty"`
}
type BrutalOptions struct {
Enabled bool `json:"enabled,omitempty"`
UpMbps int `json:"up_mbps,omitempty"`
DownMbps int `json:"down_mbps,omitempty"`
}

41
model/option.go Normal file
View File

@ -0,0 +1,41 @@
package model
import (
"bytes"
"encoding/json"
"github.com/sagernet/sing-box/option"
)
type _Options struct {
RawMessage json.RawMessage `json:"-"`
Schema string `json:"$schema,omitempty"`
Log *LogOptions `json:"log,omitempty"`
DNS *option.DNSOptions `json:"dns,omitempty"`
NTP *option.NTPOptions `json:"ntp,omitempty"`
Inbounds []option.Inbound `json:"inbounds,omitempty"`
Outbounds []Outbound `json:"outbounds,omitempty"`
Route *option.RouteOptions `json:"route,omitempty"`
Experimental *option.ExperimentalOptions `json:"experimental,omitempty"`
}
type Options _Options
func (o *Options) UnmarshalJSON(content []byte) error {
decoder := json.NewDecoder(bytes.NewReader(content))
decoder.DisallowUnknownFields()
err := decoder.Decode((*_Options)(o))
if err != nil {
return err
}
o.RawMessage = content
return nil
}
type LogOptions struct {
Disabled bool `json:"disabled,omitempty"`
Level string `json:"level,omitempty"`
Output string `json:"output,omitempty"`
Timestamp bool `json:"timestamp,omitempty"`
DisableColor bool `json:"-"`
}

View File

@ -1,155 +1,12 @@
package model package model
import ( import (
"encoding/json"
"errors"
"reflect"
"strings"
C "github.com/nitezs/sub2sing-box/constant" C "github.com/nitezs/sub2sing-box/constant"
"github.com/sagernet/sing-box/option"
) )
type _Outbound struct { type Outbound struct {
Type string `json:"type"` option.Outbound
Tag string `json:"tag,omitempty"`
DirectOptions DirectOutboundOptions `json:"-"`
SocksOptions SocksOutboundOptions `json:"-"`
HTTPOptions HTTPOutboundOptions `json:"-"`
ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"`
VMessOptions VMessOutboundOptions `json:"-"`
TrojanOptions TrojanOutboundOptions `json:"-"`
WireGuardOptions WireGuardOutboundOptions `json:"-"`
HysteriaOptions HysteriaOutboundOptions `json:"-"`
TorOptions TorOutboundOptions `json:"-"`
SSHOptions SSHOutboundOptions `json:"-"`
ShadowTLSOptions ShadowTLSOutboundOptions `json:"-"`
ShadowsocksROptions ShadowsocksROutboundOptions `json:"-"`
VLESSOptions VLESSOutboundOptions `json:"-"`
TUICOptions TUICOutboundOptions `json:"-"`
Hysteria2Options Hysteria2OutboundOptions `json:"-"`
SelectorOptions SelectorOutboundOptions `json:"-"`
URLTestOptions URLTestOutboundOptions `json:"-"`
}
type Outbound _Outbound
func (h *Outbound) RawOptions() (any, error) {
var rawOptionsPtr any
switch h.Type {
case C.TypeDirect:
rawOptionsPtr = &h.DirectOptions
case C.TypeBlock, C.TypeDNS:
rawOptionsPtr = nil
case C.TypeSOCKS:
rawOptionsPtr = &h.SocksOptions
case C.TypeHTTP:
rawOptionsPtr = &h.HTTPOptions
case C.TypeShadowsocks:
rawOptionsPtr = &h.ShadowsocksOptions
case C.TypeVMess:
rawOptionsPtr = &h.VMessOptions
case C.TypeTrojan:
rawOptionsPtr = &h.TrojanOptions
case C.TypeWireGuard:
rawOptionsPtr = &h.WireGuardOptions
case C.TypeHysteria:
rawOptionsPtr = &h.HysteriaOptions
case C.TypeTor:
rawOptionsPtr = &h.TorOptions
case C.TypeSSH:
rawOptionsPtr = &h.SSHOptions
case C.TypeShadowTLS:
rawOptionsPtr = &h.ShadowTLSOptions
case C.TypeShadowsocksR:
rawOptionsPtr = &h.ShadowsocksROptions
case C.TypeVLESS:
rawOptionsPtr = &h.VLESSOptions
case C.TypeTUIC:
rawOptionsPtr = &h.TUICOptions
case C.TypeHysteria2:
rawOptionsPtr = &h.Hysteria2Options
case C.TypeSelector:
rawOptionsPtr = &h.SelectorOptions
case C.TypeURLTest:
rawOptionsPtr = &h.URLTestOptions
case "":
return nil, errors.New("missing outbound type")
default:
return nil, errors.New("unknown outbound type: " + h.Type)
}
return rawOptionsPtr, nil
}
func (h *Outbound) MarshalJSON() ([]byte, error) {
rawOptions, err := h.RawOptions()
if err != nil {
return nil, err
}
if rawOptions == nil {
return json.Marshal((*_Outbound)(h))
}
result := make(map[string]any)
result["type"] = h.Type
result["tag"] = h.Tag
optsValue := reflect.ValueOf(rawOptions).Elem()
optsType := optsValue.Type()
for i := 0; i < optsType.NumField(); i++ {
field := optsValue.Field(i)
fieldType := optsType.Field(i)
if fieldType.Anonymous {
embeddedFields := reflect.ValueOf(field.Interface())
if field.Kind() == reflect.Struct {
for j := 0; j < embeddedFields.NumField(); j++ {
embeddedField := embeddedFields.Field(j)
embeddedFieldType := embeddedFields.Type().Field(j)
processField(embeddedField, embeddedFieldType, result)
}
}
} else {
processField(field, fieldType, result)
}
}
return json.Marshal(result)
}
func processField(field reflect.Value, fieldType reflect.StructField, result map[string]any) {
jsonTag := fieldType.Tag.Get("json")
if jsonTag == "-" {
return
}
tagParts := strings.Split(jsonTag, ",")
tagName := tagParts[0]
if len(tagParts) > 1 && tagParts[1] == "omitempty" && field.IsZero() {
return
}
result[tagName] = field.Interface()
}
func (h *Outbound) UnmarshalJSON(bytes []byte) error {
err := json.Unmarshal(bytes, (*_Outbound)(h))
if err != nil {
return err
}
rawOptions, err := h.RawOptions()
if err != nil {
return err
}
if rawOptions == nil {
return nil
}
err = json.Unmarshal(bytes, rawOptions)
if err != nil {
return err
}
rawOptionsType := reflect.TypeOf(rawOptions).Elem()
hValue := reflect.ValueOf(h).Elem()
for i := 0; i < hValue.NumField(); i++ {
fieldType := hValue.Field(i).Type()
if fieldType == rawOptionsType {
hValue.Field(i).Set(reflect.ValueOf(rawOptions).Elem())
return nil
}
}
return errors.New("unknown outbound type: " + h.Type)
} }
func (h *Outbound) GetOutbounds() []string { func (h *Outbound) GetOutbounds() []string {
@ -170,26 +27,3 @@ func (h *Outbound) SetOutbounds(outbounds []string) {
h.URLTestOptions.Outbounds = outbounds h.URLTestOptions.Outbounds = outbounds
} }
} }
type DialerOptions struct {
Detour string `json:"detour,omitempty"`
BindInterface string `json:"bind_interface,omitempty"`
Inet4BindAddress string `json:"inet4_bind_address,omitempty"`
Inet6BindAddress string `json:"inet6_bind_address,omitempty"`
ProtectPath string `json:"protect_path,omitempty"`
RoutingMark int `json:"routing_mark,omitempty"`
ReuseAddr bool `json:"reuse_addr,omitempty"`
ConnectTimeout string `json:"connect_timeout,omitempty"`
TCPFastOpen bool `json:"tcp_fast_open,omitempty"`
TCPMultiPath bool `json:"tcp_multi_path,omitempty"`
UDPFragment *bool `json:"udp_fragment,omitempty"`
UDPFragmentDefault bool `json:"-"`
DomainStrategy string `json:"domain_strategy,omitempty"`
FallbackDelay string `json:"fallback_delay,omitempty"`
IsWireGuardListener bool `json:"-"`
}
type ServerOptions struct {
Server string `json:"server"`
ServerPort uint16 `json:"server_port"`
}

View File

@ -1,13 +0,0 @@
package model
type ShadowsocksOutboundOptions struct {
DialerOptions
ServerOptions
Method string `json:"method"`
Password string `json:"password"`
Plugin string `json:"plugin,omitempty"`
PluginOptions string `json:"plugin_opts,omitempty"`
Network string `json:"network,omitempty"`
UDPOverTCP *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"`
Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"`
}

View File

@ -1,13 +0,0 @@
package model
type ShadowsocksROutboundOptions struct {
DialerOptions
ServerOptions
Method string `json:"method"`
Password string `json:"password"`
Obfs string `json:"obfs,omitempty"`
ObfsParam string `json:"obfs_param,omitempty"`
Protocol string `json:"protocol,omitempty"`
ProtocolParam string `json:"protocol_param,omitempty"`
Network string `json:"network,omitempty"`
}

View File

@ -1,19 +0,0 @@
package model
type ShadowTLSUser struct {
Name string `json:"name,omitempty"`
Password string `json:"password,omitempty"`
}
type ShadowTLSHandshakeOptions struct {
ServerOptions
DialerOptions
}
type ShadowTLSOutboundOptions struct {
DialerOptions
ServerOptions
Version int `json:"version,omitempty"`
Password string `json:"password,omitempty"`
OutboundTLSOptionsContainer
}

View File

@ -1,21 +0,0 @@
package model
type SocksOutboundOptions struct {
DialerOptions
ServerOptions
Version string `json:"version,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
Network Listable[string] `json:"network,omitempty"`
UDPOverTCP *UDPOverTCPOptions `json:"udp_over_tcp,omitempty"`
}
type HTTPOutboundOptions struct {
DialerOptions
ServerOptions
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
OutboundTLSOptionsContainer
Path string `json:"path,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
}

View File

@ -1,14 +0,0 @@
package model
type SSHOutboundOptions struct {
DialerOptions
ServerOptions
User string `json:"user,omitempty"`
Password string `json:"password,omitempty"`
PrivateKey Listable[string] `json:"private_key,omitempty"`
PrivateKeyPath string `json:"private_key_path,omitempty"`
PrivateKeyPassphrase string `json:"private_key_passphrase,omitempty"`
HostKey Listable[string] `json:"host_key,omitempty"`
HostKeyAlgorithms Listable[string] `json:"host_key_algorithms,omitempty"`
ClientVersion string `json:"client_version,omitempty"`
}

View File

@ -1,40 +0,0 @@
package model
type OutboundTLSOptions struct {
Enabled bool `json:"enabled,omitempty"`
DisableSNI bool `json:"disable_sni,omitempty"`
ServerName string `json:"server_name,omitempty"`
Insecure bool `json:"insecure,omitempty"`
ALPN Listable[string] `json:"alpn,omitempty"`
MinVersion string `json:"min_version,omitempty"`
MaxVersion string `json:"max_version,omitempty"`
CipherSuites Listable[string] `json:"cipher_suites,omitempty"`
Certificate Listable[string] `json:"certificate,omitempty"`
CertificatePath string `json:"certificate_path,omitempty"`
ECH *OutboundECHOptions `json:"ech,omitempty"`
UTLS *OutboundUTLSOptions `json:"utls,omitempty"`
Reality *OutboundRealityOptions `json:"reality,omitempty"`
}
type OutboundECHOptions struct {
Enabled bool `json:"enabled,omitempty"`
PQSignatureSchemesEnabled bool `json:"pq_signature_schemes_enabled,omitempty"`
DynamicRecordSizingDisabled bool `json:"dynamic_record_sizing_disabled,omitempty"`
Config Listable[string] `json:"config,omitempty"`
ConfigPath string `json:"config_path,omitempty"`
}
type OutboundUTLSOptions struct {
Enabled bool `json:"enabled,omitempty"`
Fingerprint string `json:"fingerprint,omitempty"`
}
type OutboundRealityOptions struct {
Enabled bool `json:"enabled,omitempty"`
PublicKey string `json:"public_key,omitempty"`
ShortID string `json:"short_id,omitempty"`
}
type OutboundTLSOptionsContainer struct {
TLS *OutboundTLSOptions `json:"tls,omitempty"`
}

View File

@ -1,9 +0,0 @@
package model
type TorOutboundOptions struct {
DialerOptions
ExecutablePath string `json:"executable_path,omitempty"`
ExtraArgs []string `json:"extra_args,omitempty"`
DataDirectory string `json:"data_directory,omitempty"`
Options map[string]string `json:"torrc,omitempty"`
}

View File

@ -1,11 +0,0 @@
package model
type TrojanOutboundOptions struct {
DialerOptions
ServerOptions
Password string `json:"password"`
Network string `json:"network,omitempty"`
OutboundTLSOptionsContainer
Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"`
}

View File

@ -1,15 +0,0 @@
package model
type TUICOutboundOptions struct {
DialerOptions
ServerOptions
UUID string `json:"uuid,omitempty"`
Password string `json:"password,omitempty"`
CongestionControl string `json:"congestion_control,omitempty"`
UDPRelayMode string `json:"udp_relay_mode,omitempty"`
UDPOverStream bool `json:"udp_over_stream,omitempty"`
ZeroRTTHandshake bool `json:"zero_rtt_handshake,omitempty"`
Heartbeat string `json:"heartbeat,omitempty"`
Network string `json:"network,omitempty"`
OutboundTLSOptionsContainer
}

View File

@ -1,6 +0,0 @@
package model
type UDPOverTCPOptions struct {
Enabled bool `json:"enabled,omitempty"`
Version uint8 `json:"version,omitempty"`
}

View File

@ -1,85 +0,0 @@
package model
import (
"encoding/json"
)
type V2RayTransportOptions struct {
Type string `json:"type"`
HTTPOptions V2RayHTTPOptions `json:"-"`
WebsocketOptions V2RayWebsocketOptions `json:"-"`
QUICOptions V2RayQUICOptions `json:"-"`
GRPCOptions V2RayGRPCOptions `json:"-"`
HTTPUpgradeOptions V2RayHTTPUpgradeOptions `json:"-"`
}
func (o *V2RayTransportOptions) MarshalJSON() ([]byte, error) {
switch o.Type {
case "ws":
return json.Marshal(&struct {
Type string `json:"type"`
*V2RayWebsocketOptions
}{
Type: o.Type,
V2RayWebsocketOptions: &o.WebsocketOptions,
})
case "quic":
return json.Marshal(&struct {
Type string `json:"type"`
*V2RayQUICOptions
}{
Type: o.Type,
V2RayQUICOptions: &o.QUICOptions,
})
case "grpc":
return json.Marshal(&struct {
Type string `json:"type"`
*V2RayGRPCOptions
}{
Type: o.Type,
V2RayGRPCOptions: &o.GRPCOptions,
})
case "http":
return json.Marshal(&struct {
Type string `json:"type"`
*V2RayHTTPOptions
}{
Type: o.Type,
V2RayHTTPOptions: &o.HTTPOptions,
})
default:
return json.Marshal(&struct{}{})
}
}
type V2RayHTTPOptions struct {
Host Listable[string] `json:"host,omitempty"`
Path string `json:"path,omitempty"`
Method string `json:"method,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
IdleTimeout string `json:"idle_timeout,omitempty"`
PingTimeout string `json:"ping_timeout,omitempty"`
}
type V2RayWebsocketOptions struct {
Path string `json:"path,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
MaxEarlyData uint32 `json:"max_early_data,omitempty"`
EarlyDataHeaderName string `json:"early_data_header_name,omitempty"`
}
type V2RayQUICOptions struct{}
type V2RayGRPCOptions struct {
ServiceName string `json:"service_name,omitempty"`
IdleTimeout string `json:"idle_timeout,omitempty"`
PingTimeout string `json:"ping_timeout,omitempty"`
PermitWithoutStream bool `json:"permit_without_stream,omitempty"`
ForceLite bool `json:"-"` // for test
}
type V2RayHTTPUpgradeOptions struct {
Host string `json:"host,omitempty"`
Path string `json:"path,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
}

View File

@ -1,13 +0,0 @@
package model
type VLESSOutboundOptions struct {
DialerOptions
ServerOptions
UUID string `json:"uuid"`
Flow string `json:"flow,omitempty"`
Network string `json:"network,omitempty"`
OutboundTLSOptionsContainer
Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"`
PacketEncoding *string `json:"packet_encoding,omitempty"`
}

View File

@ -17,18 +17,3 @@ type VmessJson struct {
Alpn string `json:"alpn"` Alpn string `json:"alpn"`
Fp string `json:"fp"` Fp string `json:"fp"`
} }
type VMessOutboundOptions struct {
DialerOptions
ServerOptions
UUID string `json:"uuid"`
Security string `json:"security"`
AlterId int `json:"alter_id,omitempty"`
GlobalPadding bool `json:"global_padding,omitempty"`
AuthenticatedLength bool `json:"authenticated_length,omitempty"`
Network string `json:"network,omitempty"`
OutboundTLSOptionsContainer
PacketEncoding string `json:"packet_encoding,omitempty"`
Multiplex *OutboundMultiplexOptions `json:"multiplex,omitempty"`
Transport *V2RayTransportOptions `json:"transport,omitempty"`
}

View File

@ -1,28 +0,0 @@
package model
import "net/netip"
type WireGuardOutboundOptions struct {
DialerOptions
SystemInterface bool `json:"system_interface,omitempty"`
GSO bool `json:"gso,omitempty"`
InterfaceName string `json:"interface_name,omitempty"`
LocalAddress Listable[netip.Prefix] `json:"local_address"`
PrivateKey string `json:"private_key"`
Peers []WireGuardPeer `json:"peers,omitempty"`
ServerOptions
PeerPublicKey string `json:"peer_public_key"`
PreSharedKey string `json:"pre_shared_key,omitempty"`
Reserved []uint8 `json:"reserved,omitempty"`
Workers int `json:"workers,omitempty"`
MTU uint32 `json:"mtu,omitempty"`
Network string `json:"network,omitempty"`
}
type WireGuardPeer struct {
ServerOptions
PublicKey string `json:"public_key,omitempty"`
PreSharedKey string `json:"pre_shared_key,omitempty"`
AllowedIPs Listable[string] `json:"allowed_ips,omitempty"`
Reserved []uint8 `json:"reserved,omitempty"`
}

View File

@ -8,6 +8,7 @@ import (
"github.com/nitezs/sub2sing-box/constant" "github.com/nitezs/sub2sing-box/constant"
"github.com/nitezs/sub2sing-box/model" "github.com/nitezs/sub2sing-box/model"
"github.com/sagernet/sing-box/option"
) )
func ParseHysteria(proxy string) (model.Outbound, error) { func ParseHysteria(proxy string) (model.Outbound, error) {
@ -70,11 +71,11 @@ func ParseHysteria(proxy string) (model.Outbound, error) {
} }
remarks = strings.TrimSpace(remarks) remarks = strings.TrimSpace(remarks)
return model.Outbound{ return model.Outbound{Outbound: option.Outbound{
Type: "hysteria", Type: "hysteria",
Tag: remarks, Tag: remarks,
HysteriaOptions: model.HysteriaOutboundOptions{ HysteriaOptions: option.HysteriaOutboundOptions{
ServerOptions: model.ServerOptions{ ServerOptions: option.ServerOptions{
Server: server, Server: server,
ServerPort: port, ServerPort: port,
}, },
@ -82,14 +83,14 @@ func ParseHysteria(proxy string) (model.Outbound, error) {
Down: downmbps, Down: downmbps,
Auth: []byte(auth), Auth: []byte(auth),
Obfs: obfs, Obfs: obfs,
Network: protocol, Network: option.NetworkList(protocol),
OutboundTLSOptionsContainer: model.OutboundTLSOptionsContainer{ OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
TLS: &model.OutboundTLSOptions{ TLS: &option.OutboundTLSOptions{
Enabled: true, Enabled: true,
Insecure: insecureBool, Insecure: insecureBool,
ALPN: alpn, ALPN: alpn,
}, },
}, },
}, },
}, nil }}, nil
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/nitezs/sub2sing-box/constant" "github.com/nitezs/sub2sing-box/constant"
"github.com/nitezs/sub2sing-box/model" "github.com/nitezs/sub2sing-box/model"
"github.com/sagernet/sing-box/option"
) )
func ParseHysteria2(proxy string) (model.Outbound, error) { func ParseHysteria2(proxy string) (model.Outbound, error) {
@ -64,29 +65,31 @@ func ParseHysteria2(proxy string) (model.Outbound, error) {
remarks = strings.TrimSpace(remarks) remarks = strings.TrimSpace(remarks)
result := model.Outbound{ result := model.Outbound{
Type: "hysteria2", Outbound: option.Outbound{
Tag: strings.TrimSpace(remarks), Type: "hysteria2",
Hysteria2Options: model.Hysteria2OutboundOptions{ Tag: strings.TrimSpace(remarks),
ServerOptions: model.ServerOptions{ Hysteria2Options: option.Hysteria2OutboundOptions{
Server: server, ServerOptions: option.ServerOptions{
ServerPort: port, Server: server,
}, ServerPort: port,
Password: password,
OutboundTLSOptionsContainer: model.OutboundTLSOptionsContainer{
TLS: &model.OutboundTLSOptions{
Enabled: enableTLS,
Insecure: insecureBool,
ServerName: sni,
}, },
Password: password,
OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
TLS: &option.OutboundTLSOptions{
Enabled: enableTLS,
Insecure: insecureBool,
ServerName: sni,
},
},
Network: option.NetworkList(network),
}, },
Network: network,
}, },
} }
if pinSHA256 != "" { if pinSHA256 != "" {
result.Hysteria2Options.OutboundTLSOptionsContainer.TLS.Certificate = []string{pinSHA256} result.Hysteria2Options.OutboundTLSOptionsContainer.TLS.Certificate = []string{pinSHA256}
} }
if obfs != "" { if obfs != "" {
result.Hysteria2Options.Obfs = &model.Hysteria2Obfs{ result.Hysteria2Options.Obfs = &option.Hysteria2Obfs{
Type: obfs, Type: obfs,
Password: obfsPassword, Password: obfsPassword,
} }

View File

@ -8,6 +8,7 @@ import (
"github.com/nitezs/sub2sing-box/constant" "github.com/nitezs/sub2sing-box/constant"
"github.com/nitezs/sub2sing-box/model" "github.com/nitezs/sub2sing-box/model"
"github.com/nitezs/sub2sing-box/util" "github.com/nitezs/sub2sing-box/util"
"github.com/sagernet/sing-box/option"
) )
func ParseShadowsocks(proxy string) (model.Outbound, error) { func ParseShadowsocks(proxy string) (model.Outbound, error) {
@ -95,17 +96,19 @@ func ParseShadowsocks(proxy string) (model.Outbound, error) {
remarks = strings.TrimSpace(remarks) remarks = strings.TrimSpace(remarks)
result := model.Outbound{ result := model.Outbound{
Type: "shadowsocks", Outbound: option.Outbound{
Tag: remarks, Type: "shadowsocks",
ShadowsocksOptions: model.ShadowsocksOutboundOptions{ Tag: remarks,
ServerOptions: model.ServerOptions{ ShadowsocksOptions: option.ShadowsocksOutboundOptions{
Server: server, ServerOptions: option.ServerOptions{
ServerPort: port, Server: server,
ServerPort: port,
},
Method: method,
Password: password,
Plugin: plugin,
PluginOptions: options,
}, },
Method: method,
Password: password,
Plugin: plugin,
PluginOptions: options,
}, },
} }
return result, nil return result, nil

View File

@ -7,6 +7,7 @@ import (
"github.com/nitezs/sub2sing-box/constant" "github.com/nitezs/sub2sing-box/constant"
"github.com/nitezs/sub2sing-box/model" "github.com/nitezs/sub2sing-box/model"
"github.com/sagernet/sing-box/option"
) )
func ParseTrojan(proxy string) (model.Outbound, error) { func ParseTrojan(proxy string) (model.Outbound, error) {
@ -68,22 +69,22 @@ func ParseTrojan(proxy string) (model.Outbound, error) {
enableUTLS := fp != "" enableUTLS := fp != ""
result := model.Outbound{ result := model.Outbound{Outbound: option.Outbound{
Type: "trojan", Type: "trojan",
Tag: remarks, Tag: remarks,
TrojanOptions: model.TrojanOutboundOptions{ TrojanOptions: option.TrojanOutboundOptions{
ServerOptions: model.ServerOptions{ ServerOptions: option.ServerOptions{
Server: server, Server: server,
ServerPort: port, ServerPort: port,
}, },
Password: password, Password: password,
Network: network, Network: option.NetworkList(network),
}, },
} }}
if security == "xtls" || security == "tls" || sni != "" { if security == "xtls" || security == "tls" || sni != "" {
result.TrojanOptions.OutboundTLSOptionsContainer = model.OutboundTLSOptionsContainer{ result.TrojanOptions.OutboundTLSOptionsContainer = option.OutboundTLSOptionsContainer{
TLS: &model.OutboundTLSOptions{ TLS: &option.OutboundTLSOptions{
Enabled: true, Enabled: true,
ALPN: alpn, ALPN: alpn,
ServerName: sni, ServerName: sni,
@ -93,16 +94,16 @@ func ParseTrojan(proxy string) (model.Outbound, error) {
} }
if security == "reality" { if security == "reality" {
result.TrojanOptions.OutboundTLSOptionsContainer = model.OutboundTLSOptionsContainer{ result.TrojanOptions.OutboundTLSOptionsContainer = option.OutboundTLSOptionsContainer{
TLS: &model.OutboundTLSOptions{ TLS: &option.OutboundTLSOptions{
Enabled: true, Enabled: true,
ServerName: sni, ServerName: sni,
Reality: &model.OutboundRealityOptions{ Reality: &option.OutboundRealityOptions{
Enabled: true, Enabled: true,
PublicKey: pbk, PublicKey: pbk,
ShortID: sid, ShortID: sid,
}, },
UTLS: &model.OutboundUTLSOptions{ UTLS: &option.OutboundUTLSOptions{
Enabled: enableUTLS, Enabled: enableUTLS,
Fingerprint: fp, Fingerprint: fp,
}, },
@ -112,21 +113,21 @@ func ParseTrojan(proxy string) (model.Outbound, error) {
} }
if network == "ws" { if network == "ws" {
result.TrojanOptions.Transport = &model.V2RayTransportOptions{ result.TrojanOptions.Transport = &option.V2RayTransportOptions{
Type: "ws", Type: "ws",
WebsocketOptions: model.V2RayWebsocketOptions{ WebsocketOptions: option.V2RayWebsocketOptions{
Path: path, Path: path,
Headers: map[string]string{ Headers: map[string]option.Listable[string]{
"Host": host, "Host": {host},
}, },
}, },
} }
} }
if network == "http" { if network == "http" {
result.TrojanOptions.Transport = &model.V2RayTransportOptions{ result.TrojanOptions.Transport = &option.V2RayTransportOptions{
Type: "http", Type: "http",
HTTPOptions: model.V2RayHTTPOptions{ HTTPOptions: option.V2RayHTTPOptions{
Host: []string{host}, Host: []string{host},
Path: path, Path: path,
}, },
@ -134,16 +135,16 @@ func ParseTrojan(proxy string) (model.Outbound, error) {
} }
if network == "quic" { if network == "quic" {
result.TrojanOptions.Transport = &model.V2RayTransportOptions{ result.TrojanOptions.Transport = &option.V2RayTransportOptions{
Type: "quic", Type: "quic",
QUICOptions: model.V2RayQUICOptions{}, QUICOptions: option.V2RayQUICOptions{},
} }
} }
if network == "grpc" { if network == "grpc" {
result.TrojanOptions.Transport = &model.V2RayTransportOptions{ result.TrojanOptions.Transport = &option.V2RayTransportOptions{
Type: "grpc", Type: "grpc",
GRPCOptions: model.V2RayGRPCOptions{ GRPCOptions: option.V2RayGRPCOptions{
ServiceName: serviceName, ServiceName: serviceName,
}, },
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/nitezs/sub2sing-box/constant" "github.com/nitezs/sub2sing-box/constant"
"github.com/nitezs/sub2sing-box/model" "github.com/nitezs/sub2sing-box/model"
"github.com/sagernet/sing-box/option"
) )
func ParseVless(proxy string) (model.Outbound, error) { func ParseVless(proxy string) (model.Outbound, error) {
@ -59,22 +60,22 @@ func ParseVless(proxy string) (model.Outbound, error) {
} }
remarks = strings.TrimSpace(remarks) remarks = strings.TrimSpace(remarks)
result := model.Outbound{ result := model.Outbound{Outbound: option.Outbound{
Type: "vless", Type: "vless",
Tag: remarks, Tag: remarks,
VLESSOptions: model.VLESSOutboundOptions{ VLESSOptions: option.VLESSOutboundOptions{
ServerOptions: model.ServerOptions{ ServerOptions: option.ServerOptions{
Server: server, Server: server,
ServerPort: port, ServerPort: port,
}, },
UUID: uuid, UUID: uuid,
Flow: flow, Flow: flow,
}, },
} }}
if security == "tls" { if security == "tls" {
result.VLESSOptions.OutboundTLSOptionsContainer = model.OutboundTLSOptionsContainer{ result.VLESSOptions.OutboundTLSOptionsContainer = option.OutboundTLSOptionsContainer{
TLS: &model.OutboundTLSOptions{ TLS: &option.OutboundTLSOptions{
Enabled: true, Enabled: true,
ALPN: alpn, ALPN: alpn,
ServerName: sni, ServerName: sni,
@ -84,13 +85,13 @@ func ParseVless(proxy string) (model.Outbound, error) {
} }
if security == "reality" { if security == "reality" {
result.VLESSOptions.OutboundTLSOptionsContainer = model.OutboundTLSOptionsContainer{ result.VLESSOptions.OutboundTLSOptionsContainer = option.OutboundTLSOptionsContainer{
TLS: &model.OutboundTLSOptions{ TLS: &option.OutboundTLSOptions{
Enabled: true, Enabled: true,
ALPN: alpn, ALPN: alpn,
ServerName: sni, ServerName: sni,
Insecure: insecureBool, Insecure: insecureBool,
Reality: &model.OutboundRealityOptions{ Reality: &option.OutboundRealityOptions{
Enabled: true, Enabled: true,
PublicKey: pbk, PublicKey: pbk,
ShortID: sid, ShortID: sid,
@ -100,31 +101,31 @@ func ParseVless(proxy string) (model.Outbound, error) {
} }
if _type == "ws" { if _type == "ws" {
result.VLESSOptions.Transport = &model.V2RayTransportOptions{ result.VLESSOptions.Transport = &option.V2RayTransportOptions{
Type: "ws", Type: "ws",
WebsocketOptions: model.V2RayWebsocketOptions{ WebsocketOptions: option.V2RayWebsocketOptions{
Path: path, Path: path,
}, },
} }
if host != "" { if host != "" {
if result.VLESSOptions.Transport.WebsocketOptions.Headers == nil { if result.VLESSOptions.Transport.WebsocketOptions.Headers == nil {
result.VLESSOptions.Transport.WebsocketOptions.Headers = make(map[string]string) result.VLESSOptions.Transport.WebsocketOptions.Headers = make(map[string]option.Listable[string])
} }
result.VLESSOptions.Transport.WebsocketOptions.Headers["Host"] = host result.VLESSOptions.Transport.WebsocketOptions.Headers["Host"] = option.Listable[string]{host}
} }
} }
if _type == "quic" { if _type == "quic" {
result.VLESSOptions.Transport = &model.V2RayTransportOptions{ result.VLESSOptions.Transport = &option.V2RayTransportOptions{
Type: "quic", Type: "quic",
QUICOptions: model.V2RayQUICOptions{}, QUICOptions: option.V2RayQUICOptions{},
} }
} }
if _type == "grpc" { if _type == "grpc" {
result.VLESSOptions.Transport = &model.V2RayTransportOptions{ result.VLESSOptions.Transport = &option.V2RayTransportOptions{
Type: "grpc", Type: "grpc",
GRPCOptions: model.V2RayGRPCOptions{ GRPCOptions: option.V2RayGRPCOptions{
ServiceName: serviceName, ServiceName: serviceName,
}, },
} }
@ -139,16 +140,16 @@ func ParseVless(proxy string) (model.Outbound, error) {
Message: err.Error(), Message: err.Error(),
} }
} }
result.VLESSOptions.Transport = &model.V2RayTransportOptions{ result.VLESSOptions.Transport = &option.V2RayTransportOptions{
Type: "http", Type: "http",
HTTPOptions: model.V2RayHTTPOptions{ HTTPOptions: option.V2RayHTTPOptions{
Host: strings.Split(hosts, ","), Host: strings.Split(hosts, ","),
}, },
} }
} }
if enableUTLS { if enableUTLS {
result.VLESSOptions.OutboundTLSOptionsContainer.TLS.UTLS = &model.OutboundUTLSOptions{ result.VLESSOptions.OutboundTLSOptionsContainer.TLS.UTLS = &option.OutboundUTLSOptions{
Enabled: enableUTLS, Enabled: enableUTLS,
Fingerprint: fp, Fingerprint: fp,
} }

View File

@ -9,6 +9,7 @@ import (
"github.com/nitezs/sub2sing-box/constant" "github.com/nitezs/sub2sing-box/constant"
"github.com/nitezs/sub2sing-box/model" "github.com/nitezs/sub2sing-box/model"
"github.com/nitezs/sub2sing-box/util" "github.com/nitezs/sub2sing-box/util"
"github.com/sagernet/sing-box/option"
) )
func ParseVmess(proxy string) (model.Outbound, error) { func ParseVmess(proxy string) (model.Outbound, error) {
@ -64,16 +65,18 @@ func ParseVmess(proxy string) (model.Outbound, error) {
} }
result := model.Outbound{ result := model.Outbound{
Type: "vmess", Outbound: option.Outbound{
Tag: name, Type: "vmess",
VMessOptions: model.VMessOutboundOptions{ Tag: name,
ServerOptions: model.ServerOptions{ VMessOptions: option.VMessOutboundOptions{
Server: vmess.Add, ServerOptions: option.ServerOptions{
ServerPort: port, Server: vmess.Add,
ServerPort: port,
},
UUID: vmess.Id,
AlterId: aid,
Security: vmess.Scy,
}, },
UUID: vmess.Id,
AlterId: aid,
Security: vmess.Scy,
}, },
} }
@ -84,10 +87,10 @@ func ParseVmess(proxy string) (model.Outbound, error) {
} else { } else {
alpn = nil alpn = nil
} }
result.VMessOptions.OutboundTLSOptionsContainer = model.OutboundTLSOptionsContainer{ result.VMessOptions.OutboundTLSOptionsContainer = option.OutboundTLSOptionsContainer{
TLS: &model.OutboundTLSOptions{ TLS: &option.OutboundTLSOptions{
Enabled: true, Enabled: true,
UTLS: &model.OutboundUTLSOptions{ UTLS: &option.OutboundUTLSOptions{
Fingerprint: vmess.Fp, Fingerprint: vmess.Fp,
}, },
ALPN: alpn, ALPN: alpn,
@ -95,7 +98,7 @@ func ParseVmess(proxy string) (model.Outbound, error) {
}, },
} }
if vmess.Fp != "" { if vmess.Fp != "" {
result.VMessOptions.OutboundTLSOptionsContainer.TLS.UTLS = &model.OutboundUTLSOptions{ result.VMessOptions.OutboundTLSOptionsContainer.TLS.UTLS = &option.OutboundUTLSOptions{
Enabled: true, Enabled: true,
Fingerprint: vmess.Fp, Fingerprint: vmess.Fp,
} }
@ -109,42 +112,42 @@ func ParseVmess(proxy string) (model.Outbound, error) {
if vmess.Host == "" { if vmess.Host == "" {
vmess.Host = vmess.Add vmess.Host = vmess.Add
} }
result.VMessOptions.Transport = &model.V2RayTransportOptions{ result.VMessOptions.Transport = &option.V2RayTransportOptions{
Type: "ws", Type: "ws",
WebsocketOptions: model.V2RayWebsocketOptions{ WebsocketOptions: option.V2RayWebsocketOptions{
Path: vmess.Path, Path: vmess.Path,
Headers: map[string]string{ Headers: map[string]option.Listable[string]{
"Host": vmess.Host, "Host": {vmess.Host},
}, },
}, },
} }
} }
if vmess.Net == "quic" { if vmess.Net == "quic" {
quic := model.V2RayQUICOptions{} quic := option.V2RayQUICOptions{}
result.VMessOptions.Transport = &model.V2RayTransportOptions{ result.VMessOptions.Transport = &option.V2RayTransportOptions{
Type: "quic", Type: "quic",
QUICOptions: quic, QUICOptions: quic,
} }
} }
if vmess.Net == "grpc" { if vmess.Net == "grpc" {
grpc := model.V2RayGRPCOptions{ grpc := option.V2RayGRPCOptions{
ServiceName: vmess.Path, ServiceName: vmess.Path,
PermitWithoutStream: true, PermitWithoutStream: true,
} }
result.VMessOptions.Transport = &model.V2RayTransportOptions{ result.VMessOptions.Transport = &option.V2RayTransportOptions{
Type: "grpc", Type: "grpc",
GRPCOptions: grpc, GRPCOptions: grpc,
} }
} }
if vmess.Net == "h2" { if vmess.Net == "h2" {
httpOps := model.V2RayHTTPOptions{ httpOps := option.V2RayHTTPOptions{
Host: strings.Split(vmess.Host, ","), Host: strings.Split(vmess.Host, ","),
Path: vmess.Path, Path: vmess.Path,
} }
result.VMessOptions.Transport = &model.V2RayTransportOptions{ result.VMessOptions.Transport = &option.V2RayTransportOptions{
Type: "http", Type: "http",
HTTPOptions: httpOps, HTTPOptions: httpOps,
} }

View File

@ -78,7 +78,6 @@
], ],
"outbounds": [ "outbounds": [
{ {
"interrupt_exist_connections": true,
"outbounds": ["<all-proxy-tags>", "direct"], "outbounds": ["<all-proxy-tags>", "direct"],
"tag": "default", "tag": "default",
"type": "selector" "type": "selector"