github.heygears.com/openimsdk/tools@v0.0.49/discovery/zookeeper/discover.go (about) 1 // Copyright © 2023 OpenIM. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package zookeeper 16 17 import ( 18 "context" 19 "fmt" 20 "strings" 21 22 "github.com/go-zookeeper/zk" 23 "github.com/openimsdk/tools/errs" 24 "google.golang.org/grpc" 25 "google.golang.org/grpc/resolver" 26 ) 27 28 var ( 29 ErrConnIsNil = errs.New("conn is nil") 30 ErrConnIsNilButLocalNotNil = errs.New("conn is nil, but local is not nil") 31 ) 32 33 func (s *ZkClient) watch(ctx context.Context) { 34 for { 35 select { 36 case <-ctx.Done(): 37 s.logger.Info(ctx, "zk watch ctx done") 38 return 39 case event := <-s.eventChan: 40 s.logger.Debug(ctx, "zk eventChan recv new event", "event", event) 41 switch event.Type { 42 case zk.EventSession: 43 switch event.State { 44 case zk.StateHasSession: 45 if s.isRegistered && !s.isStateDisconnected { 46 s.logger.Debug(ctx, "zk session event stateHasSession, client prepare to create new temp node", "event", event) 47 node, err := s.CreateTempNode(s.rpcRegisterName, s.rpcRegisterAddr) 48 if err != nil { 49 s.logger.Error(ctx, "zk session event stateHasSession, create temp node error", err, "event", event) 50 } else { 51 s.node = node 52 } 53 } 54 case zk.StateDisconnected: 55 s.isStateDisconnected = true 56 case zk.StateConnected: 57 s.isStateDisconnected = false 58 default: 59 s.logger.Debug(ctx, "zk session event", "event", event) 60 } 61 case zk.EventNodeChildrenChanged: 62 s.logger.Debug(ctx, "zk event", "event", event) 63 l := strings.Split(event.Path, "/") 64 if len(l) > 1 { 65 serviceName := l[len(l)-1] 66 s.lock.Lock() 67 s.flushResolverAndDeleteLocal(serviceName) 68 s.lock.Unlock() 69 } 70 s.logger.Debug(ctx, "zk event handle success", "path", event.Path) 71 case zk.EventNodeDataChanged: 72 case zk.EventNodeCreated: 73 s.logger.Debug(ctx, "zk node create event", "event", event) 74 case zk.EventNodeDeleted: 75 case zk.EventNotWatching: 76 } 77 } 78 } 79 } 80 81 func (s *ZkClient) GetConnsRemote(ctx context.Context, serviceName string) (conns []resolver.Address, err error) { 82 err = s.ensureName(serviceName) 83 if err != nil { 84 return nil, err 85 } 86 87 path := s.getPath(serviceName) 88 _, _, _, err = s.conn.ChildrenW(path) 89 if err != nil { 90 return nil, errs.WrapMsg(err, "children watch error", "path", path) 91 } 92 childNodes, _, err := s.conn.Children(path) 93 if err != nil { 94 return nil, errs.WrapMsg(err, "get children error", "path", path) 95 } else { 96 for _, child := range childNodes { 97 fullPath := path + "/" + child 98 data, _, err := s.conn.Get(fullPath) 99 if err != nil { 100 return nil, errs.WrapMsg(err, "get children error", "fullPath", fullPath) 101 } 102 s.logger.Debug(ctx, "get addr from remote", "conn", string(data)) 103 conns = append(conns, resolver.Address{Addr: string(data), ServerName: serviceName}) 104 } 105 } 106 return conns, nil 107 } 108 109 func (s *ZkClient) GetUserIdHashGatewayHost(ctx context.Context, userId string) (string, error) { 110 s.logger.Warn(ctx, "not implement", errs.New("zkclinet not implement GetUserIdHashGatewayHost method")) 111 return "", nil 112 } 113 114 func (s *ZkClient) GetConns(ctx context.Context, serviceName string, opts ...grpc.DialOption) ([]*grpc.ClientConn, error) { 115 s.logger.Debug(ctx, "get conns from client", "serviceName", serviceName) 116 s.lock.Lock() 117 defer s.lock.Unlock() 118 conns := s.localConns[serviceName] 119 if len(conns) == 0 { 120 s.logger.Debug(ctx, "get conns from zk remote", "serviceName", serviceName) 121 addrs, err := s.GetConnsRemote(ctx, serviceName) 122 if err != nil { 123 return nil, err 124 } 125 if len(addrs) == 0 { 126 return nil, errs.New("addr is empty").WrapMsg("no conn for service", "serviceName", 127 serviceName, "local conn", s.localConns, "ZkServers", s.ZkServers, "zkRoot", s.zkRoot) 128 } 129 for _, addr := range addrs { 130 cc, err := grpc.DialContext(ctx, addr.Addr, append(s.options, opts...)...) 131 if err != nil { 132 s.logger.Error(context.Background(), "dialContext failed", err, "addr", addr.Addr, "opts", append(s.options, opts...)) 133 return nil, errs.WrapMsg(err, "DialContext failed", "addr.Addr", addr.Addr) 134 } 135 conns = append(conns, cc) 136 } 137 s.localConns[serviceName] = conns 138 } 139 return conns, nil 140 } 141 142 func (s *ZkClient) GetConn(ctx context.Context, serviceName string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { 143 newOpts := append(s.options, grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, s.balancerName))) 144 s.logger.Debug(context.Background(), "get conn from client", "serviceName", serviceName) 145 return grpc.DialContext(ctx, fmt.Sprintf("%s:///%s", s.scheme, serviceName), append(newOpts, opts...)...) 146 } 147 148 func (s *ZkClient) GetSelfConnTarget() string { 149 return s.rpcRegisterAddr 150 } 151 152 func (s *ZkClient) CloseConn(conn *grpc.ClientConn) { 153 conn.Close() 154 }