github.com/algorand/go-algorand-sdk@v1.24.0/client/kmd/kmd.go (about)

     1  package kmd
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net/http"
     7  	"time"
     8  
     9  	"github.com/algorand/go-algorand-sdk/encoding/json"
    10  )
    11  
    12  const (
    13  	timeoutSecs    = 120
    14  	kmdTokenHeader = "X-KMD-API-Token"
    15  )
    16  
    17  // Client is the client used to interact with the kmd API
    18  type Client struct {
    19  	httpClient http.Client
    20  	apiToken   string
    21  	address    string
    22  }
    23  
    24  func makeHTTPClient() http.Client {
    25  	client := http.Client{
    26  		Timeout: timeoutSecs * time.Second,
    27  	}
    28  	return client
    29  }
    30  
    31  // MakeClient instantiates a Client for the given address and apiToken
    32  func MakeClient(address string, apiToken string) (Client, error) {
    33  	kcl := Client{
    34  		httpClient: makeHTTPClient(),
    35  		apiToken:   apiToken,
    36  		address:    address,
    37  	}
    38  	return kcl, nil
    39  }
    40  
    41  // DoV1Request accepts a request from kmdapi/requests and
    42  func (kcl Client) DoV1Request(req APIV1Request, resp APIV1Response) error {
    43  	var body []byte
    44  
    45  	// Get the path and method for this request type
    46  	reqPath, reqMethod, err := getPathAndMethod(req)
    47  	if err != nil {
    48  		return err
    49  	}
    50  
    51  	// Encode the request
    52  	body = json.Encode(req)
    53  	fullPath := fmt.Sprintf("%s/%s", kcl.address, reqPath)
    54  	hreq, err := http.NewRequest(reqMethod, fullPath, bytes.NewReader(body))
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	// Add the auth token
    60  	hreq.Header.Add(kmdTokenHeader, kcl.apiToken)
    61  
    62  	// Send the request
    63  	hresp, err := kcl.httpClient.Do(hreq)
    64  	if err != nil {
    65  		return err
    66  	}
    67  
    68  	decoder := json.NewDecoder(hresp.Body)
    69  	err = decoder.Decode(resp)
    70  	hresp.Body.Close()
    71  	if err != nil {
    72  		return err
    73  	}
    74  
    75  	// Check if this was an error response
    76  	err = resp.GetError()
    77  	if err != nil {
    78  		return err
    79  	}
    80  
    81  	return nil
    82  }
    83  
    84  // getPathAndMethod infers the request path and method from the request type
    85  func getPathAndMethod(req APIV1Request) (reqPath string, reqMethod string, err error) {
    86  	switch req.(type) {
    87  	default:
    88  		err = fmt.Errorf("unknown request type")
    89  	case VersionsRequest:
    90  		reqPath = "versions"
    91  		reqMethod = "GET"
    92  	case ListWalletsRequest:
    93  		reqPath = "v1/wallets"
    94  		reqMethod = "GET"
    95  	case CreateWalletRequest:
    96  		reqPath = "v1/wallet"
    97  		reqMethod = "POST"
    98  	case InitWalletHandleRequest:
    99  		reqPath = "v1/wallet/init"
   100  		reqMethod = "POST"
   101  	case ReleaseWalletHandleRequest:
   102  		reqPath = "v1/wallet/release"
   103  		reqMethod = "POST"
   104  	case RenewWalletHandleRequest:
   105  		reqPath = "v1/wallet/renew"
   106  		reqMethod = "POST"
   107  	case RenameWalletRequest:
   108  		reqPath = "v1/wallet/rename"
   109  		reqMethod = "POST"
   110  	case GetWalletRequest:
   111  		reqPath = "v1/wallet/info"
   112  		reqMethod = "POST"
   113  	case ExportMasterDerivationKeyRequest:
   114  		reqPath = "v1/master-key/export"
   115  		reqMethod = "POST"
   116  	case ImportKeyRequest:
   117  		reqPath = "v1/key/import"
   118  		reqMethod = "POST"
   119  	case ExportKeyRequest:
   120  		reqPath = "v1/key/export"
   121  		reqMethod = "POST"
   122  	case GenerateKeyRequest:
   123  		reqPath = "v1/key"
   124  		reqMethod = "POST"
   125  	case DeleteKeyRequest:
   126  		reqPath = "v1/key"
   127  		reqMethod = "DELETE"
   128  	case ListKeysRequest:
   129  		reqPath = "v1/key/list"
   130  		reqMethod = "POST"
   131  	case SignTransactionRequest:
   132  		reqPath = "v1/transaction/sign"
   133  		reqMethod = "POST"
   134  	case ListMultisigRequest:
   135  		reqPath = "v1/multisig/list"
   136  		reqMethod = "POST"
   137  	case ImportMultisigRequest:
   138  		reqPath = "v1/multisig/import"
   139  		reqMethod = "POST"
   140  	case ExportMultisigRequest:
   141  		reqPath = "v1/multisig/export"
   142  		reqMethod = "POST"
   143  	case DeleteMultisigRequest:
   144  		reqPath = "v1/multisig"
   145  		reqMethod = "DELETE"
   146  	case SignMultisigTransactionRequest:
   147  		reqPath = "v1/multisig/sign"
   148  		reqMethod = "POST"
   149  	}
   150  	return
   151  }