forked from mirror/serenity
Replace template.extra_groups.per_subscription
with target
This commit is contained in:
parent
53227cd88a
commit
7f454a1133
@ -4,6 +4,7 @@
|
||||
{
|
||||
"name": "",
|
||||
"extend": "",
|
||||
|
||||
// Global
|
||||
|
||||
"log": {},
|
||||
@ -12,6 +13,7 @@
|
||||
"disable_traffic_bypass": false,
|
||||
"disable_rule_set": false,
|
||||
"remote_resolve": false,
|
||||
|
||||
// DNS
|
||||
|
||||
"dns": "",
|
||||
@ -19,6 +21,7 @@
|
||||
"enable_fakeip": false,
|
||||
"pre_dns_rules": [],
|
||||
"custom_dns_rules": [],
|
||||
|
||||
// Inbound
|
||||
|
||||
"inbounds": [],
|
||||
@ -27,14 +30,14 @@
|
||||
"disable_system_proxy": false,
|
||||
"custom_tun": {},
|
||||
"custom_mixed": {},
|
||||
|
||||
// Outbound
|
||||
|
||||
"extra_groups": [
|
||||
{
|
||||
"tag": "",
|
||||
"type": "",
|
||||
"exclude_outbounds": false,
|
||||
"per_subscription": false,
|
||||
"target": "",
|
||||
"tag_per_subscription": "",
|
||||
"filter": "",
|
||||
"exclude": "",
|
||||
@ -42,13 +45,13 @@
|
||||
"custom_urltest": {}
|
||||
}
|
||||
],
|
||||
"generate_global_urltest": false,
|
||||
"direct_tag": "",
|
||||
"default_tag": "",
|
||||
"urltest_tag": "",
|
||||
"custom_direct": {},
|
||||
"custom_selector": {},
|
||||
"custom_urltest": {},
|
||||
|
||||
// Route
|
||||
|
||||
"pre_rules": [],
|
||||
@ -58,6 +61,7 @@
|
||||
"custom_geosite": {},
|
||||
"custom_rule_set": [],
|
||||
"post_rule_set": [],
|
||||
|
||||
// Experimental
|
||||
|
||||
"disable_cache_file": false,
|
||||
@ -66,6 +70,7 @@
|
||||
"clash_mode_global": "",
|
||||
"clash_mode_direct": "",
|
||||
"custom_clash_api": {},
|
||||
|
||||
// Debug
|
||||
|
||||
"pprof_listen": "",
|
||||
@ -190,17 +195,17 @@ Tag of the group outbound.
|
||||
|
||||
Type of the group outbound.
|
||||
|
||||
#### extra_groups.exclude_outbounds
|
||||
#### extra_groups.target
|
||||
|
||||
Only include subscriptions but not custom outbounds.
|
||||
|
||||
#### extra_groups.per_subscription
|
||||
|
||||
Generate a internal group for every subscription instead of a global group.
|
||||
| Value | Description |
|
||||
|----------------|------------------------------------------------------------|
|
||||
| `default` | No additional behaviors. |
|
||||
| `global` | Generate a group and add it to default selector. |
|
||||
| `subscription` | Generate a internal group for every subscription selector. |
|
||||
|
||||
#### extra_groups.tag_per_subscription
|
||||
|
||||
Tag for every new subscription internal group.
|
||||
Tag for every new subscription internal group when `target` is `subscription`.
|
||||
|
||||
`{{ .tag }} ({{ .subscription_name }})` is used by default.
|
||||
|
||||
@ -220,10 +225,6 @@ Custom [Selector](https://sing-box.sagernet.org/configuration/outbound/selector/
|
||||
|
||||
Custom [URLTest](https://sing-box.sagernet.org/configuration/outbound/urltest/) template.
|
||||
|
||||
#### generate_global_urltest
|
||||
|
||||
Generate a global `URLTest` outbound with all global outbounds.
|
||||
|
||||
#### direct_tag
|
||||
|
||||
Custom direct outbound tag.
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
C "github.com/sagernet/serenity/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-dns"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
)
|
||||
|
||||
@ -129,8 +130,7 @@ func (t Template) DisableIPv6() bool {
|
||||
|
||||
type ExtraGroup struct {
|
||||
Tag string `json:"tag,omitempty"`
|
||||
ExcludeOutbounds bool `json:"exclude_outbounds,omitempty"`
|
||||
PerSubscription bool `json:"per_subscription,omitempty"`
|
||||
Target ExtraGroupTarget `json:"target,omitempty"`
|
||||
TagPerSubscription string `json:"tag_per_subscription,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Filter option.Listable[string] `json:"filter,omitempty"`
|
||||
@ -138,3 +138,47 @@ type ExtraGroup struct {
|
||||
CustomSelector *option.SelectorOutboundOptions `json:"custom_selector,omitempty"`
|
||||
CustomURLTest *option.URLTestOutboundOptions `json:"custom_urltest,omitempty"`
|
||||
}
|
||||
|
||||
type ExtraGroupTarget uint8
|
||||
|
||||
const (
|
||||
ExtraGroupTargetDefault ExtraGroupTarget = iota
|
||||
ExtraGroupTargetGlobal
|
||||
ExtraGroupTargetSubscription
|
||||
)
|
||||
|
||||
func (t ExtraGroupTarget) String() string {
|
||||
switch t {
|
||||
case ExtraGroupTargetDefault:
|
||||
return "default"
|
||||
case ExtraGroupTargetGlobal:
|
||||
return "global"
|
||||
case ExtraGroupTargetSubscription:
|
||||
return "subscription"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func (t ExtraGroupTarget) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.String())
|
||||
}
|
||||
|
||||
func (t *ExtraGroupTarget) UnmarshalJSON(bytes []byte) error {
|
||||
var stringValue string
|
||||
err := json.Unmarshal(bytes, &stringValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch stringValue {
|
||||
case "default":
|
||||
*t = ExtraGroupTargetDefault
|
||||
case "global":
|
||||
*t = ExtraGroupTargetGlobal
|
||||
case "subscription":
|
||||
*t = ExtraGroupTargetSubscription
|
||||
default:
|
||||
return E.New("unknown extra group target: ", stringValue)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -6,15 +6,16 @@ import (
|
||||
"text/template"
|
||||
|
||||
M "github.com/sagernet/serenity/common/metadata"
|
||||
"github.com/sagernet/serenity/option"
|
||||
"github.com/sagernet/serenity/subscription"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
boxOption "github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
)
|
||||
|
||||
func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options, outbounds [][]option.Outbound, subscriptions []*subscription.Subscription) error {
|
||||
func (t *Template) renderOutbounds(metadata M.Metadata, options *boxOption.Options, outbounds [][]boxOption.Outbound, subscriptions []*subscription.Subscription) error {
|
||||
defaultTag := t.DefaultTag
|
||||
if defaultTag == "" {
|
||||
defaultTag = DefaultDefaultTag
|
||||
@ -28,7 +29,7 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
if blockTag == "" {
|
||||
blockTag = DefaultBlockTag
|
||||
}
|
||||
options.Outbounds = []option.Outbound{
|
||||
options.Outbounds = []boxOption.Outbound{
|
||||
{
|
||||
Tag: directTag,
|
||||
Type: C.TypeDirect,
|
||||
@ -52,26 +53,22 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
if urlTestTag == "" {
|
||||
urlTestTag = DefaultURLTestTag
|
||||
}
|
||||
outboundToString := func(it option.Outbound) string {
|
||||
outboundToString := func(it boxOption.Outbound) string {
|
||||
return it.Tag
|
||||
}
|
||||
var (
|
||||
globalOutbounds []option.Outbound
|
||||
globalOutboundTags []string
|
||||
)
|
||||
var globalOutboundTags []string
|
||||
if len(outbounds) > 0 {
|
||||
for _, outbound := range outbounds {
|
||||
options.Outbounds = append(options.Outbounds, outbound...)
|
||||
}
|
||||
globalOutbounds = common.Map(outbounds, func(it []option.Outbound) option.Outbound {
|
||||
return it[0]
|
||||
globalOutboundTags = common.Map(outbounds, func(it []boxOption.Outbound) string {
|
||||
return it[0].Tag
|
||||
})
|
||||
globalOutboundTags = common.Map(globalOutbounds, outboundToString)
|
||||
}
|
||||
|
||||
var (
|
||||
allGroups []option.Outbound
|
||||
allGroupOutbounds []option.Outbound
|
||||
allGroups []boxOption.Outbound
|
||||
allGroupOutbounds []boxOption.Outbound
|
||||
groupTags []string
|
||||
)
|
||||
|
||||
@ -79,11 +76,11 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
if len(it.Servers) == 0 {
|
||||
continue
|
||||
}
|
||||
joinOutbounds := common.Map(it.Servers, func(it option.Outbound) string {
|
||||
joinOutbounds := common.Map(it.Servers, func(it boxOption.Outbound) string {
|
||||
return it.Tag
|
||||
})
|
||||
if it.GenerateSelector {
|
||||
selectorOutbound := option.Outbound{
|
||||
selectorOutbound := boxOption.Outbound{
|
||||
Type: C.TypeSelector,
|
||||
Tag: it.Name,
|
||||
SelectorOptions: common.PtrValueOrDefault(it.CustomSelector),
|
||||
@ -101,7 +98,7 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
} else {
|
||||
urltestTag = it.Name + " - URLTest"
|
||||
}
|
||||
urltestOutbound := option.Outbound{
|
||||
urltestOutbound := boxOption.Outbound{
|
||||
Type: C.TypeURLTest,
|
||||
Tag: urltestTag,
|
||||
URLTestOptions: common.PtrValueOrDefault(t.CustomURLTest),
|
||||
@ -116,10 +113,11 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
allGroupOutbounds = append(allGroupOutbounds, it.Servers...)
|
||||
}
|
||||
|
||||
globalOutbounds = append(globalOutbounds, allGroups...)
|
||||
globalOutbounds = append(globalOutbounds, allGroupOutbounds...)
|
||||
|
||||
allExtraGroups := make(map[string][]option.Outbound)
|
||||
var (
|
||||
defaultGroups []boxOption.Outbound
|
||||
globalGroups []boxOption.Outbound
|
||||
subscriptionGroups = make(map[string][]boxOption.Outbound)
|
||||
)
|
||||
for _, extraGroup := range t.groups {
|
||||
myFilter := func(outboundTag string) bool {
|
||||
if len(extraGroup.filter) > 0 {
|
||||
@ -138,19 +136,14 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
}
|
||||
return true
|
||||
}
|
||||
if !extraGroup.PerSubscription {
|
||||
var extraTags []string
|
||||
if extraGroup.ExcludeOutbounds {
|
||||
extraTags = common.Filter(common.FlatMap(subscriptions, func(it *subscription.Subscription) []string {
|
||||
return common.Map(it.Servers, outboundToString)
|
||||
}), myFilter)
|
||||
} else {
|
||||
extraTags = common.Filter(common.Map(globalOutbounds, outboundToString), myFilter)
|
||||
}
|
||||
if extraGroup.Target != option.ExtraGroupTargetSubscription {
|
||||
extraTags := common.Filter(common.FlatMap(subscriptions, func(it *subscription.Subscription) []string {
|
||||
return common.Map(it.Servers, outboundToString)
|
||||
}), myFilter)
|
||||
if len(extraTags) == 0 {
|
||||
continue
|
||||
}
|
||||
groupOutbound := option.Outbound{
|
||||
groupOutbound := boxOption.Outbound{
|
||||
Tag: extraGroup.Tag,
|
||||
Type: extraGroup.Type,
|
||||
SelectorOptions: common.PtrValueOrDefault(extraGroup.CustomSelector),
|
||||
@ -162,7 +155,11 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
case C.TypeURLTest:
|
||||
groupOutbound.URLTestOptions.Outbounds = append(groupOutbound.URLTestOptions.Outbounds, extraTags...)
|
||||
}
|
||||
allExtraGroups[""] = append(allExtraGroups[""], groupOutbound)
|
||||
if extraGroup.Target == option.ExtraGroupTargetDefault {
|
||||
defaultGroups = append(defaultGroups, groupOutbound)
|
||||
} else {
|
||||
globalGroups = append(globalGroups, groupOutbound)
|
||||
}
|
||||
} else {
|
||||
tmpl := template.New("tag")
|
||||
if extraGroup.TagPerSubscription != "" {
|
||||
@ -174,26 +171,6 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
common.Must1(tmpl.Parse("{{ .tag }} ({{ .subscription_name }})"))
|
||||
}
|
||||
var outboundTags []string
|
||||
if !extraGroup.ExcludeOutbounds {
|
||||
outboundTags = common.Filter(common.FlatMap(outbounds, func(it []option.Outbound) []string {
|
||||
return common.Map(it, outboundToString)
|
||||
}), myFilter)
|
||||
}
|
||||
if len(outboundTags) > 0 {
|
||||
groupOutbound := option.Outbound{
|
||||
Tag: extraGroup.Tag,
|
||||
Type: extraGroup.Type,
|
||||
SelectorOptions: common.PtrValueOrDefault(extraGroup.CustomSelector),
|
||||
URLTestOptions: common.PtrValueOrDefault(extraGroup.CustomURLTest),
|
||||
}
|
||||
switch extraGroup.Type {
|
||||
case C.TypeSelector:
|
||||
groupOutbound.SelectorOptions.Outbounds = append(groupOutbound.SelectorOptions.Outbounds, outboundTags...)
|
||||
case C.TypeURLTest:
|
||||
groupOutbound.URLTestOptions.Outbounds = append(groupOutbound.URLTestOptions.Outbounds, outboundTags...)
|
||||
}
|
||||
allExtraGroups[""] = append(allExtraGroups[""], groupOutbound)
|
||||
}
|
||||
for _, it := range subscriptions {
|
||||
subscriptionTags := common.Filter(common.Map(it.Servers, outboundToString), myFilter)
|
||||
if len(subscriptionTags) == 0 {
|
||||
@ -213,7 +190,7 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
}
|
||||
tagPerSubscription = buffer.String()
|
||||
}
|
||||
groupOutboundPerSubscription := option.Outbound{
|
||||
groupOutboundPerSubscription := boxOption.Outbound{
|
||||
Tag: tagPerSubscription,
|
||||
Type: extraGroup.Type,
|
||||
SelectorOptions: common.PtrValueOrDefault(extraGroup.CustomSelector),
|
||||
@ -225,20 +202,21 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
case C.TypeURLTest:
|
||||
groupOutboundPerSubscription.URLTestOptions.Outbounds = append(groupOutboundPerSubscription.URLTestOptions.Outbounds, subscriptionTags...)
|
||||
}
|
||||
allExtraGroups[it.Name] = append(allExtraGroups[it.Name], groupOutboundPerSubscription)
|
||||
subscriptionGroups[it.Name] = append(subscriptionGroups[it.Name], groupOutboundPerSubscription)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
options.Outbounds = append(options.Outbounds, allGroups...)
|
||||
|
||||
defaultExtraGroupOutbounds := allExtraGroups[""]
|
||||
if len(defaultExtraGroupOutbounds) > 0 {
|
||||
options.Outbounds = append(options.Outbounds, defaultExtraGroupOutbounds...)
|
||||
options.Outbounds = groupJoin(options.Outbounds, defaultTag, false, common.Map(defaultExtraGroupOutbounds, outboundToString)...)
|
||||
if len(defaultGroups) > 0 {
|
||||
options.Outbounds = append(options.Outbounds, defaultGroups...)
|
||||
}
|
||||
if len(globalGroups) > 0 {
|
||||
options.Outbounds = append(options.Outbounds, globalGroups...)
|
||||
options.Outbounds = groupJoin(options.Outbounds, defaultTag, false, common.Map(globalGroups, outboundToString)...)
|
||||
}
|
||||
for _, it := range subscriptions {
|
||||
extraGroupOutboundsForSubscription := allExtraGroups[it.Name]
|
||||
extraGroupOutboundsForSubscription := subscriptionGroups[it.Name]
|
||||
if len(extraGroupOutboundsForSubscription) > 0 {
|
||||
options.Outbounds = append(options.Outbounds, extraGroupOutboundsForSubscription...)
|
||||
options.Outbounds = groupJoin(options.Outbounds, it.Name, true, common.Map(extraGroupOutboundsForSubscription, outboundToString)...)
|
||||
@ -251,8 +229,8 @@ func (t *Template) renderOutbounds(metadata M.Metadata, options *option.Options,
|
||||
return nil
|
||||
}
|
||||
|
||||
func groupJoin(outbounds []option.Outbound, groupTag string, appendFront bool, groupOutbounds ...string) []option.Outbound {
|
||||
groupIndex := common.Index(outbounds, func(it option.Outbound) bool {
|
||||
func groupJoin(outbounds []boxOption.Outbound, groupTag string, appendFront bool, groupOutbounds ...string) []boxOption.Outbound {
|
||||
groupIndex := common.Index(outbounds, func(it boxOption.Outbound) bool {
|
||||
return it.Tag == groupTag
|
||||
})
|
||||
if groupIndex == -1 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user