diff --git a/common/constant/key.go b/common/constant/key.go index ff371d08c669df07f24a3e81e0be0a29a6b17ddd..0c0c91f39e3134eeebe83524850e10f24f5bb1fb 100644 --- a/common/constant/key.go +++ b/common/constant/key.go @@ -100,6 +100,9 @@ const ( const ( CONFIG_NAMESPACE_KEY = "config.namespace" + CONFIG_GROUP_KEY = "config.group" + CONFIG_CLUSTER_KEY = "config.cluster" + CONFIG_CHECK_KEY = "config.check" CONFIG_TIMEOUT_KET = "config.timeout" CONFIG_VERSION_KEY = "configVersion" COMPATIBLE_CONFIG_KEY = "compatible_config" diff --git a/config_center/apollo/factory.go b/config_center/apollo/factory.go new file mode 100644 index 0000000000000000000000000000000000000000..98acfe7177bf0633f901906af52636bf80fe84f3 --- /dev/null +++ b/config_center/apollo/factory.go @@ -0,0 +1,53 @@ +/* +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 apollo + +import ( + "sync" +) + +import ( + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/extension" + "github.com/apache/dubbo-go/config_center" + "github.com/apache/dubbo-go/config_center/parser" +) + +func init() { + extension.SetConfigCenterFactory("apollo", func() config_center.DynamicConfigurationFactory { return &apolloDynamicConfigurationFactory{} }) +} + +type apolloDynamicConfigurationFactory struct { +} + +var once sync.Once +var dynamicConfiguration *apolloDynamicConfiguration + +func (f *apolloDynamicConfigurationFactory) GetDynamicConfiguration(url *common.URL) (config_center.DynamicConfiguration, error) { + var err error + once.Do(func() { + dynamicConfiguration, err = newApolloDynamicConfiguration(url) + }) + if err != nil { + return nil, err + } + dynamicConfiguration.SetParser(&parser.DefaultConfigurationParser{}) + return dynamicConfiguration, err + +} + diff --git a/config_center/apollo/impl.go b/config_center/apollo/impl.go new file mode 100644 index 0000000000000000000000000000000000000000..e98785cbe35dc194b2e6430f0568a69339a5fae3 --- /dev/null +++ b/config_center/apollo/impl.go @@ -0,0 +1,191 @@ +/* +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 apollo + +import ( + "os" + "strconv" + "strings" + "sync" + + "github.com/apache/dubbo-go/common" + "github.com/apache/dubbo-go/common/constant" + "github.com/apache/dubbo-go/config_center" + "github.com/apache/dubbo-go/config_center/parser" + "github.com/apache/dubbo-go/remoting" + + "github.com/zouyx/agollo" +) + +const ( + apolloEnvKey = "env"; + apolloAddrKey = "apollo.meta"; + apolloClusterKey = "apollo.cluster"; + apolloProtocolPrefix = "http://"; +) + +type apolloDynamicConfiguration struct { + url *common.URL + + listeners sync.Map + appConf *agollo.AppConfig + parser parser.ConfigurationParser +} + +func newApolloDynamicConfiguration(url *common.URL) (*apolloDynamicConfiguration, error) { + c := &apolloDynamicConfiguration{ + url: url, + } + configEnv := url.GetParam(apolloEnvKey, ""); + configAddr := c.getAddressWithProtocolPrefix(url) + configCluster := url.GetParam(constant.CONFIG_GROUP_KEY, "") + if len(configEnv) != 0 { + os.Setenv(apolloEnvKey, configEnv) + } + + key := os.Getenv(apolloEnvKey) + if len(key) != 0 || constant.ANYHOST_VALUE == configAddr { + configAddr = key + } + + appId := os.Getenv("app.id") + namespace := url.GetParam(constant.CONFIG_NAMESPACE_KEY, config_center.DEFAULT_GROUP) + readyConfig := &agollo.AppConfig{ + AppId: appId, + Cluster: configCluster, + NamespaceName: namespace, + Ip: configAddr, + } + + agollo.InitCustomConfig(func() (*agollo.AppConfig, error) { + return readyConfig, nil + }) + + agollo.Start() + + return c, nil +} + +func (c *apolloDynamicConfiguration) start() { + for event := range agollo.ListenChangeEvent() { + for name, change := range event.Changes { + cfgChangeEvent := &config_center.ConfigChangeEvent{ + Key: name, + Value: change.NewValue, + ConfigType: c.getChangeType(change.ChangeType), + } + c.listeners.Range(func(key, value interface{}) bool { + for listener, _ := range value.(apolloListener).listeners { + listener.Process(cfgChangeEvent) + } + return true + }) + } + } +} + +func (c *apolloDynamicConfiguration) getChangeType(change agollo.ConfigChangeType) remoting.EventType { + switch change { + case agollo.ADDED: + return remoting.EventTypeAdd + case agollo.DELETED: + return remoting.EventTypeDel + case agollo.MODIFIED: + return remoting.EventTypeUpdate + default: + panic("unknow type: " + strconv.Itoa(int(change))) + } +} + +func (c *apolloDynamicConfiguration) AddListener(key string, listener config_center.ConfigurationListener, opts ...config_center.Option) { + k := &config_center.Options{} + for _, opt := range opts { + opt(k) + } + + key = k.Group + key + l, _ := c.listeners.LoadOrStore(key, NewApolloListener()) + l.(apolloListener).AddListener(listener) +} + +func (c *apolloDynamicConfiguration) RemoveListener(key string, listener config_center.ConfigurationListener, opts ...config_center.Option) { + k := &config_center.Options{} + for _, opt := range opts { + opt(k) + } + + key = k.Group + key + l, ok := c.listeners.Load(key) + if ok { + l.(apolloListener).RemoveListener(listener) + } +} + +func (c *apolloDynamicConfiguration) GetConfig(key string, opts ...config_center.Option) (string, error) { + k := &config_center.Options{} + for _, opt := range opts { + opt(k) + } + group := k.Group + if len(group) != 0 && c.url.GetParam(constant.CONFIG_GROUP_KEY, config_center.DEFAULT_GROUP) != group { + readyConfig := &agollo.AppConfig{ + AppId: c.appConf.AppId, + Cluster: c.appConf.Cluster, + NamespaceName: "application", + Ip: c.appConf.Ip, + } + + agollo.InitCustomConfig(func() (*agollo.AppConfig, error) { + return readyConfig, nil + }) + + agollo.Start() + //Config config = ConfigService.getAppConfig(); + //return config.getProperty(key, null); + } + return agollo.GetStringValue(key, ""), nil +} + +func (c *apolloDynamicConfiguration) getAddressWithProtocolPrefix(url *common.URL) string { + address := "" + converted := address + if len(address) != 0 { + parts := strings.Split(address, ",") + addrs := make([]string, 0) + for _, part := range parts { + addr := part + if !strings.HasPrefix(part, apolloProtocolPrefix) { + addr = apolloProtocolPrefix + part + } + addrs = append(addrs, addr) + } + converted = strings.Join(addrs, ",") + } + return converted +} + +func (c *apolloDynamicConfiguration) Parser() parser.ConfigurationParser { + return c.parser +} +func (c *apolloDynamicConfiguration) SetParser(p parser.ConfigurationParser) { + c.parser = p +} + +func (c *apolloDynamicConfiguration) GetConfigs(key string, opts ...config_center.Option) (string, error) { + return c.GetConfig(key, opts...) +} diff --git a/config_center/apollo/listener.go b/config_center/apollo/listener.go new file mode 100644 index 0000000000000000000000000000000000000000..1d443165c96bcbf5076963a6f6909ab362d94f93 --- /dev/null +++ b/config_center/apollo/listener.go @@ -0,0 +1,44 @@ +/* +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 apollo + +import ( + "github.com/apache/dubbo-go/config_center" +) + +type apolloListener struct { + listeners map[config_center.ConfigurationListener]struct{} +} + +func NewApolloListener() *apolloListener { + return &apolloListener{ + listeners: make(map[config_center.ConfigurationListener]struct{}, 0), + } +} + +func (al *apolloListener) AddListener(l config_center.ConfigurationListener) { + if _, ok := al.listeners[l]; !ok { + al.listeners[l] = struct{}{} + } +} + +func (al *apolloListener) RemoveListener(l config_center.ConfigurationListener) { + delete(al.listeners, l) +} + + diff --git a/go.mod b/go.mod index 4d1f8acbba481269588bbd1128a453ba7ff62c91..124e7cfe8b4f921325c852f62c7909fa882f6dda 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,8 @@ require ( github.com/aliyun/alibaba-cloud-sdk-go v0.0.0-20190802083043-4cd0c391755e // indirect github.com/apache/dubbo-go-hessian2 v1.2.5-0.20191029001541-894e45c9aaaa github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/coocood/freecache v1.1.0 // indirect github.com/coreos/bbolt v1.3.3 // indirect github.com/coreos/etcd v3.3.13+incompatible github.com/coreos/go-semver v0.3.0 // indirect @@ -44,6 +46,7 @@ require ( github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 // indirect github.com/toolkits/concurrent v0.0.0-20150624120057-a4371d70e3e3 // indirect github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect + github.com/zouyx/agollo v1.8.0 go.etcd.io/bbolt v1.3.3 // indirect go.etcd.io/etcd v3.3.13+incompatible go.uber.org/atomic v1.4.0 diff --git a/go.sum b/go.sum index bcde5b1f80264e46fc5b581732543d19a83cf660..5df57e4fbaf670f80b6caa44010c1025df20f90b 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,8 @@ github.com/NYTimes/gziphandler v1.0.1 h1:iLrQrdwjDd52kHDA5op2UBJFjmOb9g+7scBan4R github.com/NYTimes/gziphandler v1.0.1/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/SAP/go-hdb v0.12.0 h1:5hBQZ2jjyZ268qjDmoDZJuCyLzR6oRLI60eYzmTW9m4= github.com/SAP/go-hdb v0.12.0/go.mod h1:etBT+FAi1t5k3K3tf5vQTnosgYmhDkRi8jEnQqCnxF0= github.com/SermoDigital/jose v0.0.0-20180104203859-803625baeddc h1:LkkwnbY+S8WmwkWq1SVyRWMH9nYWO1P5XN3OD1tts/w= @@ -67,6 +69,8 @@ github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23 h1:D21IyuvjDCshj1 github.com/buger/jsonparser v0.0.0-20181115193947-bf1c66bbce23/go.mod h1:bbYlZJ7hK1yFx9hf58LP0zeX7UjIGs20ufpu3evjr+s= github.com/cenkalti/backoff v2.1.1+incompatible h1:tKJnvO2kl0zmb/jA5UKAt4VoEVw1qxKWjE/Bpp46npY= github.com/cenkalti/backoff v2.1.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible h1:C29Ae4G5GtYyYMm1aztcyj/J5ckgJm2zwdDajFbx1NY= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3 h1:TJH+oke8D16535+jHExHj4nQvzlZrj7ug5D7I/orNUA= @@ -74,6 +78,8 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/containerd/continuity v0.0.0-20181203112020-004b46473808 h1:4BX8f882bXEDKfWIf0wa8HRvpnBoPszJJXL+TVbBw4M= github.com/containerd/continuity v0.0.0-20181203112020-004b46473808/go.mod h1:GL3xCUCBDV3CZiTSEKksMWbLE66hEyuu9qyDOOqM47Y= +github.com/coocood/freecache v1.1.0 h1:ENiHOsWdj1BrrlPwblhbn4GdAsMymK3pZORJ+bJGAjA= +github.com/coocood/freecache v1.1.0/go.mod h1:ePwxCDzOYvARfHdr1pByNct1at3CoKnsipOHwKlNbzI= github.com/coredns/coredns v1.1.2 h1:bAFHrSsBeTeRG5W3Nf2su3lUGw7Npw2UKeCJm/3A638= github.com/coredns/coredns v1.1.2/go.mod h1:zASH/MVDgR6XZTbxvOnsZfffS+31vg6Ackf/wo1+AM0= github.com/coreos/bbolt v1.3.3 h1:n6AiVyVRKQFNb6mJlwESEvvLoDyiTzXX7ORAUlkeBdY= @@ -439,6 +445,8 @@ github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d h1:bVQRCxQv github.com/softlayer/softlayer-go v0.0.0-20180806151055-260589d94c7d/go.mod h1:Cw4GTlQccdRGSEf6KiMju767x0NEHE0YIVPJSaXjlsw= github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= @@ -463,6 +471,8 @@ github.com/vmware/govmomi v0.18.0 h1:f7QxSmP7meCtoAmiKZogvVbLInT+CZx6Px6K5rYsJZo github.com/vmware/govmomi v0.18.0/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= +github.com/zouyx/agollo v1.8.0 h1:u2Z+zsSOUND9mZlKYSWGvxkRKZyRcBe+wK+mfBxYWv8= +github.com/zouyx/agollo v1.8.0/go.mod h1:4JiqkUebtrabKqJ9OBbgRlRvtvOKIeMUhNqd5qVvqqM= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v3.3.13+incompatible h1:jCejD5EMnlGxFvcGRyEV4VGlENZc7oPQX6o0t7n3xbw=