From 23c65655c2e96678eb9b496d1a058ca1c43ad449 Mon Sep 17 00:00:00 2001 From: lash Date: Sat, 11 Jan 2025 17:46:26 +0000 Subject: [PATCH] Separate remote http implementation from interface --- go.mod | 2 + go.sum | 4 + remote/account_service.go | 277 +------------------------------------- 3 files changed, 7 insertions(+), 276 deletions(-) diff --git a/go.mod b/go.mod index 255ee42..2d2b945 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,14 @@ go 1.23.4 require ( git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250111151614-46bf21b7b8bd + github.com/grassrootseconomics/eth-custodial v1.3.0-beta github.com/grassrootseconomics/ussd-data-service v1.2.0-beta github.com/stretchr/testify v1.9.0 ) require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/joho/godotenv v1.5.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/stretchr/objx v0.5.2 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index d0ddcf8..a2201ef 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,12 @@ git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250111151614 git.grassecon.net/grassrootseconomics/visedriver v0.8.0-beta.10.0.20250111151614-46bf21b7b8bd/go.mod h1:E6W7ZOa7ZvVr0Bc5ot0LNSwpSPYq4hXlAIvEPy3AJ7U= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU= +github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo= github.com/grassrootseconomics/ussd-data-service v1.2.0-beta h1:fn1gwbWIwHVEBtUC2zi5OqTlfI/5gU1SMk0fgGixIXk= github.com/grassrootseconomics/ussd-data-service v1.2.0-beta/go.mod h1:omfI0QtUwIdpu9gMcUqLMCG8O1XWjqJGBx1qUMiGWC0= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= diff --git a/remote/account_service.go b/remote/account_service.go index 3fbaaf0..9456efb 100644 --- a/remote/account_service.go +++ b/remote/account_service.go @@ -1,18 +1,9 @@ package remote import ( - "bytes" "context" - "encoding/json" - "errors" - "io" - "log" - "net/http" - "net/url" - "git.grassecon.net/grassrootseconomics/visedriver/config" - "git.grassecon.net/grassrootseconomics/visedriver/models" - "github.com/grassrootseconomics/eth-custodial/pkg/api" + "git.grassecon.net/grassrootseconomics/sarafu-api/models" dataserviceapi "github.com/grassrootseconomics/ussd-data-service/pkg/api" ) @@ -26,269 +17,3 @@ type AccountServiceInterface interface { TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) } - -type AccountService struct { -} - -// Parameters: -// - trackingId: A unique identifier for the account.This should be obtained from a previous call to -// CreateAccount or a similar function that returns an AccountResponse. The `trackingId` field in the -// AccountResponse struct can be used here to check the account status during a transaction. -// -// Returns: -// - string: The status of the transaction as a string. If there is an error during the request or processing, this will be an empty string. -// - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data. -// If no error occurs, this will be nil -func (as *AccountService) TrackAccountStatus(ctx context.Context, publicKey string) (*models.TrackStatusResult, error) { - var r models.TrackStatusResult - - ep, err := url.JoinPath(config.TrackURL, publicKey) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return &r, nil -} - -// CheckBalance retrieves the balance for a given public key from the custodial balance API endpoint. -// Parameters: -// - publicKey: The public key associated with the account whose balance needs to be checked. -func (as *AccountService) CheckBalance(ctx context.Context, publicKey string) (*models.BalanceResult, error) { - var balanceResult models.BalanceResult - - ep, err := url.JoinPath(config.BalanceURL, publicKey) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &balanceResult) - return &balanceResult, err -} - -// CreateAccount creates a new account in the custodial system. -// Returns: -// - *models.AccountResponse: A pointer to an AccountResponse struct containing the details of the created account. -// If there is an error during the request or processing, this will be nil. -// - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data. -// If no error occurs, this will be nil. -func (as *AccountService) CreateAccount(ctx context.Context) (*models.AccountResult, error) { - var r models.AccountResult - // Create a new request - req, err := http.NewRequest("POST", config.CreateAccountURL, nil) - if err != nil { - return nil, err - } - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return &r, nil -} - -// FetchVouchers retrieves the token holdings for a given public key from the data indexer API endpoint -// Parameters: -// - publicKey: The public key associated with the account. -func (as *AccountService) FetchVouchers(ctx context.Context, publicKey string) ([]dataserviceapi.TokenHoldings, error) { - var r struct { - Holdings []dataserviceapi.TokenHoldings `json:"holdings"` - } - - ep, err := url.JoinPath(config.VoucherHoldingsURL, publicKey) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return r.Holdings, nil -} - -// FetchTransactions retrieves the last 10 transactions for a given public key from the data indexer API endpoint -// Parameters: -// - publicKey: The public key associated with the account. -func (as *AccountService) FetchTransactions(ctx context.Context, publicKey string) ([]dataserviceapi.Last10TxResponse, error) { - var r struct { - Transfers []dataserviceapi.Last10TxResponse `json:"transfers"` - } - - ep, err := url.JoinPath(config.VoucherTransfersURL, publicKey) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return r.Transfers, nil -} - -// VoucherData retrieves voucher metadata from the data indexer API endpoint. -// Parameters: -// - address: The voucher address. -func (as *AccountService) VoucherData(ctx context.Context, address string) (*models.VoucherDataResult, error) { - var r struct { - TokenDetails models.VoucherDataResult `json:"tokenDetails"` - } - - ep, err := url.JoinPath(config.VoucherDataURL, address) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - return &r.TokenDetails, err -} - -// TokenTransfer creates a new token transfer in the custodial system. -// Returns: -// - *models.TokenTransferResponse: A pointer to an TokenTransferResponse struct containing the trackingId. -// If there is an error during the request or processing, this will be nil. -// - error: An error if any occurred during the HTTP request, reading the response, or unmarshalling the JSON data. -// If no error occurs, this will be nil. -func (as *AccountService) TokenTransfer(ctx context.Context, amount, from, to, tokenAddress string) (*models.TokenTransferResponse, error) { - var r models.TokenTransferResponse - - // Create request payload - payload := map[string]string{ - "amount": amount, - "from": from, - "to": to, - "tokenAddress": tokenAddress, - } - - payloadBytes, err := json.Marshal(payload) - if err != nil { - return nil, err - } - - // Create a new request - req, err := http.NewRequest("POST", config.TokenTransferURL, bytes.NewBuffer(payloadBytes)) - if err != nil { - return nil, err - } - _, err = doRequest(ctx, req, &r) - if err != nil { - return nil, err - } - - return &r, nil -} - -// CheckAliasAddress retrieves the address of an alias from the API endpoint. -// Parameters: -// - alias: The alias of the user. -func (as *AccountService) CheckAliasAddress(ctx context.Context, alias string) (*dataserviceapi.AliasAddress, error) { - var r dataserviceapi.AliasAddress - - ep, err := url.JoinPath(config.CheckAliasURL, alias) - if err != nil { - return nil, err - } - - req, err := http.NewRequest("GET", ep, nil) - if err != nil { - return nil, err - } - - _, err = doRequest(ctx, req, &r) - return &r, err -} - -func doRequest(ctx context.Context, req *http.Request, rcpt any) (*api.OKResponse, error) { - var okResponse api.OKResponse - var errResponse api.ErrResponse - - req.Header.Set("Authorization", "Bearer "+config.BearerToken) - req.Header.Set("Content-Type", "application/json") - - logRequestDetails(req) - - resp, err := http.DefaultClient.Do(req) - if err != nil { - log.Printf("Failed to make %s request to endpoint: %s with reason: %s", req.Method, req.URL, err.Error()) - errResponse.Description = err.Error() - return nil, err - } - defer resp.Body.Close() - - log.Printf("Received response for %s: Status Code: %d | Content-Type: %s", req.URL, resp.StatusCode, resp.Header.Get("Content-Type")) - body, err := io.ReadAll(resp.Body) - if err != nil { - return nil, err - } - if resp.StatusCode >= http.StatusBadRequest { - err := json.Unmarshal([]byte(body), &errResponse) - if err != nil { - return nil, err - } - return nil, errors.New(errResponse.Description) - } - err = json.Unmarshal([]byte(body), &okResponse) - if err != nil { - return nil, err - } - if len(okResponse.Result) == 0 { - return nil, errors.New("Empty api result") - } - - v, err := json.Marshal(okResponse.Result) - if err != nil { - return nil, err - } - - err = json.Unmarshal(v, &rcpt) - return &okResponse, err -} - -func logRequestDetails(req *http.Request) { - var bodyBytes []byte - contentType := req.Header.Get("Content-Type") - if req.Body != nil { - bodyBytes, err := io.ReadAll(req.Body) - if err != nil { - log.Printf("Error reading request body: %s", err) - return - } - req.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) - } else { - bodyBytes = []byte("-") - } - - log.Printf("URL: %s | Content-Type: %s | Method: %s| Request Body: %s", req.URL, contentType, req.Method, string(bodyBytes)) -}