Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New horizon.Client methods #47

Merged
merged 2 commits into from
Mar 24, 2017
Merged
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
78 changes: 73 additions & 5 deletions clients/horizon/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,44 @@ func (c *Client) LoadAccount(accountID string) (account Account, err error) {
return
}

// LoadAccountOffers loads the account offers from horizon. err can be either error
// object or horizon.Error object.
func (c *Client) LoadAccountOffers(accountID string, params ...interface{}) (offers OffersPage, err error) {
query := url.Values{}
for _, param := range params {
switch param := param.(type) {
case Limit:
query.Add("limit", strconv.Itoa(int(param)))
case Order:
query.Add("order", string(param))
case Cursor:
query.Add("cursor", string(param))
default:
err = fmt.Errorf("Undefined parameter: %+v", param)
return
}
}

var q string
if len(query) > 0 {
q = "?" + query.Encode()
}

url := fmt.Sprintf("%s/accounts/%s/offers%s", c.URL, accountID, q)
resp, err := c.HTTP.Get(url)
if err != nil {
return
}

err = decodeResponse(resp, &offers)
return
}

// LoadMemo loads memo for a transaction in Payment
func (c *Client) LoadMemo(p *Payment) (err error) {
res, err := c.HTTP.Get(p.Links.Transaction.Href)
if err != nil {
return errors.Wrap(err, "load transaciton failed")
return errors.Wrap(err, "load transaction failed")
}
defer res.Body.Close()
return json.NewDecoder(res.Body).Decode(&p.Memo)
Expand All @@ -63,9 +96,30 @@ func (c *Client) SequenceForAccount(
return xdr.SequenceNumber(seq), nil
}

func (c *Client) stream(url string, cursor *string, handler func(data []byte) error) (err error) {
// LoadOrderBook loads order book for given selling and buying assets.
func (c *Client) LoadOrderBook(selling Asset, buying Asset) (orderBook OrderBookSummary, err error) {
query := url.Values{}

query.Add("selling_asset_type", selling.Type)
query.Add("selling_asset_code", selling.Code)
query.Add("selling_asset_issuer", selling.Issuer)

query.Add("buying_asset_type", buying.Type)
query.Add("buying_asset_code", buying.Code)
query.Add("buying_asset_issuer", buying.Issuer)

resp, err := c.HTTP.Get(c.URL + "/order_book?" + query.Encode())
if err != nil {
return
}

err = decodeResponse(resp, &orderBook)
return
}

func (c *Client) stream(url string, cursor *Cursor, handler func(data []byte) error) (err error) {
if cursor != nil {
url += "?cursor=" + *cursor
url += "?cursor=" + string(*cursor)
}

req, err := http.NewRequest("GET", url, nil)
Expand Down Expand Up @@ -120,8 +174,22 @@ func (c *Client) stream(url string, cursor *string, handler func(data []byte) er
return nil
}

// StreamLedgers streams incoming ledgers
func (c *Client) StreamLedgers(cursor *Cursor, handler LedgerHandler) (err error) {
url := fmt.Sprintf("%s/ledgers", c.URL)
return c.stream(url, cursor, func(data []byte) error {
var ledger Ledger
err = json.Unmarshal(data, &ledger)
if err != nil {
return errors.Wrap(err, "Error unmarshaling data")
}
handler(ledger)
return nil
})
}

// StreamPayments streams incoming payments
func (c *Client) StreamPayments(accountID string, cursor *string, handler PaymentHandler) (err error) {
func (c *Client) StreamPayments(accountID string, cursor *Cursor, handler PaymentHandler) (err error) {
url := fmt.Sprintf("%s/accounts/%s/payments", c.URL, accountID)
return c.stream(url, cursor, func(data []byte) error {
var payment Payment
Expand All @@ -135,7 +203,7 @@ func (c *Client) StreamPayments(accountID string, cursor *string, handler Paymen
}

// StreamTransactions streams incoming transactions
func (c *Client) StreamTransactions(accountID string, cursor *string, handler TransactionHandler) (err error) {
func (c *Client) StreamTransactions(accountID string, cursor *Cursor, handler TransactionHandler) (err error) {
url := fmt.Sprintf("%s/accounts/%s/transactions", c.URL, accountID)
return c.stream(url, cursor, func(data []byte) error {
var transaction Transaction
Expand Down
31 changes: 31 additions & 0 deletions clients/horizon/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,20 @@ var DefaultPublicNetClient = &Client{
HTTP: http.DefaultClient,
}

// Cursor represents `cursor` param in queries
type Cursor string

// Limit represents `limit` param in queries
type Limit uint

// Order represents `order` param in queries
type Order string

const (
OrderAsc Order = "asc"
OrderDesc Order = "desc"
)

var (
// ErrTransactionNotFailed is the error returned from a call to ResultCodes()
// against a `Problem` value that is not of type "transaction_failed".
Expand All @@ -51,6 +65,17 @@ type Client struct {
HTTP HTTP
}

type ClientInterface interface {
LoadAccount(accountID string) (Account, error)
LoadAccountOffers(accountID string, params ...interface{}) (offers OffersPage, err error)
LoadMemo(p *Payment) error
LoadOrderBook(selling Asset, buying Asset) (orderBook OrderBookSummary, err error)
StreamLedgers(cursor *Cursor, handler LedgerHandler) error
StreamPayments(accountID string, cursor *Cursor, handler PaymentHandler) error
StreamTransactions(accountID string, cursor *Cursor, handler TransactionHandler) error
SubmitTransaction(txeBase64 string) (TransactionSuccess, error)
}

// Error struct contains the problem returned by Horizon
type Error struct {
Response *http.Response
Expand All @@ -64,6 +89,9 @@ type HTTP interface {
PostForm(url string, data url.Values) (resp *http.Response, err error)
}

// LedgerHandler is a function that is called when a new ledger is received
type LedgerHandler func(Ledger)

// PaymentHandler is a function that is called when a new payment is received
type PaymentHandler func(Payment)

Expand All @@ -72,3 +100,6 @@ type TransactionHandler func(Transaction)

// ensure that the horizon client can be used as a SequenceProvider
var _ build.SequenceProvider = &Client{}

// ensure that the horizon client implements ClientInterface
var _ ClientInterface = &Client{}
Loading