国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

腳本之家,腳本語(yǔ)言編程技術(shù)及教程分享平臺(tái)!
分類(lèi)導(dǎo)航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務(wù)器之家 - 腳本之家 - Golang - viper配置框架的介紹支持zookeeper的讀取和監(jiān)聽(tīng)

viper配置框架的介紹支持zookeeper的讀取和監(jiān)聽(tīng)

2020-07-09 10:07Go語(yǔ)言中文網(wǎng) Golang

這篇文章主要介紹了viper配置框架的介紹支持zookeeper的讀取和監(jiān)聽(tīng),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

viper作為配置框架,其功能非常的強(qiáng)大,我們沒(méi)有理由不去了解一下。我們先看官網(wǎng)對(duì)它的功能簡(jiǎn)介:

viper是完整配置解決方案,他可以處理所有類(lèi)型和格式的配置文件,他有如下功能:

  • 設(shè)置默認(rèn)配置
  • 支持讀取 JSON TOML YAML HCL 和 Java 屬性配置文件
  • 監(jiān)聽(tīng)配置文件變化,實(shí)時(shí)讀取讀取配置文件內(nèi)容
  • 讀取環(huán)境變量值
  • 讀取遠(yuǎn)程配置系統(tǒng) (etcd Consul) 和監(jiān)控配置變化
  • 讀取命令 Flag 值
  • 讀取 buffer 值
  • 讀取確切值

乍一看,未免有相見(jiàn)恨晚之感,可仔細(xì)一想,不免腦袋里有另外一種聲音:不會(huì)不支持讀取 zookeeper 吧?好吧,至少我是這樣的。

基于這種想法,當(dāng)然要去立馬嘗試,如下:

?
1
viper.AddRemoteProvider("zookeeper", "xx.xx.xx.xx:2181", "/viper/test")

返回結(jié)果是:

Unsupported Remote Provider Type zookeeper

果不其然,于是追蹤 viper.AddRemoteProvider 的源碼,發(fā)現(xiàn)viper只支持如下幾種

?
1
var SupportedRemoteProviders = []string{"etcd", "consul", "firestore"}

如果就此打住,未免有點(diǎn)太可惜,作為偏執(zhí)狂,總想著能否來(lái)改造下viper,讓其支持 zookeeper ,于是在issue上找是否有人遇到同樣的問(wèn)題,還整讓我找到了, 傳送 。但是不完整,且稍微有點(diǎn)bug。所以根據(jù)他的基礎(chǔ)上,我做了些調(diào)整。進(jìn)入正題,我們開(kāi)始修改viper源碼。說(shuō)明下,我的viper版本是最新的 1.7.0

修改源碼

1、添加zookeeper.go

添加的位置: github.com/bketelsen/crypt/zookeeper , zookeeper 目錄需要自己創(chuàng)建, github.com/bketelsen/crypt 是viper的依賴(lài)包,會(huì)自動(dòng)下載

viper配置框架的介紹支持zookeeper的讀取和監(jiān)聽(tīng)

文件內(nèi)容:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
package zookeeper
 
import (
    "errors"
    "fmt"
    zk "github.com/samuel/go-zookeeper/zk"
    //"github.com/xordataexchange/crypt/backend"
    "github.com/bketelsen/crypt/backend"
    "strings"
    "time"
)
 
type Client struct {
    client *zk.Conn
    waitIndex uint64
}
 
func New(machines []string) (*Client, error) {
    zkclient, _, err := zk.Connect(machines, time.Second)
    if err != nil {
        return nil, err
    }
    return &Client{zkclient, 0}, nil
}
 
func (c *Client) Get(key string) ([]byte, error) {
    resp, _, err := c.client.Get(key)
    if err != nil {
        return nil, err
    }
    return []byte(resp), nil
}
 
func nodeWalk(prefix string, c *Client, vars map[string]string) error {
    l, stat, err := c.client.Children(prefix)
    if err != nil {
        return err
    }
 
    if stat.NumChildren == 0 {
        b, _, err := c.client.Get(prefix)
        if err != nil {
            return err
        }
        vars[prefix] = string(b)
 
    } else {
        for _, key := range l {
            s := prefix + "/" + key
            _, stat, err := c.client.Exists(s)
            if err != nil {
                return err
            }
            if stat.NumChildren == 0 {
                b, _, err := c.client.Get(s)
                if err != nil {
                    return err
                }
                vars[s] = string(b)
            } else {
                nodeWalk(s, c, vars)
            }
        }
    }
    return nil
}
 
func (c *Client) GetValues(key string, keys []string) (map[string]string, error) {
    vars := make(map[string]string)
    for _, v := range keys {
        v = fmt.Sprintf("%s/%s", key, v)
        v = strings.Replace(v, "/*", "", -1)
        _, _, err := c.client.Exists(v)
        if err != nil {
            return vars, err
        }
        if v == "/" {
            v = ""
        }
        err = nodeWalk(v, c, vars)
        if err != nil {
            return vars, err
        }
    }
    return vars, nil
}
 
func (c *Client) List(key string) (backend.KVPairs, error) {
    var list backend.KVPairs
    resp, stat, err := c.client.Children(key)
    if err != nil {
        return nil, err
    }
 
    if stat.NumChildren == 0 {
        return list, nil
    }
 
    entries, err := c.GetValues(key, resp)
    if err != nil {
        return nil, err
    }
 
    for k, v := range entries {
        list = append(list, &backend.KVPair{Key: k, Value: []byte(v)})
    }
    return list, nil
}
 
func (c *Client) createParents(key string) error {
    flags := int32(0)
    acl := zk.WorldACL(zk.PermAll)
 
    if key[0] != '/' {
        return errors.New("Invalid path")
    }
 
    payload := []byte("")
    pathString := ""
    pathNodes := strings.Split(key, "/")
    for i := 1; i < len(pathNodes); i++ {
        pathString += "/" + pathNodes[i]
        _, err := c.client.Create(pathString, payload, flags, acl)
        // not being able to create the node because it exists or not having
        // sufficient rights is not an issue. It is ok for the node to already
        // exist and/or us to only have read rights
        if err != nil && err != zk.ErrNodeExists && err != zk.ErrNoAuth {
            return err
        }
    }
    return nil
}
 
func (c *Client) Set(key string, value []byte) error {
    err := c.createParents(key)
    if err != nil {
        return err
    }
    _, err = c.client.Set(key, []byte(value), -1)
    return err
}
 
func (c *Client) Watch(key string, stop chan bool) <-chan *backend.Response {
    respChan := make(chan *backend.Response, 0)
    go func() {
        for {
            resp, _, watch, err := c.client.GetW(key)
            if err != nil {
                respChan <- &backend.Response{nil, err}
                time.Sleep(time.Second * 5)
            }
 
            select {
            case e := <-watch:
                if e.Type == zk.EventNodeDataChanged {
                    resp, _, err = c.client.Get(key)
                    if err != nil {
                        respChan <- &backend.Response{nil, err}
                    }
                    c.waitIndex = 0
                    respChan <- &backend.Response{[]byte(resp), nil}
                }
            }
        }
    }()
    return respChan
}

這個(gè)文件是實(shí)現(xiàn) ConfigManager 接口,我們?cè)谏蠄D中看到 etcdconsulfilestore ,均有實(shí)現(xiàn)該接口,接口的定義很簡(jiǎn)單

?
1
2
3
4
5
6
type ConfigManager interface {
    Get(key string) ([]byte, error)
    List(key string) (KVPairs, error)
    Set(key string, value []byte) error
    Watch(key string, stop chan bool) <-chan *Response
}

2、修改config.go

文件的位置: github.com/bketelsen/crypt/config/config.go ,如下圖

 

viper配置框架的介紹支持zookeeper的讀取和監(jiān)聽(tīng)

func NewStandardEtcdConfigManager(machines []string) (ConfigManager, error) 方法下面添加如下方法:

?
1
2
3
4
5
6
7
8
9
// NewStandardZookeeperConfigManager returns a new ConfigManager backed by Zookeeper.
// Data will be encrypted.
func NewStandardZookeeperConfigManager(machines []string) (ConfigManager, error) {
    store, err := zookeeper.New(machines)
    if err != nil {
        return nil, err
    }
    return NewStandardConfigManager(store)
}

func NewEtcdConfigManager(machines []string, keystore io.Reader) (ConfigManager, error) 方法下面添加如下方法:

?
1
2
3
4
5
6
7
8
9
// NewZookeeperConfigManager returns a new ConfigManager backed by zookeeper.
// Data will be encrypted.
func NewZookeeperConfigManager(machines []string, keystore io.Reader) (ConfigManager, error) {
    store, err := zookeeper.New(machines)
    if err != nil {
        return nil, err
    }
    return NewConfigManager(store, keystore)
}

這兩個(gè)方法是初始化 ConfigManager 對(duì)象,也就是我們剛才添加的 zookeeper.go 文件的對(duì)象

3、修改remote.go

文件的位置: github.com/spf13/viper/remote/remote.go ,如下圖

 

viper配置框架的介紹支持zookeeper的讀取和監(jiān)聽(tīng)

找到74行,用下面的代碼替換 func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) 方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
func getConfigManager(rp viper.RemoteProvider) (crypt.ConfigManager, error) {
    var cm crypt.ConfigManager
    var err error
 
    if rp.SecretKeyring() != "" {
        var kr *os.File
        kr, err = os.Open(rp.SecretKeyring())
        if err != nil {
            return nil, err
        }
        defer kr.Close()
        switch rp.Provider() {
        case "etcd":
            cm, err = crypt.NewEtcdConfigManager([]string{rp.Endpoint()}, kr)
        case "zookeeper":
            cm, err = crypt.NewZookeeperConfigManager([]string{rp.Endpoint()}, kr)
        case "firestore":
            cm, err = crypt.NewFirestoreConfigManager([]string{rp.Endpoint()}, kr)
        default:
            cm, err = crypt.NewConsulConfigManager([]string{rp.Endpoint()}, kr)
        }
    } else {
        switch rp.Provider() {
        case "etcd":
            cm, err = crypt.NewStandardEtcdConfigManager([]string{rp.Endpoint()})
        case "zookeeper":
            cm, err = crypt.NewStandardZookeeperConfigManager([]string{rp.Endpoint()})
        case "firestore":
            cm, err = crypt.NewStandardFirestoreConfigManager([]string{rp.Endpoint()})
        default:
            cm, err = crypt.NewStandardConsulConfigManager([]string{rp.Endpoint()})
        }
    }
    if err != nil {
        return nil, err
    }
    return cm, nil
}

細(xì)心的讀者可能已經(jīng)發(fā)現(xiàn),其實(shí)就添加了兩個(gè)case選項(xiàng):

viper配置框架的介紹支持zookeeper的讀取和監(jiān)聽(tīng)

4、修改viper.go

文件的位置: github.com/spf13/viper/viper.go ,如下圖

 

viper配置框架的介紹支持zookeeper的讀取和監(jiān)聽(tīng)

取+監(jiān)聽(tīng)zookeeper(1)\image-20200521222843002.png)

找到兩個(gè) SupportedRemoteProviders 定義的定法,1.7.0版本的行號(hào)分別是:290,331。只要添加 zookeeper ,即可

?
1
SupportedRemoteProviders = []string{"etcd", "consul", "firestore", "zookeeper"}

好了,修改代碼的工作已經(jīng)完了,接下來(lái)我們來(lái)測(cè)試:

測(cè)試

注意:zookeeper中已經(jīng)設(shè)置了內(nèi)容

set /viper/test {"appName":"test","nodes":["127.0.0.1","127.0.0.2","127.0.0.3"]}

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package main
 
import (
    "fmt"
    "github.com/fsnotify/fsnotify"
    "github.com/spf13/viper"
    _ "github.com/spf13/viper/remote"
    "time"
)
 
 
type config struct {
    AppName string
    Nodes []string
}
 
func main() {
    var waitGroup=sync.WaitGroup{}
    waitGroup.Add(1)
    readRemoteZookeeper()
    go watchRemoteZookeeper()
    waitGroup.Wait()
}
 
func readRemoteZookeeper() {
    viper.AddRemoteProvider("zookeeper", "62.234.15.24:2181", "/viper/test")
    viper.SetConfigType("json")
    err := viper.ReadRemoteConfig()
    if err != nil {
        panic(fmt.Sprintf("read remote zookeeper error:+%v", err))
    }
 
    var C config
    viper.Unmarshal(&C)
    fmt.Printf("從zookeeper讀取配置內(nèi)容:%+v\n", C)
}
 
func watchRemoteZookeeper() {
    go func() {
        for {
  //delay after each request
            time.Sleep(time.Second * 5)
            err := viper.WatchRemoteConfig()
            if err != nil {
                fmt.Errorf("unable to read remote config: %v", err)
                continue
            }
            fmt.Printf("從zookeeper讀取更新內(nèi)容:appName=%s,nodes=%+v\n", viper.Get("appName"), viper.Get("nodes"))
        }
    }()
}

輸出內(nèi)容:

從zookeeper讀取配置內(nèi)容:{AppName:test Nodes:[127.0.0.1 127.0.0.2 127.0.0.3]}
從zookeeper讀取更新內(nèi)容:appName=test,nodes=[127.0.0.1 127.0.0.2 127.0.0.3]

如果我們修改zookeeper的內(nèi)容,則viper會(huì)讀取到更新后的內(nèi)容:

?
1
set /viper/test {"appName":"test","nodes":["127.0.0.1","127.0.0.2","127.0.0.3","127.0.0.4"]}
?
1
從zookeeper讀取更新內(nèi)容:appName=test,nodes=[127.0.0.1 127.0.0.2 127.0.0.3 127.0.0.4]

結(jié)語(yǔ)

讓viper支持 zookeeper 并不復(fù)雜的,并且基本上不需要修改原有的方法, 這要?dú)w結(jié)于viper用到一個(gè)非常重要的設(shè)計(jì)原則: 開(kāi)閉原則 ,讀者可以自行體會(huì)。

關(guān)于viper的基本使用, github 已經(jīng)有非常詳細(xì)的例子,這里就不再贅述,如有疑問(wèn),可以私信我

到此這篇關(guān)于viper配置框架的介紹支持zookeeper的讀取和監(jiān)聽(tīng)的文章就介紹到這了,更多相關(guān)viper配置框架支持zookeeper的讀取和監(jiān)聽(tīng)內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!

原文鏈接:https://studygolang.com/articles/28829

延伸 · 閱讀

精彩推薦
  • Golanggo日志系統(tǒng)logrus顯示文件和行號(hào)的操作

    go日志系統(tǒng)logrus顯示文件和行號(hào)的操作

    這篇文章主要介紹了go日志系統(tǒng)logrus顯示文件和行號(hào)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧...

    SmallQinYan12302021-02-02
  • Golanggolang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法

    今天小編就為大家分享一篇golang json.Marshal 特殊html字符被轉(zhuǎn)義的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧 ...

    李浩的life12792020-05-27
  • Golanggolang如何使用struct的tag屬性的詳細(xì)介紹

    golang如何使用struct的tag屬性的詳細(xì)介紹

    這篇文章主要介紹了golang如何使用struct的tag屬性的詳細(xì)介紹,從例子說(shuō)起,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看...

    Go語(yǔ)言中文網(wǎng)11352020-05-21
  • Golanggolang的httpserver優(yōu)雅重啟方法詳解

    golang的httpserver優(yōu)雅重啟方法詳解

    這篇文章主要給大家介紹了關(guān)于golang的httpserver優(yōu)雅重啟的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,...

    helight2992020-05-14
  • GolangGolang中Bit數(shù)組的實(shí)現(xiàn)方式

    Golang中Bit數(shù)組的實(shí)現(xiàn)方式

    這篇文章主要介紹了Golang中Bit數(shù)組的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧...

    天易獨(dú)尊11682021-06-09
  • Golanggo語(yǔ)言制作端口掃描器

    go語(yǔ)言制作端口掃描器

    本文給大家分享的是使用go語(yǔ)言編寫(xiě)的TCP端口掃描器,可以選擇IP范圍,掃描的端口,以及多線程,有需要的小伙伴可以參考下。 ...

    腳本之家3642020-04-25
  • GolangGolang通脈之?dāng)?shù)據(jù)類(lèi)型詳情

    Golang通脈之?dāng)?shù)據(jù)類(lèi)型詳情

    這篇文章主要介紹了Golang通脈之?dāng)?shù)據(jù)類(lèi)型,在編程語(yǔ)言中標(biāo)識(shí)符就是定義的具有某種意義的詞,比如變量名、常量名、函數(shù)名等等,Go語(yǔ)言中標(biāo)識(shí)符允許由...

    4272021-11-24
  • Golanggolang 通過(guò)ssh代理連接mysql的操作

    golang 通過(guò)ssh代理連接mysql的操作

    這篇文章主要介紹了golang 通過(guò)ssh代理連接mysql的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧...

    a165861639710342021-03-08
主站蜘蛛池模板: 亚洲国产精品久久久久 | 精品一区二区三区蜜桃 | 亚洲欧美另类在线 | av在线天堂网 | 天天精品 | 中国大陆高清aⅴ毛片 | 亚洲精品久久久久久一区二区 | 久久久久亚洲精品 | 久久久亚洲 | 国产精品视频久久 | 最新国产精品 | 成人av福利 | 精品少妇一区二区三区日产乱码 | 国产片在线免费观看 | 国产日韩欧美 | 国产精品久久嫩一区二区免费 | 能免费看的av | 涩涩一区| 人人人人人你人人人人人 | 天堂va在线高清一区 | 天堂v视频永久在线播放 | 欧美日韩亚洲国产精品 | 欧美激情网址 | 中文字幕 国产精品 | 欧美成人a| 国内精品视频 | 欧洲精品码一区二区三区免费看 | 黄色成人在线观看视频 | 国产精品高潮呻吟久久 | 黄色的视频免费看 | 一区二区在线免费观看 | 国产美女一区二区 | 免费视频黄 | 亚洲乱码国产乱码精品精软件 | 日韩精品在线观看视频 | 久久精品久久久久久 | 欧美激情视频一区二区三区 | 国产精品久久久久久久久久久久久久 | 中文字幕成人 | 日韩av中文字幕在线播放 | 亚洲区视频 |