11package agollo
22
33import (
4- "crypto/hmac"
5- "crypto/sha1"
6- "encoding/base64"
74 "encoding/json"
85 "fmt"
96 "io/ioutil"
107 "net"
118 "net/http"
129 "net/url"
10+ "os"
1311 "time"
1412)
1513
1614var (
1715 defaultClientTimeout = 90 * time .Second
1816)
1917
20- // https://github.com/ctripcorp/apollo/wiki/%E5%85%B6%E5%AE%83%E8%AF%AD%E8%A8%80%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97
21- type ApolloClient interface {
22- Apply (opts ... ApolloClientOption )
23-
24- Notifications (configServerURL , appID , clusterName string , notifications []Notification ) (int , []Notification , error )
25-
26- // 该接口会直接从数据库中获取配置,可以配合配置推送通知实现实时更新配置。
27- GetConfigsFromNonCache (configServerURL , appID , cluster , namespace string , opts ... NotificationsOption ) (int , * Config , error )
28-
29- // 该接口会从缓存中获取配置,适合频率较高的配置拉取请求,如简单的每30秒轮询一次配置。
30- GetConfigsFromCache (configServerURL , appID , cluster , namespace string ) (Configurations , error )
31-
32- // 该接口从MetaServer获取ConfigServer列表
33- GetConfigServers (metaServerURL , appID string ) (int , []ConfigServer , error )
34- }
35-
36- type Notifications []Notification
37-
38- func (n Notifications ) String () string {
39- bytes , _ := json .Marshal (n )
40- return string (bytes )
41- }
42-
43- type Notification struct {
44- NamespaceName string `json:"namespaceName"` // namespaceName: "application",
45- NotificationID int `json:"notificationId"` // notificationId: 107
46- }
47-
48- type NotificationsOptions struct {
49- ReleaseKey string
50- }
51-
52- type NotificationsOption func (* NotificationsOptions )
53-
54- func ReleaseKey (releaseKey string ) NotificationsOption {
55- return func (o * NotificationsOptions ) {
56- o .ReleaseKey = releaseKey
57- }
58- }
59-
60- type Config struct {
61- AppID string `json:"appId"` // appId: "AppTest",
62- Cluster string `json:"cluster"` // cluster: "default",
63- NamespaceName string `json:"namespaceName"` // namespaceName: "TEST.Namespace1",
64- Configurations Configurations `json:"configurations"` // configurations: {Name: "Foo"},
65- ReleaseKey string `json:"releaseKey"` // releaseKey: "20181017110222-5ce3b2da895720e8"
66- }
67-
68- type ConfigServer struct {
69- AppName string `json:"appName"`
70- InstanceID string `json:"instanceId"`
71- HomePageURL string `json:"homepageUrl"`
72- }
18+ const (
19+ // ENV_APOLLO_ACCESS_KEY 默认从环境变量中读取Apollo的AccessKey
20+ // 会被显示传入的AccessKey所覆盖
21+ ENV_APOLLO_ACCESS_KEY = "APOLLO_ACCESS_KEY"
22+ )
7323
7424type Doer interface {
7525 Do (* http.Request ) (* http.Response , error )
7626}
7727
7828type apolloClient struct {
79- Doer Doer
80- IP string
81- ConfigType string // 默认properties不需要在namespace后加后缀名,其他情况例如application.json {xml,yml,yaml,json,...}
82- AccessKey string
83- }
84-
85- type ApolloClientOption func (* apolloClient )
86-
87- func WithDoer (d Doer ) ApolloClientOption {
88- return func (a * apolloClient ) {
89- a .Doer = d
90- }
91- }
92-
93- func WithIP (ip string ) ApolloClientOption {
94- return func (a * apolloClient ) {
95- a .IP = ip
96- }
97- }
98-
99- func WithConfigType (configType string ) ApolloClientOption {
100- return func (a * apolloClient ) {
101- a .ConfigType = configType
102- }
103- }
104-
105- func WithAccessKey (accessKey string ) ApolloClientOption {
106- return func (a * apolloClient ) {
107- a .AccessKey = accessKey
108- }
29+ Doer Doer
30+ IP string
31+ ConfigType string // 默认properties不需要在namespace后加后缀名,其他情况例如application.json {xml,yml,yaml,json,...}
32+ AccessKey string
33+ SignatureFunc SignatureFunc
10934}
11035
11136func NewApolloClient (opts ... ApolloClientOption ) ApolloClient {
@@ -115,46 +40,15 @@ func NewApolloClient(opts ...ApolloClientOption) ApolloClient {
11540 Doer : & http.Client {
11641 Timeout : defaultClientTimeout , // Notifications由于服务端会hold住请求60秒,所以请确保客户端访问服务端的超时时间要大于60秒。
11742 },
43+ AccessKey : os .Getenv (ENV_APOLLO_ACCESS_KEY ),
44+ SignatureFunc : DefaultSignatureFunc ,
11845 }
11946
12047 c .Apply (opts ... )
12148
12249 return c
12350}
12451
125- const (
126- AUTHORIZATION_FORMAT = "Apollo %s:%s"
127- DELIMITER = "\n "
128- HTTP_HEADER_AUTHORIZATION = "Authorization"
129- HTTP_HEADER_TIMESTAMP = "Timestamp"
130- )
131-
132- func signature (timestamp , url , accessKey string ) string {
133-
134- stringToSign := timestamp + DELIMITER + url
135-
136- key := []byte (accessKey )
137- mac := hmac .New (sha1 .New , key )
138- _ , _ = mac .Write ([]byte (stringToSign ))
139- return base64 .StdEncoding .EncodeToString (mac .Sum (nil ))
140- }
141-
142- func (c * apolloClient ) httpHeader (appID , uri string ) map [string ]string {
143-
144- headers := map [string ]string {}
145- if "" == c .AccessKey {
146- return headers
147- }
148-
149- timestamp := fmt .Sprintf ("%v" , time .Now ().UnixNano ()/ int64 (time .Millisecond ))
150- signature := signature (timestamp , uri , c .AccessKey )
151-
152- headers [HTTP_HEADER_AUTHORIZATION ] = fmt .Sprintf (AUTHORIZATION_FORMAT , appID , signature )
153- headers [HTTP_HEADER_TIMESTAMP ] = timestamp
154-
155- return headers
156- }
157-
15852func (c * apolloClient ) Apply (opts ... ApolloClientOption ) {
15953 for _ , opt := range opts {
16054 opt (c )
@@ -170,7 +64,13 @@ func (c *apolloClient) Notifications(configServerURL, appID, cluster string, not
17064 )
17165 apiURL := fmt .Sprintf ("%s%s" , configServerURL , requestURI )
17266
173- headers := c .httpHeader (appID , requestURI )
67+ headers := c .SignatureFunc (& SignatureContext {
68+ ConfigServerURL : configServerURL ,
69+ RequestURI : requestURI ,
70+ AccessKey : c .AccessKey ,
71+ AppID : appID ,
72+ Cluster : cluster ,
73+ })
17474 status , err = c .do ("GET" , apiURL , headers , & result )
17575 return
17676}
@@ -191,7 +91,13 @@ func (c *apolloClient) GetConfigsFromNonCache(configServerURL, appID, cluster, n
19191 )
19292 apiURL := fmt .Sprintf ("%s%s" , configServerURL , requestURI )
19393
194- headers := c .httpHeader (appID , requestURI )
94+ headers := c .SignatureFunc (& SignatureContext {
95+ ConfigServerURL : configServerURL ,
96+ RequestURI : requestURI ,
97+ AccessKey : c .AccessKey ,
98+ AppID : appID ,
99+ Cluster : cluster ,
100+ })
195101 config = new (Config )
196102 status , err = c .do ("GET" , apiURL , headers , config )
197103 return
@@ -208,7 +114,13 @@ func (c *apolloClient) GetConfigsFromCache(configServerURL, appID, cluster, name
208114 )
209115 apiURL := fmt .Sprintf ("%s%s" , configServerURL , requestURI )
210116
211- headers := c .httpHeader (appID , requestURI )
117+ headers := c .SignatureFunc (& SignatureContext {
118+ ConfigServerURL : configServerURL ,
119+ RequestURI : requestURI ,
120+ AccessKey : c .AccessKey ,
121+ AppID : appID ,
122+ Cluster : cluster ,
123+ })
212124 config = make (Configurations )
213125 _ , err = c .do ("GET" , apiURL , headers , config )
214126 return
@@ -219,7 +131,13 @@ func (c *apolloClient) GetConfigServers(metaServerURL, appID string) (int, []Con
219131 requestURI := fmt .Sprintf ("/services/config?id=%s&appId=%s" , c .IP , appID )
220132 apiURL := fmt .Sprintf ("%s%s" , metaServerURL , requestURI )
221133
222- headers := c .httpHeader (appID , requestURI )
134+ headers := c .SignatureFunc (& SignatureContext {
135+ ConfigServerURL : metaServerURL ,
136+ RequestURI : requestURI ,
137+ AccessKey : c .AccessKey ,
138+ AppID : appID ,
139+ Cluster : "" ,
140+ })
223141 var cfs []ConfigServer
224142 status , err := c .do ("GET" , apiURL , headers , & cfs )
225143 return status , cfs , err
0 commit comments