package proxy import ( "fmt" "io" abcicli "github.com/tendermint/tendermint/abci/client" "github.com/tendermint/tendermint/abci/example/counter" "github.com/tendermint/tendermint/abci/example/kvstore" "github.com/tendermint/tendermint/abci/types" tmsync "github.com/tendermint/tendermint/libs/sync" ) // ClientCreator creates new ABCI clients. type ClientCreator interface { // NewABCIClient returns a new ABCI client. NewABCIClient() (abcicli.Client, error) } //---------------------------------------------------- // local proxy uses a mutex on an in-proc app type localClientCreator struct { mtx *tmsync.RWMutex app types.Application } // NewLocalClientCreator returns a ClientCreator for the given app, // which will be running locally. func NewLocalClientCreator(app types.Application) ClientCreator { return &localClientCreator{ mtx: new(tmsync.RWMutex), app: app, } } func (l *localClientCreator) NewABCIClient() (abcicli.Client, error) { return abcicli.NewLocalClient(l.mtx, l.app), nil } //--------------------------------------------------------------- // remote proxy opens new connections to an external app process type remoteClientCreator struct { addr string transport string mustConnect bool } // NewRemoteClientCreator returns a ClientCreator for the given address (e.g. // "192.168.0.1") and transport (e.g. "tcp"). Set mustConnect to true if you // want the client to connect before reporting success. func NewRemoteClientCreator(addr, transport string, mustConnect bool) ClientCreator { return &remoteClientCreator{ addr: addr, transport: transport, mustConnect: mustConnect, } } func (r *remoteClientCreator) NewABCIClient() (abcicli.Client, error) { remoteApp, err := abcicli.NewClient(r.addr, r.transport, r.mustConnect) if err != nil { return nil, fmt.Errorf("failed to connect to proxy: %w", err) } return remoteApp, nil } // DefaultClientCreator returns a default ClientCreator, which will create a // local client if addr is one of: 'counter', 'counter_serial', 'kvstore', // 'persistent_kvstore' or 'noop', otherwise - a remote client. // // The Closer is a noop except for persistent_kvstore applications, // which will clean up the store. func DefaultClientCreator(addr, transport, dbDir string) (ClientCreator, io.Closer) { switch addr { case "counter": return NewLocalClientCreator(counter.NewApplication(false)), noopCloser{} case "counter_serial": return NewLocalClientCreator(counter.NewApplication(true)), noopCloser{} case "kvstore": return NewLocalClientCreator(kvstore.NewApplication()), noopCloser{} case "persistent_kvstore": app := kvstore.NewPersistentKVStoreApplication(dbDir) return NewLocalClientCreator(app), app case "noop": return NewLocalClientCreator(types.NewBaseApplication()), noopCloser{} default: mustConnect := false // loop retrying return NewRemoteClientCreator(addr, transport, mustConnect), noopCloser{} } } type noopCloser struct{} func (noopCloser) Close() error { return nil }