github.com/bitfinexcom/bitfinex-api-go@v0.0.0-20210608095005-9e0b26f200fb/v2/websocket/factories.go (about) 1 package websocket 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "strings" 7 "sync" 8 9 "github.com/bitfinexcom/bitfinex-api-go/pkg/models/book" 10 "github.com/bitfinexcom/bitfinex-api-go/pkg/models/candle" 11 "github.com/bitfinexcom/bitfinex-api-go/pkg/models/derivatives" 12 "github.com/bitfinexcom/bitfinex-api-go/pkg/models/ticker" 13 "github.com/bitfinexcom/bitfinex-api-go/pkg/models/trade" 14 ) 15 16 type messageFactory interface { 17 Build(sub *subscription, objType string, raw []interface{}, raw_bytes []byte) (interface{}, error) 18 BuildSnapshot(sub *subscription, raw [][]interface{}, raw_bytes []byte) (interface{}, error) 19 } 20 21 type TickerFactory struct { 22 *subscriptions 23 } 24 25 func newTickerFactory(subs *subscriptions) *TickerFactory { 26 return &TickerFactory{ 27 subscriptions: subs, 28 } 29 } 30 31 func (f *TickerFactory) Build(sub *subscription, objType string, raw []interface{}, raw_bytes []byte) (interface{}, error) { 32 return ticker.FromRaw(sub.Request.Symbol, raw) 33 } 34 35 func (f *TickerFactory) BuildSnapshot(sub *subscription, raw [][]interface{}, raw_bytes []byte) (interface{}, error) { 36 return ticker.SnapshotFromRaw(sub.Request.Symbol, raw) 37 } 38 39 type TradeFactory struct { 40 *subscriptions 41 } 42 43 func newTradeFactory(subs *subscriptions) *TradeFactory { 44 return &TradeFactory{ 45 subscriptions: subs, 46 } 47 } 48 49 func (f *TradeFactory) Build(sub *subscription, objType string, raw []interface{}, raw_bytes []byte) (interface{}, error) { 50 if "tu" == objType { 51 return nil, nil // do not process TradeUpdate messages on public feed, only need to process TradeExecution (first copy seen) 52 } 53 return trade.FromRaw(sub.Request.Symbol, raw) 54 } 55 56 func (f *TradeFactory) BuildSnapshot(sub *subscription, raw [][]interface{}, raw_bytes []byte) (interface{}, error) { 57 return trade.SnapshotFromRaw(sub.Request.Symbol, raw) 58 } 59 60 type BookFactory struct { 61 *subscriptions 62 orderbooks map[string]*Orderbook 63 manageBooks bool 64 lock sync.Mutex 65 } 66 67 func newBookFactory(subs *subscriptions, obs map[string]*Orderbook, manageBooks bool) *BookFactory { 68 return &BookFactory{ 69 subscriptions: subs, 70 orderbooks: obs, 71 manageBooks: manageBooks, 72 } 73 } 74 75 func ConvertBytesToJsonNumberArray(b []byte) ([]interface{}, error) { 76 var rawJSONNumbers []interface{} 77 d := json.NewDecoder(strings.NewReader(string(b))) 78 d.UseNumber() 79 80 err := d.Decode(&rawJSONNumbers) 81 if err != nil { 82 return nil, err 83 } 84 85 return rawJSONNumbers, nil 86 } 87 88 func (f *BookFactory) Build(sub *subscription, objType string, raw []interface{}, b []byte) (interface{}, error) { 89 rawJSONNumbers, err := ConvertBytesToJsonNumberArray(b) 90 if err != nil { 91 return nil, err 92 } 93 94 update, err := book.FromRaw(sub.Request.Symbol, sub.Request.Precision, raw, rawJSONNumbers[1]) 95 if f.manageBooks { 96 f.lock.Lock() 97 defer f.lock.Unlock() 98 if orderbook, ok := f.orderbooks[sub.Request.Symbol]; ok { 99 orderbook.UpdateWith(update) 100 } 101 } 102 103 return update, err 104 } 105 106 func (f *BookFactory) BuildSnapshot(sub *subscription, raw [][]interface{}, b []byte) (interface{}, error) { 107 rawJSONNumbers, err := ConvertBytesToJsonNumberArray(b) 108 if err != nil { 109 return nil, err 110 } 111 112 update, err := book.SnapshotFromRaw(sub.Request.Symbol, sub.Request.Precision, raw, rawJSONNumbers[1]) 113 if err != nil { 114 return nil, err 115 } 116 117 if f.manageBooks { 118 f.lock.Lock() 119 defer f.lock.Unlock() 120 // create new orderbook 121 f.orderbooks[sub.Request.Symbol] = &Orderbook{ 122 symbol: sub.Request.Symbol, 123 bids: make([]*book.Book, 0), 124 asks: make([]*book.Book, 0), 125 } 126 f.orderbooks[sub.Request.Symbol].SetWithSnapshot(update) 127 } 128 129 return update, nil 130 } 131 132 type CandlesFactory struct { 133 *subscriptions 134 } 135 136 func newCandlesFactory(subs *subscriptions) *CandlesFactory { 137 return &CandlesFactory{ 138 subscriptions: subs, 139 } 140 } 141 142 func (f *CandlesFactory) Build(sub *subscription, objType string, raw []interface{}, raw_bytes []byte) (interface{}, error) { 143 sym, res, err := extractSymbolResolutionFromKey(sub.Request.Key) 144 if err != nil { 145 return nil, err 146 } 147 candle, err := candle.FromRaw(sym, res, raw) 148 return candle, err 149 } 150 151 func (f *CandlesFactory) BuildSnapshot(sub *subscription, raw [][]interface{}, raw_bytes []byte) (interface{}, error) { 152 sym, res, err := extractSymbolResolutionFromKey(sub.Request.Key) 153 if err != nil { 154 return nil, err 155 } 156 snap, err := candle.SnapshotFromRaw(sym, res, raw) 157 return snap, err 158 } 159 160 type StatsFactory struct { 161 *subscriptions 162 } 163 164 func newStatsFactory(subs *subscriptions) *StatsFactory { 165 return &StatsFactory{ 166 subscriptions: subs, 167 } 168 } 169 170 func (f *StatsFactory) Build(sub *subscription, objType string, raw []interface{}, raw_bytes []byte) (interface{}, error) { 171 splits := strings.Split(sub.Request.Key, ":") 172 if len(splits) != 3 { 173 return nil, fmt.Errorf("unable to parse key to symbol %s", sub.Request.Key) 174 } 175 symbol := splits[1] + ":" + splits[2] 176 d, err := derivatives.FromWsRaw(symbol, raw) 177 return d, err 178 } 179 180 func (f *StatsFactory) BuildSnapshot(sub *subscription, raw [][]interface{}, raw_bytes []byte) (interface{}, error) { 181 // no snapshots 182 return nil, nil 183 }