mirror of
https://github.com/tendermint/tendermint.git
synced 2026-02-04 11:02:06 +00:00
While I'd hoped to be able to make the socket client less weird, I think that this is a nice middle ground in terms of improving readability and removing the vestigal components without breaking anything or radically changing the underlying assumptions. In the future we'd want to have requests be identified by a request ID, and then we could drop the request tracking logic in the client entirely, and this is protocol breaking. The alternatives aren't substantively different than the current implementation.
89 lines
2.9 KiB
Go
89 lines
2.9 KiB
Go
package abciclient
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"github.com/tendermint/tendermint/abci/types"
|
|
"github.com/tendermint/tendermint/libs/log"
|
|
"github.com/tendermint/tendermint/libs/service"
|
|
)
|
|
|
|
const (
|
|
dialRetryIntervalSeconds = 3
|
|
echoRetryIntervalSeconds = 1
|
|
)
|
|
|
|
//go:generate ../../scripts/mockery_generate.sh Client
|
|
|
|
// Client defines an interface for an ABCI client.
|
|
//
|
|
// All methods return the appropriate protobuf ResponseXxx struct and
|
|
// an error.
|
|
//
|
|
// NOTE these are client errors, eg. ABCI socket connectivity issues.
|
|
// Application-related errors are reflected in response via ABCI error codes
|
|
// and logs.
|
|
type Client interface {
|
|
service.Service
|
|
|
|
Error() error
|
|
|
|
Flush(context.Context) error
|
|
Echo(ctx context.Context, msg string) (*types.ResponseEcho, error)
|
|
Info(context.Context, types.RequestInfo) (*types.ResponseInfo, error)
|
|
CheckTx(context.Context, types.RequestCheckTx) (*types.ResponseCheckTx, error)
|
|
Query(context.Context, types.RequestQuery) (*types.ResponseQuery, error)
|
|
Commit(context.Context) (*types.ResponseCommit, error)
|
|
InitChain(context.Context, types.RequestInitChain) (*types.ResponseInitChain, error)
|
|
PrepareProposal(context.Context, types.RequestPrepareProposal) (*types.ResponsePrepareProposal, error)
|
|
ProcessProposal(context.Context, types.RequestProcessProposal) (*types.ResponseProcessProposal, error)
|
|
ExtendVote(context.Context, types.RequestExtendVote) (*types.ResponseExtendVote, error)
|
|
VerifyVoteExtension(context.Context, types.RequestVerifyVoteExtension) (*types.ResponseVerifyVoteExtension, error)
|
|
FinalizeBlock(context.Context, types.RequestFinalizeBlock) (*types.ResponseFinalizeBlock, error)
|
|
ListSnapshots(context.Context, types.RequestListSnapshots) (*types.ResponseListSnapshots, error)
|
|
OfferSnapshot(context.Context, types.RequestOfferSnapshot) (*types.ResponseOfferSnapshot, error)
|
|
LoadSnapshotChunk(context.Context, types.RequestLoadSnapshotChunk) (*types.ResponseLoadSnapshotChunk, error)
|
|
ApplySnapshotChunk(context.Context, types.RequestApplySnapshotChunk) (*types.ResponseApplySnapshotChunk, error)
|
|
}
|
|
|
|
//----------------------------------------
|
|
|
|
// NewClient returns a new ABCI client of the specified transport type.
|
|
// It returns an error if the transport is not "socket" or "grpc"
|
|
func NewClient(logger log.Logger, addr, transport string, mustConnect bool) (Client, error) {
|
|
switch transport {
|
|
case "socket":
|
|
return NewSocketClient(logger, addr, mustConnect), nil
|
|
case "grpc":
|
|
return NewGRPCClient(logger, addr, mustConnect), nil
|
|
default:
|
|
return nil, fmt.Errorf("unknown abci transport %s", transport)
|
|
}
|
|
}
|
|
|
|
type requestAndResponse struct {
|
|
*types.Request
|
|
*types.Response
|
|
|
|
mtx sync.Mutex
|
|
signal chan struct{}
|
|
}
|
|
|
|
func makeReqRes(req *types.Request) *requestAndResponse {
|
|
return &requestAndResponse{
|
|
Request: req,
|
|
Response: nil,
|
|
signal: make(chan struct{}),
|
|
}
|
|
}
|
|
|
|
// markDone marks the ReqRes object as done.
|
|
func (r *requestAndResponse) markDone() {
|
|
r.mtx.Lock()
|
|
defer r.mtx.Unlock()
|
|
|
|
close(r.signal)
|
|
}
|