trpc.group/trpc-go/trpc-go@v1.0.3/docs/developer_guide/develop_plugins/config.zh_CN.md (about) 1 [English](config.md) | 中文 2 3 # 怎么开发一个 config 类型的插件 4 5 本指南将介绍如何开发一个依赖配置进行加载的 config 类型的插件。 6 7 `config` 包提供两套不同的配置接口,`config.DataProvider` 和 `config.KVConfig`。 8 本指南以开发 `KVConfig` 类型的配置为例,`DataProvider` 类型的配置与之类似。 9 10 开发该插件需要实现以下两个子功能: 11 12 - 实现插件依赖配置进行加载,详细说明请参考 [plugin](/plugin/README.zh_CN.md) 13 - 实现 `config.KVConfig` 接口,并将实现注册到 `config` 包 14 15 下面以 [trpc-config-etcd](https://github.com/trpc-ecosystem/go-config-etcd) 为例,来介绍相关开发步骤。 16 17 ## 实现插件依赖配置进行加载 18 19 ### 1. 确定插件的配置 20 21 下面是在 "trpc_go.yaml" 配置文件中设置 "Endpoint" 和 "Dialtimeout" 的配置示例: 22 23 ```yaml 24 plugins: 25 config: 26 etcd: 27 endpoints: 28 - localhost:2379 29 dialtimeout: 5s 30 ``` 31 32 ```go 33 const ( 34 pluginName = "etcd" 35 pluginType = "config" 36 ) 37 ``` 38 39 插件是基于[etcd-client](https://github.com/etcd-io/etcd/tree/main/client/v3) 封装的, 因此完整的配置见 [Config](https://github.com/etcd-io/etcd/blob/client/v3.5.9/client/v3/config.go#L26)。 40 41 ### 2. 实现 `plugin.Factory` 接口 42 43 ```go 44 // etcdPlugin etcd Configuration center plugin. 45 type etcdPlugin struct{} 46 47 // Type implements plugin.Factory. 48 func (p *etcdPlugin) Type() string { 49 return pluginType 50 } 51 52 // Setup implements plugin.Factory. 53 func (p *etcdPlugin) Setup(name string, decoder plugin.Decoder) error { 54 cfg := clientv3.Config{} 55 err := decoder.Decode(&cfg) 56 if err != nil { 57 return err 58 } 59 c, err := New(cfg) 60 if err != nil { 61 return err 62 } 63 config.SetGlobalKV(c) 64 config.Register(c) 65 return nil 66 } 67 ``` 68 69 ### 3. 调用 `plugin.Register` 把插件自己注册到 `plugin` 包 70 71 ```go 72 func init() { 73 plugin.Register(pluginName, NewPlugin()) 74 } 75 ``` 76 77 ## 实现 `config.KVConfig` 接口,并将实现注册到 `config` 包 78 79 ### 1. 实现 `config.KVConfig` 接口 80 81 插件暂时只支持 Watch 和 Get 读操作,不支持 Put和 Del 写操作。 82 83 ```go 84 // Client etcd client. 85 type Client struct { 86 cli *clientv3.Client 87 } 88 89 // Name returns plugin name. 90 func (c *Client) Name() string { 91 return pluginName 92 } 93 94 // Get Obtains the configuration content value according to the key, and implement the config.KV interface. 95 func (c *Client) Get(ctx context.Context, key string, _ ...config.Option) (config.Response, error) { 96 result, err := c.cli.Get(ctx, key) 97 if err != nil { 98 return nil, err 99 } 100 rsp := &getResponse{ 101 md: make(map[string]string), 102 } 103 104 if result.Count > 1 { 105 // TODO: support multi keyvalues 106 return nil, ErrNotImplemented 107 } 108 109 for _, v := range result.Kvs { 110 rsp.val = string(v.Value) 111 } 112 return rsp, nil 113 } 114 115 // Watch monitors configuration changes and implements the config.Watcher interface. 116 func (c *Client) Watch(ctx context.Context, key string, opts ...config.Option) (<-chan config.Response, error) { 117 rspCh := make(chan config.Response, 1) 118 go c.watch(ctx, key, rspCh) 119 return rspCh, nil 120 } 121 122 // watch adds watcher for etcd changes. 123 func (c *Client) watch(ctx context.Context, key string, rspCh chan config.Response) { 124 rch := c.cli.Watch(ctx, key) 125 for r := range rch { 126 for _, ev := range r.Events { 127 rsp := &watchResponse{ 128 val: string(ev.Kv.Value), 129 md: make(map[string]string), 130 eventType: config.EventTypeNull, 131 } 132 switch ev.Type { 133 case clientv3.EventTypePut: 134 rsp.eventType = config.EventTypePut 135 case clientv3.EventTypeDelete: 136 rsp.eventType = config.EventTypeDel 137 default: 138 } 139 rspCh <- rsp 140 } 141 } 142 } 143 144 // ErrNotImplemented not implemented error 145 var ErrNotImplemented = errors.New("not implemented") 146 147 // Put creates or updates the configuration content value to implement the config.KV interface. 148 func (c *Client) Put(ctx context.Context, key, val string, opts ...config.Option) error { 149 return ErrNotImplemented 150 } 151 152 // Del deletes the configuration item key and implement the config.KV interface. 153 func (c *Client) Del(ctx context.Context, key string, opts ...config.Option) error { 154 return ErrNotImplemented 155 } 156 ``` 157 158 ### 2. 将实现的 `config.KVConfig` 注册到 config 包 159 160 `*etcdPlugin.Setup` 函数中已经调用了 `config.Register` 和 `config.SetGlobalKV`。 161 162 ```go 163 config.SetGlobalKV(c) 164 config.Register(c) 165 ```