package resolver import ( "common/db/etcd" "common/discover/common" "common/log" "context" "go.etcd.io/etcd/client/v3" "google.golang.org/grpc/resolver" "strings" ) const etcdSchema = "etcd" func init() { resolver.Register(&etcdBuilder{}) } type etcdBuilder struct{} func (*etcdBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) { serviceName := strings.TrimPrefix(target.URL.Path, "/") r := &etcdResolver{ serviceName: serviceName, cc: cc, } r.start() return r, nil } func (*etcdBuilder) Scheme() string { return etcdSchema } type etcdResolver struct { serviceName string cc resolver.ClientConn ctx context.Context cancel context.CancelFunc } func (r *etcdResolver) start() { r.ctx, r.cancel = context.WithCancel(context.Background()) r.update() go r.watch() } func (r *etcdResolver) getPrefix() string { return common.KeyDiscoverService + "/" + r.serviceName } func (r *etcdResolver) update() { resp, err := etcd.GetClient().Get(r.getPrefix(), clientv3.WithPrefix()) if err != nil { log.Errorf("etcd resolver get error: %v", err) return } var addrArray []resolver.Address for _, kv := range resp.Kvs { addr := string(kv.Value) if addr != "" { addrArray = append(addrArray, resolver.Address{Addr: addr}) } } _ = r.cc.UpdateState(resolver.State{Addresses: addrArray}) } func (r *etcdResolver) watch() { watchCh := etcd.GetClient().Watch(r.getPrefix(), clientv3.WithPrefix()) for w := range watchCh { if w.Err() != nil { continue } r.update() } } func (r *etcdResolver) ResolveNow(resolver.ResolveNowOptions) { r.update() } func (r *etcdResolver) Close() { r.cancel() }