package selector import ( "context" "sync/atomic" ) var ( _ Rebalancer = (*Default)(nil) _ Builder = (*DefaultBuilder)(nil) ) type Default struct { NodeBuilder WeightedNodeBuilder Balancer Balancer nodes atomic.Value } func (d *Default) Select(ctx context.Context, opts ...SelectOption) (selected Node, done DoneFunc, err error) { var ( options SelectOptions candidates []WeightedNode ) nodes, ok := d.nodes.Load().([]WeightedNode) if !ok { return nil, nil, ErrNoAvailable } for _, o := range opts { o(&options) } if len(options.NodeFilters) > 0 { newNodes := make([]Node, len(nodes)) for i, wc := range nodes { newNodes[i] = wc } for _, filter := range options.NodeFilters { newNodes = filter(ctx, newNodes) } candidates = make([]WeightedNode, len(newNodes)) for i, n := range newNodes { candidates[i] = n.(WeightedNode) } } else { candidates = nodes } wn, done, err := d.Balancer.Pick(ctx, candidates) if err != nil { return nil, nil, err } p, ok := FromPeerContext(ctx) if ok { p.Node = wn.Raw() } return wn.Raw(), done, nil } func (d *Default) Apply(nodes []Node) { weightedNodes := make([]WeightedNode, 0, len(nodes)) for _, v := range nodes { weightedNodes = append(weightedNodes, d.NodeBuilder.Build(v)) } d.nodes.Store(weightedNodes) } type DefaultBuilder struct { Node WeightedNodeBuilder Balancer BalancerBuilder } func (d *DefaultBuilder) Build() Selector { return &Default{ NodeBuilder: d.Node, Balancer: d.Balancer.Builder(), } }