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  }