/
actions_trade.go
128 lines (107 loc) · 3.39 KB
/
actions_trade.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package horizon
import (
"errors"
"fmt"
"github.com/stellar/go/xdr"
"github.com/stellar/horizon/db2"
"github.com/stellar/horizon/db2/history"
"github.com/stellar/horizon/render/hal"
"github.com/stellar/horizon/resource"
)
// TradeIndexAction renders a page of effect resources, filtered to include
// only trades, identified by a normal page query and optionally filtered by an account
// or order book
type TradeIndexAction struct {
Action
AccountFilter string
Selling xdr.Asset
Buying xdr.Asset
PagingParams db2.PageQuery
Records []history.Effect
// LedgerRecords is a cache of loaded ledger data used to populate the time
// when a trade occurred.
LedgerRecords map[int32]history.Ledger
Page hal.Page
}
// JSON is a method for actions.JSON
func (action *TradeIndexAction) JSON() {
action.Do(
action.EnsureHistoryFreshness,
action.loadParams,
action.loadRecords,
action.loadLedgers,
action.loadPage,
func() {
hal.Render(action.W, action.Page)
},
)
}
// LoadQuery sets action.Query from the request params
func (action *TradeIndexAction) loadParams() {
action.AccountFilter = action.GetString("account_id")
action.PagingParams = action.GetPageQuery()
// scott: It is unfortunate that we have this string guard below. Instead, we
// should probably add an alternative to `GetAsset` that returns a zero-value
// xdr.Asset when not provided by the request. Perhaps `MaybeGetAsset`?.
if action.GetString("selling_asset_type") != "" {
action.Selling = action.GetAsset("selling_")
action.Buying = action.GetAsset("buying_")
}
}
// loadRecords populates action.Records
func (action *TradeIndexAction) loadRecords() {
trades := action.HistoryQ().Effects().OfType(history.EffectTrade)
if action.AccountFilter != "" {
trades = trades.ForAccount(action.AccountFilter)
}
if (action.Selling != xdr.Asset{} || action.Buying != xdr.Asset{}) {
trades = trades.ForOrderBook(action.Selling, action.Buying)
}
action.Err = trades.Page(action.PagingParams).Select(&action.Records)
}
// loadLedgers collects the unique ledgers referenced in the loaded trades and loads the details for each.
func (action *TradeIndexAction) loadLedgers() {
if len(action.Records) == 0 {
return
}
ledgerSequences := make([]interface{}, len(action.Records))
// populate the unique sequences
for i, trade := range action.Records {
ledgerSequences[i] = trade.LedgerSequence()
}
var ledgers []history.Ledger
action.Err = action.HistoryQ().LedgersBySequence(
&ledgers,
ledgerSequences...,
)
if action.Err != nil {
return
}
action.LedgerRecords = map[int32]history.Ledger{}
for _, l := range ledgers {
action.LedgerRecords[l.Sequence] = l
}
}
// loadPage populates action.Page
func (action *TradeIndexAction) loadPage() {
for _, record := range action.Records {
var res resource.Trade
ledger, found := action.LedgerRecords[record.LedgerSequence()]
if !found {
msg := fmt.Sprintf("could not find ledger data for sequence %d", record.LedgerSequence())
action.Err = errors.New(msg)
return
}
action.Err = res.Populate(action.Ctx, record, ledger)
if action.Err != nil {
return
}
action.Page.Add(res)
}
action.Page.BaseURL = action.BaseURL()
action.Page.BasePath = action.Path()
action.Page.Limit = action.PagingParams.Limit
action.Page.Cursor = action.PagingParams.Cursor
action.Page.Order = action.PagingParams.Order
action.Page.PopulateLinks()
}