github.com/v2fly/v2ray-core/v5@v5.16.2-0.20240507031116-8191faa6e095/infra/conf/synthetic/router/router.go (about) 1 package router 2 3 //go:generate go run github.com/v2fly/v2ray-core/v5/common/errors/errorgen 4 5 import ( 6 "context" 7 "encoding/json" 8 "strings" 9 10 "github.com/golang/protobuf/proto" 11 12 "github.com/v2fly/v2ray-core/v5/app/router" 13 "github.com/v2fly/v2ray-core/v5/common/platform" 14 "github.com/v2fly/v2ray-core/v5/common/serial" 15 "github.com/v2fly/v2ray-core/v5/infra/conf/cfgcommon" 16 "github.com/v2fly/v2ray-core/v5/infra/conf/geodata" 17 rule2 "github.com/v2fly/v2ray-core/v5/infra/conf/rule" 18 ) 19 20 type RouterRulesConfig struct { // nolint: revive 21 RuleList []json.RawMessage `json:"rules"` 22 DomainStrategy string `json:"domainStrategy"` 23 } 24 25 // StrategyConfig represents a strategy config 26 type StrategyConfig struct { 27 Type string `json:"type"` 28 Settings *json.RawMessage `json:"settings"` 29 } 30 31 type BalancingRule struct { 32 Tag string `json:"tag"` 33 Selectors cfgcommon.StringList `json:"selector"` 34 Strategy StrategyConfig `json:"strategy"` 35 FallbackTag string `json:"fallbackTag"` 36 } 37 38 // Build builds the balancing rule 39 func (r *BalancingRule) Build() (*router.BalancingRule, error) { 40 if r.Tag == "" { 41 return nil, newError("empty balancer tag") 42 } 43 if len(r.Selectors) == 0 { 44 return nil, newError("empty selector list") 45 } 46 47 var strategy string 48 switch strings.ToLower(r.Strategy.Type) { 49 case strategyRandom, "": 50 r.Strategy.Type = strategyRandom 51 strategy = strategyRandom 52 case strategyLeastLoad: 53 strategy = strategyLeastLoad 54 case strategyLeastPing: 55 strategy = "leastping" 56 default: 57 return nil, newError("unknown balancing strategy: " + r.Strategy.Type) 58 } 59 60 settings := []byte("{}") 61 if r.Strategy.Settings != nil { 62 settings = ([]byte)(*r.Strategy.Settings) 63 } 64 rawConfig, err := strategyConfigLoader.LoadWithID(settings, r.Strategy.Type) 65 if err != nil { 66 return nil, newError("failed to parse to strategy config.").Base(err) 67 } 68 var ts proto.Message 69 if builder, ok := rawConfig.(cfgcommon.Buildable); ok { 70 ts, err = builder.Build() 71 if err != nil { 72 return nil, err 73 } 74 } 75 76 return &router.BalancingRule{ 77 Strategy: strategy, 78 StrategySettings: serial.ToTypedMessage(ts), 79 FallbackTag: r.FallbackTag, 80 OutboundSelector: r.Selectors, 81 Tag: r.Tag, 82 }, nil 83 } 84 85 type RouterConfig struct { // nolint: revive 86 Settings *RouterRulesConfig `json:"settings"` // Deprecated 87 RuleList []json.RawMessage `json:"rules"` 88 DomainStrategy *string `json:"domainStrategy"` 89 Balancers []*BalancingRule `json:"balancers"` 90 91 DomainMatcher string `json:"domainMatcher"` 92 93 cfgctx context.Context 94 } 95 96 func (c *RouterConfig) getDomainStrategy() router.DomainStrategy { 97 ds := "" 98 if c.DomainStrategy != nil { 99 ds = *c.DomainStrategy 100 } else if c.Settings != nil { 101 ds = c.Settings.DomainStrategy 102 } 103 104 switch strings.ToLower(ds) { 105 case "alwaysip", "always_ip", "always-ip": 106 return router.DomainStrategy_UseIp 107 case "ipifnonmatch", "ip_if_non_match", "ip-if-non-match": 108 return router.DomainStrategy_IpIfNonMatch 109 case "ipondemand", "ip_on_demand", "ip-on-demand": 110 return router.DomainStrategy_IpOnDemand 111 default: 112 return router.DomainStrategy_AsIs 113 } 114 } 115 116 func (c *RouterConfig) BuildV5(ctx context.Context) (*router.Config, error) { 117 c.cfgctx = ctx 118 return c.Build() 119 } 120 121 func (c *RouterConfig) Build() (*router.Config, error) { 122 config := new(router.Config) 123 config.DomainStrategy = c.getDomainStrategy() 124 125 if c.cfgctx == nil { 126 c.cfgctx = cfgcommon.NewConfigureLoadingContext(context.Background()) 127 128 geoloadername := platform.NewEnvFlag("v2ray.conf.geoloader").GetValue(func() string { 129 return "standard" 130 }) 131 132 if loader, err := geodata.GetGeoDataLoader(geoloadername); err == nil { 133 cfgcommon.SetGeoDataLoader(c.cfgctx, loader) 134 } else { 135 return nil, newError("unable to create geo data loader ").Base(err) 136 } 137 } 138 139 var rawRuleList []json.RawMessage 140 if c != nil { 141 rawRuleList = c.RuleList 142 if c.Settings != nil { 143 c.RuleList = append(c.RuleList, c.Settings.RuleList...) 144 rawRuleList = c.RuleList 145 } 146 } 147 148 for _, rawRule := range rawRuleList { 149 rule, err := rule2.ParseRule(c.cfgctx, rawRule) 150 if err != nil { 151 return nil, err 152 } 153 154 if rule.DomainMatcher == "" { 155 rule.DomainMatcher = c.DomainMatcher 156 } 157 158 config.Rule = append(config.Rule, rule) 159 } 160 for _, rawBalancer := range c.Balancers { 161 balancer, err := rawBalancer.Build() 162 if err != nil { 163 return nil, err 164 } 165 config.BalancingRule = append(config.BalancingRule, balancer) 166 } 167 return config, nil 168 }