func dialWebsocketMulti(ctx context.Context, addrs []string, path string, opts dialOpts) (*dialResult, error) {
	// Prioritise non-dial errors over the normal "connection refused".
	isDialError := func(err error) bool {
		netErr, ok := errors.Cause(err).(*net.OpError)
		if !ok {
			return false
		}
		return netErr.Op == "dial"
	}
	combine := func(initial, other error) error {
		if initial == nil || isDialError(initial) {
			return other
		}
		if isDialError(other) {
			return initial
		}
		return other
	}
	// Dial all addresses at reasonable intervals.
	try := parallel.NewTry(0, combine)
	defer try.Kill()
	// Make a context that's cancelled when the try
	// completes so that (for example) a slow DNS
	// query will be cancelled if a previous try succeeds.
	ctx, cancel := context.WithCancel(ctx)
	go func() {
		<-try.Dead()
		cancel()
	}()
	tried := make(map[string]bool)
	addrProvider := newAddressProvider(addrs, opts.DNSCache, opts.IPAddrResolver)
	for {
		resolvedAddr, err := addrProvider.next(ctx)
		if err == io.EOF {
			break
		} else if err != nil {
			recordTryError(try, err)
			continue
		}

		ipStr := net.JoinHostPort(resolvedAddr.ip, resolvedAddr.port)
		if tried[ipStr] {
			continue
		}
		tried[ipStr] = true
		err = startDialWebsocket(ctx, try, ipStr, resolvedAddr.host, path, opts)
		if err == parallel.ErrStopped {
			break
		}
		if err != nil {
			return nil, errors.Trace(err)
		}
		select {
		case <-opts.Clock.After(opts.DialAddressInterval):
		case <-try.Dead():
		}
	}
	try.Close()
	result, err := try.Result()
	if err != nil {
		return nil, errors.Trace(err)
	}
	return result.(*dialResult), nil
}
// dialWebsocketMulti dials a websocket with one of the provided addresses, the
// specified URL path, TLS configuration, and dial options. Each of the
// specified addresses will be attempted concurrently, and the first
// successful connection will be returned.
dialWebsocketMulti dials a websocket with one of the provided addresses, the
specified URL path, TLS configuration, and dial options. Each of the
specified addresses will be attempted concurrently, and the first
successful connection will be returned.
// dialWebsocketMulti dials a websocket with one of the provided addresses the // specified URL path TLS configuration and dial options . Each of the // specified addresses will be attempted concurrently and the first // successful connection will be returned .
func dialWebsocketMulti(ctx context.Context, addrs []string, path string, opts dialOpts) (*dialResult, error) {
	isDialError := func(err error) bool {
		netErr, ok := errors.Cause(err).(*net.OpError)
		if !ok {
			return false
		}
		return netErr.Op == "dial"
	}
	combine := func(initial, other error) error {
		if initial == nil || isDialError(initial) {
			return other
		}
		if isDialError(other) {
			return initial
		}
		return other
	}
	try := parallel.NewTry(0, combine)
	defer try.Kill()
	ctx, cancel := context.WithCancel(ctx)
	go func() {
		<-try.Dead()
		cancel()
	}()
	tried := make(map[string]bool)
	addrProvider := newAddressProvider(addrs, opts.DNSCache, opts.IPAddrResolver)
	for {
		resolvedAddr, err := addrProvider.next(ctx)
		if err == io.EOF {
			break
		} else if err != nil {
			recordTryError(try, err)
			continue
		}
		ipStr := net.JoinHostPort(resolvedAddr.ip, resolvedAddr.port)
		if tried[ipStr] {
			continue
		}
		tried[ipStr] = true
		err = startDialWebsocket(ctx, try, ipStr, resolvedAddr.host, path, opts)
		if err == parallel.ErrStopped {
			break
		}
		if err != nil {
			return nil, errors.Trace(err)
		}
		select {
		case <-opts.Clock.After(opts.DialAddressInterval):
		case <-try.Dead():
		}
	}
	try.Close()
	result, err := try.Result()
	if err != nil {
		return nil, errors.Trace(err)
	}
	return result.(*dialResult), nil
}
func dialWebsocketMulti ( ctx context . Context , addrs [ ] string , path string , opts dialOpts ) ( * dialResult , error ) { isDialError := func ( err error ) bool { netErr , ok := errors . Cause ( err ) . ( * net . OpError ) if ! ok { return false } return netErr . Op == " " } combine := func ( initial , other error ) error { if initial == nil || isDialError ( initial ) { return other } if isDialError ( other ) { return initial } return other } try := parallel . NewTry ( 0 , combine ) defer try . Kill ( ) ctx , cancel := context . WithCancel ( ctx ) go func ( ) { <- try . Dead ( ) cancel ( ) } ( ) tried := make ( map [ string ] bool ) addrProvider := newAddressProvider ( addrs , opts . DNSCache , opts . IPAddrResolver ) for { resolvedAddr , err := addrProvider . next ( ctx ) if err == io . EOF { break } else if err != nil { recordTryError ( try , err ) continue } ipStr := net . JoinHostPort ( resolvedAddr . ip , resolvedAddr . port ) if tried [ ipStr ] { continue } tried [ ipStr ] = true err = startDialWebsocket ( ctx , try , ipStr , resolvedAddr . host , path , opts ) if err == parallel . ErrStopped { break } if err != nil { return nil , errors . Trace ( err ) } select { case <- opts . Clock . After ( opts . DialAddressInterval ) : case <- try . Dead ( ) : } } try . Close ( ) result , err := try . Result ( ) if err != nil { return nil , errors . Trace ( err ) } return result . ( * dialResult ) , nil }
dialWebsocketMulti dials a websocket with one of the provided addresses, the
specified URL path, TLS configuration, and dial options.
dialWebsocketMulti dials a websocket with one of the provided addresses the specified URL path TLS configuration and dial options .
// Prioritise non-dial errors over the normal "connection refused". // Dial all addresses at reasonable intervals. // Make a context that's cancelled when the try // completes so that (for example) a slow DNS // query will be cancelled if a previous try succeeds.