Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 26 additions & 6 deletions client/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,45 @@ import (
)

type Account interface {
GetAccountChannels(req *account.AccountChannelsRequest) (*account.AccountChannelsResponse, XRPLResponse, error)
GetAccountChannels(req *account.AccountChannelsRequest, params XRPLPaginatedParams) ([]account.AccountChannelsResponse, []XRPLResponse, error)
GetAccountInfo(req *account.AccountInfoRequest) (*account.AccountInfoResponse, XRPLResponse, error)
}

type accountImpl struct {
client Client
}

func (a *accountImpl) GetAccountChannels(req *account.AccountChannelsRequest) (*account.AccountChannelsResponse, XRPLResponse, error) {
res, err := a.client.SendRequest(req)
func (a *accountImpl) GetAccountChannels(req *account.AccountChannelsRequest, params XRPLPaginatedParams) ([]account.AccountChannelsResponse, []XRPLResponse, error) {

err := req.Validate()
if err != nil {
return nil, nil, err
}
var acr account.AccountChannelsResponse
err = res.GetResult(&acr)

XRPLResponse, err := a.client.SendRequestPaginated(req, params.Limit, params.Paginated)
if err != nil {
return nil, nil, err
}
return &acr, res, nil

XRPLResponsePages := XRPLResponse.GetXRPLPages()

acrPages := []account.AccountChannelsResponse{}

// loop through pages and get result
for _, page := range XRPLResponsePages {

var acr account.AccountChannelsResponse

err = page.GetResult(&acr)
if err != nil {
return nil, nil, err
}

// append result to array
acrPages = append(acrPages, acr)
}

return acrPages, XRPLResponsePages, nil
}

func (a *accountImpl) GetAccountInfo(req *account.AccountInfoRequest) (*account.AccountInfoResponse, XRPLResponse, error) {
Expand Down
132 changes: 99 additions & 33 deletions client/accounts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,29 @@ import (
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/xyield/xrpl-go/model/client/account"
"github.com/xyield/xrpl-go/model/client/common"
)

type mockClient struct {
mock.Mock
}

type mockPaginatedResponse struct {
Pages []mockClientXrplResponse
}

func (r mockPaginatedResponse) GetXRPLPages() []XRPLResponse {
res := make([]XRPLResponse, len(r.Pages))
for i, page := range r.Pages {
res[i] = page
}
return res
}

type mockClientXrplResponse struct {
Result map[string]any
}

func (m *mockClientXrplResponse) GetResult(v any) error {
func (m mockClientXrplResponse) GetResult(v any) error {
dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{TagName: "json", Result: &v})
if err != nil {
return err
Expand All @@ -31,18 +42,28 @@ func (m *mockClientXrplResponse) GetResult(v any) error {
return nil
}

func (m mockClientXrplResponse) GetMarker() any {
return nil
}

func (m *mockClient) SendRequest(req XRPLRequest) (XRPLResponse, error) {
args := m.Called(req)
return args.Get(0).(XRPLResponse), args.Error(1)
}

func (m *mockClient) SendRequestPaginated(reqParams XRPLPaginatedRequest, limit int, pagination bool) (XRPLPaginatedResponse, error) {
args := m.Called(reqParams, limit, pagination)
return args.Get(0).(XRPLPaginatedResponse), args.Error(1)
}

func TestGetAccountChannels(t *testing.T) {

tt := []struct {
description string
input account.AccountChannelsRequest
sendRequestResult mockClientXrplResponse
output account.AccountChannelsResponse
paginationParams XRPLPaginatedParams
sendRequestResult mockPaginatedResponse
output []account.AccountChannelsResponse
expectedErr error
}{
{
Expand All @@ -51,43 +72,71 @@ func TestGetAccountChannels(t *testing.T) {
Account: "rLHmBn4fT92w4F6ViyYbjoizLTo83tHTHu",
DestinationAccount: "rnZvsWuLem5Ha46AZs61jLWR9R5esinkG3",
},
sendRequestResult: mockClientXrplResponse{
Result: map[string]any{
"account": 123,
"destination_account": "rnZvsWuLem5Ha46AZs61jLWR9R5esinkG3",
},
sendRequestResult: mockPaginatedResponse{
Pages: []mockClientXrplResponse{{
Result: map[string]any{
"account": 123,
"destination_account": "rnZvsWuLem5Ha46AZs61jLWR9R5esinkG3",
},
}},
},
output: account.AccountChannelsResponse{},
output: []account.AccountChannelsResponse{},
expectedErr: errors.New("1 error(s) decoding:\n\n* 'account' expected type 'types.Address', got unconvertible type 'int', value: '123'"),
},
{
description: "successful response",
input: account.AccountChannelsRequest{
Account: "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
DestinationAccount: "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
LedgerIndex: common.VALIDATED,
},
sendRequestResult: mockClientXrplResponse{
Result: map[string]any{
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"channels": []any{
map[string]any{
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"amount": "1000",
"balance": "0",
"channel_id": "C7F634794B79DB40E87179A9D1BF05D05797AE7E92DF8E93FD6656E8C4BE3AE7",
"destination_account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"public_key": "aBR7mdD75Ycs8DRhMgQ4EMUEmBArF8SEh1hfjrT2V9DQTLNbJVqw",
"public_key_hex": "03CFD18E689434F032A4E84C63E2A3A6472D684EAF4FD52CA67742F3E24BAE81B2",
"settle_delay": 60,
paginationParams: XRPLPaginatedParams{
Limit: 0,
Paginated: true,
},
sendRequestResult: mockPaginatedResponse{
Pages: []mockClientXrplResponse{{
Result: map[string]any{
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"channels": []any{
map[string]any{
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"amount": "1000",
"balance": "0",
"channel_id": "C7F634794B79DB40E87179A9D1BF05D05797AE7E92DF8E93FD6656E8C4BE3AE7",
"destination_account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"public_key": "aBR7mdD75Ycs8DRhMgQ4EMUEmBArF8SEh1hfjrT2V9DQTLNbJVqw",
"public_key_hex": "03CFD18E689434F032A4E84C63E2A3A6472D684EAF4FD52CA67742F3E24BAE81B2",
"settle_delay": 60,
},
},
"ledger_hash": "1EDBBA3C793863366DF5B31C2174B6B5E6DF6DB89A7212B86838489148E2A581",
"ledger_index": 71766314,
"validated": true,
"marker": "pageMarker1",
},
"ledger_hash": "1EDBBA3C793863366DF5B31C2174B6B5E6DF6DB89A7212B86838489148E2A581",
"ledger_index": 71766314,
"validated": true,
},
{
Result: map[string]any{
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"channels": []any{
map[string]any{
"account": "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
"amount": "1000",
"balance": "0",
"channel_id": "C7F634794B79DB40E87179A9D1BF05D05797AE7E92DF8E93FD6656E8C4BE3AE7",
"destination_account": "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
"public_key": "aBR7mdD75Ycs8DRhMgQ4EMUEmBArF8SEh1hfjrT2V9DQTLNbJVqw",
"public_key_hex": "03CFD18E689434F032A4E84C63E2A3A6472D684EAF4FD52CA67742F3E24BAE81B2",
"settle_delay": 60,
},
},
"ledger_hash": "1EDBBA3C793863366DF5B31C2174B6B5E6DF6DB89A7212B86838489148E2A581",
"ledger_index": 71766314,
"validated": true,
},
}},
},
output: account.AccountChannelsResponse{
output: []account.AccountChannelsResponse{{
Account: "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
LedgerIndex: 71766314,
LedgerHash: "1EDBBA3C793863366DF5B31C2174B6B5E6DF6DB89A7212B86838489148E2A581",
Expand All @@ -104,7 +153,26 @@ func TestGetAccountChannels(t *testing.T) {
},
},
Validated: true,
Marker: "pageMarker1",
},
{
Account: "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
LedgerIndex: 71766314,
LedgerHash: "1EDBBA3C793863366DF5B31C2174B6B5E6DF6DB89A7212B86838489148E2A581",
Channels: []account.ChannelResult{
{
Account: "rf1BiGeXwwQoi8Z2ueFYTEXSwuJYfV2Jpn",
Amount: "1000",
Balance: "0",
ChannelID: "C7F634794B79DB40E87179A9D1BF05D05797AE7E92DF8E93FD6656E8C4BE3AE7",
DestinationAccount: "ra5nK24KXen9AHvsdFTKHSANinZseWnPcX",
PublicKey: "aBR7mdD75Ycs8DRhMgQ4EMUEmBArF8SEh1hfjrT2V9DQTLNbJVqw",
PublicKeyHex: "03CFD18E689434F032A4E84C63E2A3A6472D684EAF4FD52CA67742F3E24BAE81B2",
SettleDelay: 60,
},
},
Validated: true,
}},
expectedErr: nil,
},
}
Expand All @@ -115,17 +183,15 @@ func TestGetAccountChannels(t *testing.T) {

cl := new(mockClient)
a := &accountImpl{client: cl}
cl.On("SendRequestPaginated", &tc.input, tc.paginationParams.Limit, tc.paginationParams.Paginated).Return(tc.sendRequestResult, nil)

cl.On("SendRequest", &tc.input).Return(&tc.sendRequestResult, nil)

res, _, err := a.GetAccountChannels(&tc.input)
res, _, err := a.GetAccountChannels(&tc.input, tc.paginationParams)

if tc.expectedErr != nil {
require.EqualError(t, err, tc.expectedErr.Error())
} else {
require.Equal(t, &tc.output, res)
require.Equal(t, tc.output, res)
}

})
}
}
17 changes: 17 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package client

type Client interface {
SendRequest(req XRPLRequest) (XRPLResponse, error)
SendRequestPaginated(reqParams XRPLPaginatedRequest, limit int, pagination bool) (XRPLPaginatedResponse, error)
}

type XRPLClient struct {
Expand All @@ -16,6 +17,22 @@ type XRPLRequest interface {

type XRPLResponse interface {
GetResult(v any) error
GetMarker() any
}

type XRPLPaginatedParams struct {
Limit int
Paginated bool
}

type XRPLPaginatedRequest interface {
Method() string
Validate() error
SetMarker(m any)
}

type XRPLPaginatedResponse interface {
GetXRPLPages() []XRPLResponse
}

type XRPLResponseWarning struct {
Expand Down
77 changes: 77 additions & 0 deletions client/jsonrpc/jsonrpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,3 +186,80 @@ func CheckForError(res *http.Response) (jsonrpcmodels.JsonRpcResponse, error) {

return jr, nil
}

func (c *JsonRpcClient) SendRequestPaginated(reqParams client.XRPLPaginatedRequest, limit int, pagination bool) (client.XRPLPaginatedResponse, error) {

responsePages := []jsonrpcmodels.JsonRpcResponse{}

if !pagination {

res, err := c.SendRequest(reqParams)
if err != nil {
return nil, err
}
jr, ok := res.(*jsonrpcmodels.JsonRpcResponse)
if !ok {
return nil, errors.New("problem casting XRPLResponse to JsonRpcResponse")
}

responsePages = append(responsePages, *jr)

} else {

// set default limit if nothing passed in
if limit == 0 {
limit = 10
}

err := GetPages(c, reqParams, &responsePages, limit, 0)
if err != nil {
return nil, err
}
}

res := jsonrpcmodels.JsonRpcPaginationResponse{
Pages: responsePages,
}

return res, nil
}

func GetPages(c *JsonRpcClient, reqParams client.XRPLPaginatedRequest, responsePages *[]jsonrpcmodels.JsonRpcResponse, limit int, counter int) error {

if limit == counter {
return nil
}

// get first page of results
result, err := c.SendRequest(reqParams)
if err != nil {
return err
}

fmt.Printf("Paginated response %v : ", result)

// cast to JsonRpcResponse
jr, ok := result.(*jsonrpcmodels.JsonRpcResponse)
if !ok {
return errors.New("problem casting XRPLResponse to JsonRpcResponse")
}

// add result to array
*responsePages = append(*responsePages, *jr)

// check for marker
marker := jr.GetMarker()
if marker != nil {

// set marker in request to get next page
reqParams.SetMarker(marker)

// increase counter
counter++

// make next request
return GetPages(c, reqParams, responsePages, limit, counter)
}

return nil
}
Loading