func (t *Transport) Call(method string, params, result interface{}) error {
	ctx := t.t.Context(nil)
Loop:
	for {
		connCh := make(chan *jsonrpc2.Conn, 1)
		select {
		case t.connCh <- connCh:
		case <-ctx.Done():
			return errors.Wrap(ctx.Err(), "context closed")
		}
		conn := <-connCh
		err := conn.Call(ctx, method, params, result)
		if err == nil {
			return nil
		}
		if err := ctx.Err(); err != nil {
			return errors.Wrap(err, "context closed")
		}
		if !t.autoReconnectEnabled {
			return errors.Wrap(err, "call failed")
		}
		err = errors.Cause(err)
		if _, ok := err.(*websocket.CloseError); ok || err == io.ErrUnexpectedEOF {
			select {
			case t.errCh <- errors.Wrap(err, "WebSocket closed"):
				continue Loop
			case <-ctx.Done():
				return errors.Wrap(ctx.Err(), "context closed")
			}
		}
		return errors.Wrap(err, "call failed")
	}
}
Call implements interfaces.CallCloser.
package websocket
import (
	"io"
	"context"
	"net"
	"time"
	"github.com/gorilla/websocket"
	"github.com/pkg/errors"
	"github.com/sourcegraph/jsonrpc2"
	tomb "gopkg.in/tomb.v2"
)
const (
	DefaultHandshakeTimeout      = 30 * time.Second
	DefaultWriteTimeout          = 10 * time.Second
	DefaultReadTimeout           = 20 * time.Second
	DefaultAutoReconnectMaxDelay = 1 * time.Minute
	InitialAutoReconnectDelay       = 1 * time.Second
	AutoReconnectBackoffCoefficient = 1.5
)
var netDialer net.Dialer
type Transport struct {
	urls         []string
	nextURLIndex int
	currentURL   string
	handshakeTimeout time.Duration
	readTimeout      time.Duration
	writeTimeout     time.Duration
	autoReconnectEnabled  bool
	autoReconnectMaxDelay time.Duration
	monitorChan chan<- interface{}
	connCh chan chan *jsonrpc2.Conn
	errCh  chan error
	t *tomb.Tomb
}
type Option func(*Transport)
func SetDialTimeout(timeout time.Duration) Option {
	return SetHandshakeTimeout(timeout)
}
func SetHandshakeTimeout(timeout time.Duration) Option {
	return func(t *Transport) {
		t.handshakeTimeout = timeout
	}
}
func SetReadTimeout(timeout time.Duration) Option {
	return func(t *Transport) {
		t.readTimeout = timeout
	}
}
func SetWriteTimeout(timeout time.Duration) Option {
	return func(t *Transport) {
		t.writeTimeout = timeout
	}
}
func SetReadWriteTimeout(timeout time.Duration) Option {
	return func(t *Transport) {
		t.readTimeout = timeout
		t.writeTimeout = timeout
	}
}
func SetAutoReconnectEnabled(enabled bool) Option {
	return func(t *Transport) {
		t.autoReconnectEnabled = enabled
	}
}
func SetAutoReconnectMaxDelay(delay time.Duration) Option {
	return func(t *Transport) {
		t.autoReconnectMaxDelay = delay
	}
}
func SetMonitor(monitorChan chan<- interface{}) Option {
	return func(t *Transport) {
		t.monitorChan = monitorChan
	}
}
func NewTransport(urls []string, options ...Option) (*Transport, error) {
	t := &Transport{
		urls:                  urls,
		handshakeTimeout:      DefaultHandshakeTimeout,
		readTimeout:           DefaultReadTimeout,
		writeTimeout:          DefaultWriteTimeout,
		autoReconnectMaxDelay: DefaultAutoReconnectMaxDelay,
		connCh:                make(chan chan *jsonrpc2.Conn),
		errCh:                 make(chan error),
		t:                     &tomb.Tomb{},
	}
	for _, opt := range options {
		opt(t)
	}
	t.t.Go(t.dialer)
	return t, nil
}