github.com/KYVENetwork/cometbft/v38@v38.0.3/proxy/client.go (about) 1 package proxy 2 3 import ( 4 "fmt" 5 6 abcicli "github.com/KYVENetwork/cometbft/v38/abci/client" 7 "github.com/KYVENetwork/cometbft/v38/abci/example/kvstore" 8 "github.com/KYVENetwork/cometbft/v38/abci/types" 9 cmtsync "github.com/KYVENetwork/cometbft/v38/libs/sync" 10 e2e "github.com/KYVENetwork/cometbft/v38/test/e2e/app" 11 ) 12 13 //go:generate ../scripts/mockery_generate.sh ClientCreator 14 15 // ClientCreator creates new ABCI clients. 16 type ClientCreator interface { 17 // NewABCIClient returns a new ABCI client. 18 NewABCIClient() (abcicli.Client, error) 19 } 20 21 //---------------------------------------------------- 22 // local proxy uses a mutex on an in-proc app 23 24 type localClientCreator struct { 25 mtx *cmtsync.Mutex 26 app types.Application 27 } 28 29 // NewLocalClientCreator returns a [ClientCreator] for the given app, which 30 // will be running locally. 31 // 32 // Maintains a single mutex over all new clients created with NewABCIClient. For 33 // a local client creator that uses a single mutex per new client, rather use 34 // [NewConnSyncLocalClientCreator]. 35 func NewLocalClientCreator(app types.Application) ClientCreator { 36 return &localClientCreator{ 37 mtx: new(cmtsync.Mutex), 38 app: app, 39 } 40 } 41 42 func (l *localClientCreator) NewABCIClient() (abcicli.Client, error) { 43 return abcicli.NewLocalClient(l.mtx, l.app), nil 44 } 45 46 //---------------------------------------------------- 47 // local proxy creates a new mutex for each client 48 49 type connSyncLocalClientCreator struct { 50 app types.Application 51 } 52 53 // NewConnSyncLocalClientCreator returns a local [ClientCreator] for the given 54 // app. 55 // 56 // Unlike [NewLocalClientCreator], this is a "connection-synchronized" local 57 // client creator, meaning each call to NewABCIClient returns an ABCI client 58 // that maintains its own mutex over the application (i.e. it is 59 // per-"connection" synchronized). 60 func NewConnSyncLocalClientCreator(app types.Application) ClientCreator { 61 return &connSyncLocalClientCreator{ 62 app: app, 63 } 64 } 65 66 func (c *connSyncLocalClientCreator) NewABCIClient() (abcicli.Client, error) { 67 // Specifying nil for the mutex causes each instance to create its own 68 // mutex. 69 return abcicli.NewLocalClient(nil, c.app), nil 70 } 71 72 //--------------------------------------------------------------- 73 // remote proxy opens new connections to an external app process 74 75 type remoteClientCreator struct { 76 addr string 77 transport string 78 mustConnect bool 79 } 80 81 // NewRemoteClientCreator returns a ClientCreator for the given address (e.g. 82 // "192.168.0.1") and transport (e.g. "tcp"). Set mustConnect to true if you 83 // want the client to connect before reporting success. 84 func NewRemoteClientCreator(addr, transport string, mustConnect bool) ClientCreator { 85 return &remoteClientCreator{ 86 addr: addr, 87 transport: transport, 88 mustConnect: mustConnect, 89 } 90 } 91 92 func (r *remoteClientCreator) NewABCIClient() (abcicli.Client, error) { 93 remoteApp, err := abcicli.NewClient(r.addr, r.transport, r.mustConnect) 94 if err != nil { 95 return nil, fmt.Errorf("failed to connect to proxy: %w", err) 96 } 97 98 return remoteApp, nil 99 } 100 101 // DefaultClientCreator returns a default [ClientCreator], which will create a 102 // local client if addr is one of "kvstore", "persistent_kvstore", "e2e", 103 // "noop". 104 // 105 // Otherwise a remote client will be created. 106 // 107 // Each of "kvstore", "persistent_kvstore" and "e2e" also currently have an 108 // "_connsync" variant (i.e. "kvstore_connsync", etc.), which attempts to 109 // replicate the same concurrency model as the remote client. 110 func DefaultClientCreator(addr, transport, dbDir string) ClientCreator { 111 switch addr { 112 case "kvstore": 113 return NewLocalClientCreator(kvstore.NewInMemoryApplication()) 114 case "kvstore_connsync": 115 return NewConnSyncLocalClientCreator(kvstore.NewInMemoryApplication()) 116 case "persistent_kvstore": 117 return NewLocalClientCreator(kvstore.NewPersistentApplication(dbDir)) 118 case "persistent_kvstore_connsync": 119 return NewConnSyncLocalClientCreator(kvstore.NewPersistentApplication(dbDir)) 120 case "e2e": 121 app, err := e2e.NewApplication(e2e.DefaultConfig(dbDir)) 122 if err != nil { 123 panic(err) 124 } 125 return NewLocalClientCreator(app) 126 case "e2e_connsync": 127 app, err := e2e.NewApplication(e2e.DefaultConfig(dbDir)) 128 if err != nil { 129 panic(err) 130 } 131 return NewConnSyncLocalClientCreator(app) 132 case "noop": 133 return NewLocalClientCreator(types.NewBaseApplication()) 134 default: 135 mustConnect := false // loop retrying 136 return NewRemoteClientCreator(addr, transport, mustConnect) 137 } 138 }