/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package configurator import ( "strings" ) import ( gxset "github.com/dubbogo/gost/container/set" gxnet "github.com/dubbogo/gost/net" ) import ( "github.com/apache/dubbo-go/common" "github.com/apache/dubbo-go/common/constant" "github.com/apache/dubbo-go/common/extension" "github.com/apache/dubbo-go/config_center" ) func init() { extension.SetDefaultConfigurator(newConfigurator) } func newConfigurator(url *common.URL) config_center.Configurator { return &overrideConfigurator{configuratorUrl: url} } type overrideConfigurator struct { configuratorUrl *common.URL } func (c *overrideConfigurator) GetUrl() *common.URL { return c.configuratorUrl } func (c *overrideConfigurator) Configure(url *common.URL) { // remove configuratorUrl some param that can not be configured if c.configuratorUrl.GetParam(constant.ENABLED_KEY, "true") == "false" || len(c.configuratorUrl.Location) == 0 { return } // branch for version 2.7.x apiVersion := c.configuratorUrl.GetParam(constant.CONFIG_VERSION_KEY, "") if len(apiVersion) != 0 { currentSide := url.GetParam(constant.SIDE_KEY, "") configuratorSide := c.configuratorUrl.GetParam(constant.SIDE_KEY, "") if currentSide == configuratorSide && common.DubboRole[common.CONSUMER] == currentSide && c.configuratorUrl.Port == "0" { localIP, _ := gxnet.GetLocalIP() c.configureIfMatch(localIP, url) } else if currentSide == configuratorSide && common.DubboRole[common.PROVIDER] == currentSide && c.configuratorUrl.Port == url.Port { c.configureIfMatch(url.Ip, url) } } else { // branch for version 2.6.x and less c.configureDeprecated(url) } } func (c *overrideConfigurator) configureIfMatchInternal(url *common.URL) { configApp := c.configuratorUrl.GetParam(constant.APPLICATION_KEY, c.configuratorUrl.Username) currentApp := url.GetParam(constant.APPLICATION_KEY, url.Username) if len(configApp) == 0 || constant.ANY_VALUE == configApp || configApp == currentApp { conditionKeys := gxset.NewSet() conditionKeys.Add(constant.CATEGORY_KEY) conditionKeys.Add(constant.CHECK_KEY) conditionKeys.Add(constant.ENABLED_KEY) conditionKeys.Add(constant.GROUP_KEY) conditionKeys.Add(constant.VERSION_KEY) conditionKeys.Add(constant.APPLICATION_KEY) conditionKeys.Add(constant.SIDE_KEY) conditionKeys.Add(constant.CONFIG_VERSION_KEY) conditionKeys.Add(constant.COMPATIBLE_CONFIG_KEY) returnUrl := false c.configuratorUrl.RangeParams(func(k, _ string) bool { value := c.configuratorUrl.GetParam(k, "") if strings.HasPrefix(k, "~") || k == constant.APPLICATION_KEY || k == constant.SIDE_KEY { conditionKeys.Add(k) if len(value) != 0 && value != constant.ANY_VALUE && value != url.GetParam(strings.TrimPrefix(k, "~"), "") { returnUrl = true return false } } return true }) if returnUrl { return } configUrl := c.configuratorUrl.CloneExceptParams(conditionKeys) url.SetParams(configUrl.GetParams()) } } // configureIfMatch translate from java, compatible rules in java func (c *overrideConfigurator) configureIfMatch(host string, url *common.URL) { if constant.ANYHOST_VALUE == c.configuratorUrl.Ip || host == c.configuratorUrl.Ip { providers := c.configuratorUrl.GetParam(constant.OVERRIDE_PROVIDERS_KEY, "") if len(providers) == 0 || strings.Contains(providers, url.Location) || strings.Contains(providers, constant.ANYHOST_VALUE) { c.configureIfMatchInternal(url) } } } func (c *overrideConfigurator) configureDeprecated(url *common.URL) { // If override url has port, means it is a provider address. We want to control a specific provider with this override url, it may take effect on the specific provider instance or on consumers holding this provider instance. if c.configuratorUrl.Port != "0" { if url.Port == c.configuratorUrl.Port { c.configureIfMatch(url.Ip, url) } } else { // override url don't have a port, means the ip override url specify is a consumer address or 0.0.0.0 // 1.If it is a consumer ip address, the intention is to control a specific consumer instance, it must takes effect at the consumer side, any provider received this override url should ignore; // 2.If the ip is 0.0.0.0, this override url can be used on consumer, and also can be used on provider if url.GetParam(constant.SIDE_KEY, "") == common.DubboRole[common.CONSUMER] { localIP, _ := gxnet.GetLocalIP() c.configureIfMatch(localIP, url) } else { c.configureIfMatch(constant.ANYHOST_VALUE, url) } } }