package picker import ( "context" "errors" "gim/pkg/logger" "go.uber.org/zap" "google.golang.org/grpc/balancer" "google.golang.org/grpc/balancer/base" ) // AddrPickerName 实现指定地址调用的RPC调用 const AddrPickerName = "addr" type addrKey struct{} var ErrNoSubConnSelect = errors.New("no sub conn select") func init() { balancer.Register(newBuilder()) } func ContextWithAddr(ctx context.Context, addr string) context.Context { return context.WithValue(ctx, addrKey{}, addr) } type addrPickerBuilder struct{} func newBuilder() balancer.Builder { return base.NewBalancerBuilder(AddrPickerName, &addrPickerBuilder{}, base.Config{HealthCheck: true}) } func (*addrPickerBuilder) Build(info base.PickerBuildInfo) balancer.Picker { if len(info.ReadySCs) == 0 { return base.NewErrPicker(balancer.ErrNoSubConnAvailable) } subConns := make(map[string]balancer.SubConn, len(info.ReadySCs)) for k, sc := range info.ReadySCs { subConns[sc.Address.Addr] = k } return &addrPicker{ subConnes: subConns, } } type addrPicker struct { subConnes map[string]balancer.SubConn } func (p *addrPicker) Pick(info balancer.PickInfo) (balancer.PickResult, error) { pr := balancer.PickResult{} address := info.Ctx.Value(addrKey{}).(string) sc, ok := p.subConnes[address] if !ok { logger.Logger.Error("Pick error", zap.String("address", address), zap.Any("subConnes", p.subConnes)) return pr, ErrNoSubConnSelect } pr.SubConn = sc return pr, nil }