package privval import ( "context" "time" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/service" ) const ( defaultMaxDialRetries = 10 defaultRetryWaitMilliseconds = 100 ) // SignerServiceEndpointOption sets an optional parameter on the SignerDialerEndpoint. type SignerServiceEndpointOption func(*SignerDialerEndpoint) // SignerDialerEndpointTimeoutReadWrite sets the read and write timeout for // connections from client processes. func SignerDialerEndpointTimeoutReadWrite(timeout time.Duration) SignerServiceEndpointOption { return func(ss *SignerDialerEndpoint) { ss.timeoutReadWrite = timeout } } // SignerDialerEndpointConnRetries sets the amount of attempted retries to // acceptNewConnection. func SignerDialerEndpointConnRetries(retries int) SignerServiceEndpointOption { return func(ss *SignerDialerEndpoint) { ss.maxConnRetries = retries } } // SignerDialerEndpointRetryWaitInterval sets the retry wait interval to a // custom value. func SignerDialerEndpointRetryWaitInterval(interval time.Duration) SignerServiceEndpointOption { return func(ss *SignerDialerEndpoint) { ss.retryWait = interval } } // SignerDialerEndpoint dials using its dialer and responds to any signature // requests using its privVal. type SignerDialerEndpoint struct { signerEndpoint dialer SocketDialer retryWait time.Duration maxConnRetries int } // NewSignerDialerEndpoint returns a SignerDialerEndpoint that will dial using the given // dialer and respond to any signature requests over the connection // using the given privVal. func NewSignerDialerEndpoint( logger log.Logger, dialer SocketDialer, options ...SignerServiceEndpointOption, ) *SignerDialerEndpoint { sd := &SignerDialerEndpoint{ dialer: dialer, retryWait: defaultRetryWaitMilliseconds * time.Millisecond, maxConnRetries: defaultMaxDialRetries, } sd.signerEndpoint.logger = logger sd.BaseService = *service.NewBaseService(logger, "SignerDialerEndpoint", sd) sd.signerEndpoint.timeoutReadWrite = defaultTimeoutReadWriteSeconds * time.Second for _, optionFunc := range options { optionFunc(sd) } return sd } func (sd *SignerDialerEndpoint) OnStart(context.Context) error { return nil } func (sd *SignerDialerEndpoint) OnStop() {} func (sd *SignerDialerEndpoint) ensureConnection(ctx context.Context) error { if sd.IsConnected() { return nil } timer := time.NewTimer(0) defer timer.Stop() retries := 0 for retries < sd.maxConnRetries { if err := ctx.Err(); err != nil { return err } conn, err := sd.dialer() if err != nil { retries++ sd.logger.Debug("SignerDialer: Reconnection failed", "retries", retries, "max", sd.maxConnRetries, "err", err) // Wait between retries timer.Reset(sd.retryWait) select { case <-ctx.Done(): return ctx.Err() case <-timer.C: } } else { sd.SetConnection(conn) sd.logger.Debug("SignerDialer: Connection Ready") return nil } } sd.logger.Debug("SignerDialer: Max retries exceeded", "retries", retries, "max", sd.maxConnRetries) return ErrNoConnection }