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  }