11package config
22
3- import (
4- "errors"
5- "path/filepath"
6- "reflect"
7- "sync"
8- "time"
9-
10- "github.com/fsnotify/fsnotify"
11- "github.com/nacos-group/nacos-sdk-go/v2/clients"
12- "github.com/nacos-group/nacos-sdk-go/v2/clients/config_client"
13- "github.com/nacos-group/nacos-sdk-go/v2/common/constant"
14- "github.com/nacos-group/nacos-sdk-go/v2/vo"
15- "github.com/spf13/viper"
16- )
17-
18- type ConfigManager interface {
19- GetData () interface {} // 获取配置数据
20- LoadData () error // 先加载再获取数据
21- WatchData () <- chan error //热更新
22- Close () error //关闭
23- }
24-
25- // yaml和json部分
26- type LocalConfig struct {
27- Viper * viper.Viper
28- Lastupdate time.Time
29- Data interface {} // 传入的配置结构体指针
30- Path string // 配置文件路径
31- Check int // 0表示监听未开启,1表示已开启,2表示停止监听,不会再触发热更新操作
32- mu sync.Mutex
33- ch chan error //传递更新信号或错误的管道
34- }
35-
36- // c需传入结构体指针,返回接口类型
37- func NewLocalConfig (c interface {}, path string ) (ConfigManager , error ) {
38- if reflect .ValueOf (c ).Kind () != reflect .Ptr {
39- return nil , errors .New ("config struct must be a pointer" )
40- }
41- return & LocalConfig {
42- Viper : viper .New (),
43- Data : c ,
44- Lastupdate : time .Now (),
45- Path : path ,
46- Check : 0 ,
47- mu : sync.Mutex {},
48- ch : make (chan error ),
49- }, nil
50- }
51-
52- func (l * LocalConfig ) GetData () interface {} {
53- return l .Data
54- }
55-
56- func (l * LocalConfig ) LoadData () error {
57- l .Viper .SetConfigFile (l .Path )
58-
59- // 检查扩展名(支持yaml, json),如果不是则报错
60- ext := filepath .Ext (l .Path )
61- switch ext {
62- case ".yaml" , ".yml" :
63- l .Viper .SetConfigType ("yaml" )
64- case ".json" :
65- l .Viper .SetConfigType ("json" )
66- default :
67- return errors .New ("only .yaml, .yml, or .json are supported" )
68- }
69-
70- // 读取配置文件
71- err := loadData (l )
72- return err
73- }
74-
75- // 传回的通道会在配置文件发生变化时发送信号
76- func (l * LocalConfig ) WatchData () <- chan error {
77- // 如果已经监听过就退出,防止开多个协程监听,不将错误传入管道了避免与热更新的错误混淆
78- if l .Check == 1 {
79- return nil
80- }
81- l .Check = 1
82-
83- l .Viper .OnConfigChange (func (e fsnotify.Event ) {
84- l .mu .Lock ()
85- defer l .mu .Unlock ()
86- // 停止监听就退出
87- if l .Check == 2 {
88- return
89- }
90- // 不知道为什么会连着调用两次,所以加个时间限制
91- if time .Since (l .Lastupdate ) < 1 * time .Second {
92- return
93- }
94- err := loadData (l )
95- if err != nil {
96- // 热更新时出错
97- l .ch <- err
98- return
99- }
100- // 发送信号通知配置已更新
101- l .ch <- nil
102- })
103- l .Viper .WatchConfig ()
104-
105- return l .ch
106- }
107-
108- func (l * LocalConfig ) Close () error {
109- close (l .ch )
110- // 停止监听标志
111- l .Check = 2
112- // 感觉没有错误但得和nacos的一致
113- return nil
3+ type ConfigManager [T any ] interface {
4+ GetData () * T // 获取配置数据
5+ WatchData () <- chan struct {} // 热更新, 只负责更新数据, 不负责更新后的操作
6+ Close () error // 关闭
1147}
115-
116- func loadData (l * LocalConfig ) error {
117- if err := l .Viper .ReadInConfig (); err != nil {
118- return err
119- }
120-
121- if err := l .Viper .Unmarshal (l .Data ); err != nil {
122- return err
123- }
124-
125- l .Lastupdate = time .Now ()
126- return nil
127- }
128-
129- // Nacos部分
130- // 定义查询结构体
131- type NacosConfig struct {
132- DataId string // 配置key
133- Group string // 配置组
134- Data string // 配置value,获取值时也在这里获取
135- Client config_client.IConfigClient // Nacos客户端
136- Check int
137- ch chan error
138- mu sync.Mutex
139- }
140-
141- func NewClientConfig (namespace , username , password string , time uint64 ) * constant.ClientConfig {
142- return & constant.ClientConfig {
143- NamespaceId : namespace ,
144- TimeoutMs : time ,
145- Username : username ,
146- Password : password ,
147- }
148- }
149-
150- func NewServerConfig (ip []string , port []uint64 ) []constant.ServerConfig {
151- serverConfigs := make ([]constant.ServerConfig , 0 , len (ip ))
152- for i := 0 ; i < len (ip ); i ++ {
153- serverConfigs = append (serverConfigs , constant.ServerConfig {
154- IpAddr : ip [i ],
155- Port : port [i ],
156- })
157- }
158- return serverConfigs
159- }
160-
161- // 创建nacos客户端
162- func NewNacos (clientConfig * constant.ClientConfig , serverConfigs []constant.ServerConfig ) (config_client.IConfigClient , error ) {
163- client , err := clients .NewConfigClient (vo.NacosClientParam {
164- ClientConfig : clientConfig ,
165- ServerConfigs : serverConfigs ,
166- })
167- if err != nil {
168- return nil , err
169- }
170- return client , nil
171- }
172-
173- // 返回接口类型
174- func NewNacosConfig (dataId , group , content string , clientconfig * constant.ClientConfig , serverconfig []constant.ServerConfig ) (ConfigManager , error ) {
175- client , err := NewNacos (clientconfig , serverconfig )
176- if err != nil {
177- return nil , err
178- }
179- return & NacosConfig {
180- DataId : dataId ,
181- Group : group ,
182- Data : content ,
183- Client : client ,
184- Check : 0 ,
185- ch : make (chan error ),
186- mu : sync.Mutex {},
187- }, nil
188- }
189-
190- func (p * NacosConfig ) GetData () interface {} {
191- return p .Data
192- }
193-
194- func (p * NacosConfig ) LoadData () error {
195- content , err := p .Client .GetConfig (vo.ConfigParam {
196- DataId : p .DataId ,
197- Group : p .Group ,
198- })
199- if err != nil {
200- return err
201- }
202- p .Data = content
203- return nil
204- }
205-
206- func (p * NacosConfig ) WatchData () <- chan error {
207- if p .Check == 1 {
208- return nil
209- }
210- p .Check = 1
211- err := p .Client .ListenConfig (vo.ConfigParam {
212- DataId : p .DataId ,
213- Group : p .Group ,
214- OnChange : func (namespace , group , dataId , data string ) {
215- p .mu .Lock ()
216- defer p .mu .Unlock ()
217- p .Data = data
218- p .ch <- nil
219- },
220- })
221- if err != nil {
222- p .ch <- err
223- }
224- return p .ch
225- }
226-
227- func (p * NacosConfig ) Close () error {
228- // nacos提供了专门关闭方法
229- cancelParam := vo.ConfigParam {
230- DataId : p .DataId ,
231- Group : p .Group ,
232- }
233- p .Check = 0
234- return p .Client .CancelListenConfig (cancelParam )
235- }
0 commit comments