github.com/MetalBlockchain/metalgo@v1.11.9/api/info/client.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package info
     5  
     6  import (
     7  	"context"
     8  	"net/netip"
     9  	"time"
    10  
    11  	"github.com/MetalBlockchain/metalgo/ids"
    12  	"github.com/MetalBlockchain/metalgo/utils/rpc"
    13  	"github.com/MetalBlockchain/metalgo/vms/platformvm/signer"
    14  )
    15  
    16  var _ Client = (*client)(nil)
    17  
    18  // Client interface for an Info API Client.
    19  // See also AwaitBootstrapped.
    20  type Client interface {
    21  	GetNodeVersion(context.Context, ...rpc.Option) (*GetNodeVersionReply, error)
    22  	GetNodeID(context.Context, ...rpc.Option) (ids.NodeID, *signer.ProofOfPossession, error)
    23  	GetNodeIP(context.Context, ...rpc.Option) (netip.AddrPort, error)
    24  	GetNetworkID(context.Context, ...rpc.Option) (uint32, error)
    25  	GetNetworkName(context.Context, ...rpc.Option) (string, error)
    26  	GetBlockchainID(context.Context, string, ...rpc.Option) (ids.ID, error)
    27  	Peers(context.Context, ...rpc.Option) ([]Peer, error)
    28  	IsBootstrapped(context.Context, string, ...rpc.Option) (bool, error)
    29  	GetTxFee(context.Context, ...rpc.Option) (*GetTxFeeResponse, error)
    30  	Uptime(context.Context, ids.ID, ...rpc.Option) (*UptimeResponse, error)
    31  	GetVMs(context.Context, ...rpc.Option) (map[ids.ID][]string, error)
    32  }
    33  
    34  // Client implementation for an Info API Client
    35  type client struct {
    36  	requester rpc.EndpointRequester
    37  }
    38  
    39  // NewClient returns a new Info API Client
    40  func NewClient(uri string) Client {
    41  	return &client{requester: rpc.NewEndpointRequester(
    42  		uri + "/ext/info",
    43  	)}
    44  }
    45  
    46  func (c *client) GetNodeVersion(ctx context.Context, options ...rpc.Option) (*GetNodeVersionReply, error) {
    47  	res := &GetNodeVersionReply{}
    48  	err := c.requester.SendRequest(ctx, "info.getNodeVersion", struct{}{}, res, options...)
    49  	return res, err
    50  }
    51  
    52  func (c *client) GetNodeID(ctx context.Context, options ...rpc.Option) (ids.NodeID, *signer.ProofOfPossession, error) {
    53  	res := &GetNodeIDReply{}
    54  	err := c.requester.SendRequest(ctx, "info.getNodeID", struct{}{}, res, options...)
    55  	return res.NodeID, res.NodePOP, err
    56  }
    57  
    58  func (c *client) GetNodeIP(ctx context.Context, options ...rpc.Option) (netip.AddrPort, error) {
    59  	res := &GetNodeIPReply{}
    60  	err := c.requester.SendRequest(ctx, "info.getNodeIP", struct{}{}, res, options...)
    61  	return res.IP, err
    62  }
    63  
    64  func (c *client) GetNetworkID(ctx context.Context, options ...rpc.Option) (uint32, error) {
    65  	res := &GetNetworkIDReply{}
    66  	err := c.requester.SendRequest(ctx, "info.getNetworkID", struct{}{}, res, options...)
    67  	return uint32(res.NetworkID), err
    68  }
    69  
    70  func (c *client) GetNetworkName(ctx context.Context, options ...rpc.Option) (string, error) {
    71  	res := &GetNetworkNameReply{}
    72  	err := c.requester.SendRequest(ctx, "info.getNetworkName", struct{}{}, res, options...)
    73  	return res.NetworkName, err
    74  }
    75  
    76  func (c *client) GetBlockchainID(ctx context.Context, alias string, options ...rpc.Option) (ids.ID, error) {
    77  	res := &GetBlockchainIDReply{}
    78  	err := c.requester.SendRequest(ctx, "info.getBlockchainID", &GetBlockchainIDArgs{
    79  		Alias: alias,
    80  	}, res, options...)
    81  	return res.BlockchainID, err
    82  }
    83  
    84  func (c *client) Peers(ctx context.Context, options ...rpc.Option) ([]Peer, error) {
    85  	res := &PeersReply{}
    86  	err := c.requester.SendRequest(ctx, "info.peers", struct{}{}, res, options...)
    87  	return res.Peers, err
    88  }
    89  
    90  func (c *client) IsBootstrapped(ctx context.Context, chainID string, options ...rpc.Option) (bool, error) {
    91  	res := &IsBootstrappedResponse{}
    92  	err := c.requester.SendRequest(ctx, "info.isBootstrapped", &IsBootstrappedArgs{
    93  		Chain: chainID,
    94  	}, res, options...)
    95  	return res.IsBootstrapped, err
    96  }
    97  
    98  func (c *client) GetTxFee(ctx context.Context, options ...rpc.Option) (*GetTxFeeResponse, error) {
    99  	res := &GetTxFeeResponse{}
   100  	err := c.requester.SendRequest(ctx, "info.getTxFee", struct{}{}, res, options...)
   101  	return res, err
   102  }
   103  
   104  func (c *client) Uptime(ctx context.Context, subnetID ids.ID, options ...rpc.Option) (*UptimeResponse, error) {
   105  	res := &UptimeResponse{}
   106  	err := c.requester.SendRequest(ctx, "info.uptime", &UptimeRequest{
   107  		SubnetID: subnetID,
   108  	}, res, options...)
   109  	return res, err
   110  }
   111  
   112  func (c *client) GetVMs(ctx context.Context, options ...rpc.Option) (map[ids.ID][]string, error) {
   113  	res := &GetVMsReply{}
   114  	err := c.requester.SendRequest(ctx, "info.getVMs", struct{}{}, res, options...)
   115  	return res.VMs, err
   116  }
   117  
   118  // AwaitBootstrapped polls the node every [freq] to check if [chainID] has
   119  // finished bootstrapping. Returns true once [chainID] reports that it has
   120  // finished bootstrapping.
   121  // Only returns an error if [ctx] returns an error.
   122  func AwaitBootstrapped(ctx context.Context, c Client, chainID string, freq time.Duration, options ...rpc.Option) (bool, error) {
   123  	ticker := time.NewTicker(freq)
   124  	defer ticker.Stop()
   125  
   126  	for {
   127  		res, err := c.IsBootstrapped(ctx, chainID, options...)
   128  		if err == nil && res {
   129  			return true, nil
   130  		}
   131  
   132  		select {
   133  		case <-ticker.C:
   134  		case <-ctx.Done():
   135  			return false, ctx.Err()
   136  		}
   137  	}
   138  }