forked from TrueCloudLab/frostfs-node
ad7ad12a0c
There is a need to work with a set of Neo RPC nodes in order not to depend on the failure of some nodes while others are active. Support "multi-client" mode of morph `Client` entity. If instance is not "multi-client", it works as before. Constructor `New` creates multi-client, and each method performs iterating over the fixed set of endpoints until success. Opened client connections are cached (without eviction for now). Storage (as earlier) and IR (from now) nodes can be configured with multiple Neo endpoints. As above, `New` creates multi-client instance, so we don't need initialization changes on app-side. `Wait` and `GetDesignateHash` methods of `Client` return an error from now to detect connection errors. `NotaryEnabled` method is removed as unused. Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
154 lines
3.6 KiB
Go
154 lines
3.6 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
|
"github.com/nspcc-dev/neofs-node/pkg/util/logger"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// Option is a client configuration change function.
|
|
type Option func(*cfg)
|
|
|
|
// groups the configurations with default values.
|
|
type cfg struct {
|
|
ctx context.Context // neo-go client context
|
|
|
|
dialTimeout time.Duration // client dial timeout
|
|
|
|
logger *logger.Logger // logging component
|
|
|
|
gas util.Uint160 // native gas script-hash
|
|
|
|
waitInterval time.Duration
|
|
|
|
signer *transaction.Signer
|
|
|
|
extraEndpoints []string
|
|
}
|
|
|
|
const (
|
|
defaultDialTimeout = 5 * time.Second
|
|
defaultWaitInterval = 500 * time.Millisecond
|
|
)
|
|
|
|
func defaultConfig() *cfg {
|
|
return &cfg{
|
|
ctx: context.Background(),
|
|
dialTimeout: defaultDialTimeout,
|
|
logger: zap.L(),
|
|
waitInterval: defaultWaitInterval,
|
|
signer: &transaction.Signer{
|
|
Scopes: transaction.Global,
|
|
},
|
|
}
|
|
}
|
|
|
|
// New creates, initializes and returns the Client instance.
|
|
// Notary support should be enabled with EnableNotarySupport client
|
|
// method separately.
|
|
//
|
|
// If private key is nil, it panics.
|
|
//
|
|
// Other values are set according to provided options, or by default:
|
|
// * client context: Background;
|
|
// * dial timeout: 5s;
|
|
// * blockchain network type: netmode.PrivNet;
|
|
// * logger: zap.L().
|
|
//
|
|
// If desired option satisfies the default value, it can be omitted.
|
|
// If multiple options of the same config value are supplied,
|
|
// the option with the highest index in the arguments will be used.
|
|
func New(key *keys.PrivateKey, endpoint string, opts ...Option) (*Client, error) {
|
|
if key == nil {
|
|
panic("empty private key")
|
|
}
|
|
|
|
// build default configuration
|
|
cfg := defaultConfig()
|
|
|
|
// apply options
|
|
for _, opt := range opts {
|
|
opt(cfg)
|
|
}
|
|
|
|
endpoints := append(cfg.extraEndpoints, endpoint)
|
|
|
|
return &Client{
|
|
multiClient: &multiClient{
|
|
cfg: *cfg,
|
|
account: wallet.NewAccountFromPrivateKey(key),
|
|
endpoints: endpoints,
|
|
clients: make(map[string]*Client, len(endpoints)),
|
|
},
|
|
}, nil
|
|
}
|
|
|
|
// WithContext returns a client constructor option that
|
|
// specifies the neo-go client context.
|
|
//
|
|
// Ignores nil value.
|
|
//
|
|
// If option not provided, context.Background() is used.
|
|
func WithContext(ctx context.Context) Option {
|
|
return func(c *cfg) {
|
|
if ctx != nil {
|
|
c.ctx = ctx
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithDialTimeout returns a client constructor option
|
|
// that specifies neo-go client dial timeout duration.
|
|
//
|
|
// Ignores non-positive value.
|
|
//
|
|
// If option not provided, 5s timeout is used.
|
|
func WithDialTimeout(dur time.Duration) Option {
|
|
return func(c *cfg) {
|
|
if dur > 0 {
|
|
c.dialTimeout = dur
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithLogger returns a client constructor option
|
|
// that specifies the component for writing log messages.
|
|
//
|
|
// Ignores nil value.
|
|
//
|
|
// If option not provided, zap.L() is used.
|
|
func WithLogger(logger *logger.Logger) Option {
|
|
return func(c *cfg) {
|
|
if logger != nil {
|
|
c.logger = logger
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithSigner returns a client constructor option
|
|
// that specifies the signer and the scope of the transaction.
|
|
//
|
|
// Ignores nil value.
|
|
//
|
|
// If option not provided, signer with global scope is used.
|
|
func WithSigner(signer *transaction.Signer) Option {
|
|
return func(c *cfg) {
|
|
if signer != nil {
|
|
c.signer = signer
|
|
}
|
|
}
|
|
}
|
|
|
|
// WithExtraEndpoints returns a client constructor option
|
|
// that specifies additional Neo rpc endpoints.
|
|
func WithExtraEndpoints(endpoints []string) Option {
|
|
return func(c *cfg) {
|
|
c.extraEndpoints = append(c.extraEndpoints, endpoints...)
|
|
}
|
|
}
|