From 6e9bda83a1c8aa168728d1bf75697c4aee244643 Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Mon, 11 Sep 2017 09:07:41 +1000 Subject: [PATCH] Link up websocket handler to routes after refactor and various improvements --- exchanges/stats/stats.go | 10 ++ exchanges/stats/stats_test.go | 14 ++ helpers.go | 3 +- main.go | 12 +- portfolio/portfolio.go | 8 +- portfolio/portfolio_test.go | 4 +- restful_router.go | 22 ++-- tools/websocket_client/main.go | 232 +++++++++++++-------------------- websocket.go | 12 +- 9 files changed, 148 insertions(+), 169 deletions(-) diff --git a/exchanges/stats/stats.go b/exchanges/stats/stats.go index 0b003e2f..200a35fa 100644 --- a/exchanges/stats/stats.go +++ b/exchanges/stats/stats.go @@ -54,6 +54,16 @@ func Add(exchange string, p pair.CurrencyPair, assetType string, price, volume f return } + if p.FirstCurrency == "XBT" { + newPair := pair.NewCurrencyPair("BTC", p.SecondCurrency.String()) + Append(exchange, newPair, assetType, price, volume) + } + + if p.SecondCurrency == "USDT" { + newPair := pair.NewCurrencyPair(p.FirstCurrency.String(), "USD") + Append(exchange, newPair, assetType, price, volume) + } + Append(exchange, p, assetType, price, volume) } diff --git a/exchanges/stats/stats_test.go b/exchanges/stats/stats_test.go index 3cefd2b9..db3c17fa 100644 --- a/exchanges/stats/stats_test.go +++ b/exchanges/stats/stats_test.go @@ -114,6 +114,20 @@ func TestAdd(t *testing.T) { if len(Items) != 1 { t.Error("Test Failed - stats Add did not add exchange info.") } + + p.FirstCurrency = "XBT" + Add("ANX", p, "SPOT", 1201, 43) + + if Items[1].Pair.Pair() != "XBTUSD" { + t.Fatal("Test failed. stats Add did not add exchange info.") + } + + p = pair.NewCurrencyPair("ETH", "USDT") + Add("ANX", p, "SPOT", 300, 1000) + + if Items[2].Pair.Pair() != "ETHUSD" { + t.Fatal("Test failed. stats Add did not add exchange info.") + } } func TestAppend(t *testing.T) { diff --git a/helpers.go b/helpers.go index 554f66ff..86132f6a 100644 --- a/helpers.go +++ b/helpers.go @@ -4,11 +4,10 @@ import ( "errors" "fmt" - "github.com/thrasher-/gocryptotrader/exchanges/stats" - "github.com/thrasher-/gocryptotrader/currency/pair" exchange "github.com/thrasher-/gocryptotrader/exchanges" "github.com/thrasher-/gocryptotrader/exchanges/orderbook" + "github.com/thrasher-/gocryptotrader/exchanges/stats" "github.com/thrasher-/gocryptotrader/exchanges/ticker" ) diff --git a/main.go b/main.go index a39251bd..4f8c8aba 100644 --- a/main.go +++ b/main.go @@ -299,9 +299,15 @@ func SeedExchangeAccountInfo(data []exchange.AccountInfo) { currencyName) port.RemoveExchangeAddress(exchangeName, currencyName) } else { - log.Printf("Portfolio: Updating %s %s entry with balance %f.\n", - exchangeName, currencyName, total) - port.UpdateExchangeAddressBalance(exchangeName, currencyName, total) + balance, ok := port.GetAddressBalance(exchangeName, currencyName, portfolio.PortfolioAddressExchange) + if !ok { + continue + } + if balance != total { + log.Printf("Portfolio: Updating %s %s entry with balance %f.\n", + exchangeName, currencyName, total) + port.UpdateExchangeAddressBalance(exchangeName, currencyName, total) + } } } } diff --git a/portfolio/portfolio.go b/portfolio/portfolio.go index 81f6eae4..d3e52fb5 100644 --- a/portfolio/portfolio.go +++ b/portfolio/portfolio.go @@ -108,10 +108,12 @@ func GetCryptoIDAddress(address string, coinType string) (float64, error) { } // GetAddressBalance acceses the portfolio base and returns the balance by passed -// in address -func (p *Base) GetAddressBalance(address string) (float64, bool) { +// in address, coin type and description +func (p *Base) GetAddressBalance(address, coinType, description string) (float64, bool) { for x := range p.Addresses { - if p.Addresses[x].Address == address { + if p.Addresses[x].Address == address && + p.Addresses[x].Description == description && + p.Addresses[x].CoinType == coinType { return p.Addresses[x].Balance, true } } diff --git a/portfolio/portfolio_test.go b/portfolio/portfolio_test.go index 86e689a0..7a3a9c94 100644 --- a/portfolio/portfolio_test.go +++ b/portfolio/portfolio_test.go @@ -49,12 +49,12 @@ func TestGetAddressBalance(t *testing.T) { portfolio := Base{} portfolio.AddAddress(ltcAddress, ltc, description, balance) - addBalance, _ := portfolio.GetAddressBalance("LdP8Qox1VAhCzLJNqrr74YovaWYyNBUWvL") + addBalance, _ := portfolio.GetAddressBalance("LdP8Qox1VAhCzLJNqrr74YovaWYyNBUWvL", ltc, description) if addBalance != balance { t.Error("Test Failed - Portfolio GetAddressBalance() Error: Incorrect value") } - addBalance, found := portfolio.GetAddressBalance("WigWham") + addBalance, found := portfolio.GetAddressBalance("WigWham", ltc, description) if addBalance != 0 { t.Error("Test Failed - Portfolio GetAddressBalance() Error: Incorrect value") } diff --git a/restful_router.go b/restful_router.go index bd335797..f6666bac 100644 --- a/restful_router.go +++ b/restful_router.go @@ -46,6 +46,12 @@ func NewRouter(exchanges []exchange.IBotExchange) *mux.Router { router := mux.NewRouter().StrictSlash(true) routes = Routes{ + Route{ + "", + "GET", + "/", + getIndex, + }, Route{ "GetAllSettings", "GET", @@ -94,6 +100,12 @@ func NewRouter(exchanges []exchange.IBotExchange) *mux.Router { "/exchanges/{exchangeName}/orderbook/latest/{currency}", RESTGetOrderbook, }, + Route{ + "ws", + "GET", + "/ws", + WebsocketClientHandler, + }, } for _, route := range routes { @@ -114,13 +126,3 @@ func getIndex(w http.ResponseWriter, r *http.Request) { fmt.Fprint(w, "GoCryptoTrader RESTful interface. For the web GUI, please visit the web GUI readme.") w.WriteHeader(http.StatusOK) } - -// IndexRoute maps the index route to the getIndex function -var IndexRoute = Routes{ - Route{ - "", - "GET", - "/", - getIndex, - }, -} diff --git a/tools/websocket_client/main.go b/tools/websocket_client/main.go index 66e23569..4cb31fe1 100644 --- a/tools/websocket_client/main.go +++ b/tools/websocket_client/main.go @@ -1,116 +1,114 @@ package main import ( + "errors" + "fmt" "log" "net/http" - "time" "github.com/gorilla/websocket" "github.com/thrasher-/gocryptotrader/common" "github.com/thrasher-/gocryptotrader/config" ) +// Vars for the websocket client var ( WSConn *websocket.Conn ) +// WebsocketEvent is the struct used for websocket events type WebsocketEvent struct { - Event string `json:"event"` - Data interface{} `json:"data"` - Exchange string `json:"exchange,omitempty"` + Exchange string `json:"exchange,omitempty"` + AssetType string `json:"assetType,omitempty"` + Event string + Data interface{} } +// WebsocketAuth is the struct used for a websocket auth request type WebsocketAuth struct { Username string `json:"username"` Password string `json:"password"` } +// WebsocketEventResponse is the struct used for websocket event responses type WebsocketEventResponse struct { Event string `json:"event"` Data interface{} `json:"data"` Error string `json:"error"` } -type WebsocketTickerRequest struct { - Exchange string `json:"exchangeName"` - Currency string `json:"currency"` +// WebsocketOrderbookTickerRequest is a struct used for ticker and orderbook +// requests +type WebsocketOrderbookTickerRequest struct { + Exchange string `json:"exchangeName"` + Currency string `json:"currency"` + AssetType string `json:"assetType"` } -func SendWebsocketAuth(username, password string) error { - pwHash := common.HexEncodeToString(common.GetSHA256([]byte(password))) +// SendWebsocketEvent sends a websocket event message +func SendWebsocketEvent(event string, reqData interface{}, result *WebsocketEventResponse) error { req := WebsocketEvent{ - Event: "auth", - Data: WebsocketAuth{ - Username: username, - Password: pwHash, - }, + Event: event, } - return SendWebsocketMsg(req) -} - -func SendWebsocketMsg(data interface{}) error { - return WSConn.WriteJSON(data) -} - -func GetWebsocketTicker(currency string) error { - wsevt := WebsocketEvent{ - Event: "ticker", - Data: currency, + if reqData != nil { + req.Data = reqData } - return SendWebsocketMsg(wsevt) + err := WSConn.WriteJSON(req) + if err != nil { + return err + } + + err = WSConn.ReadJSON(&result) + if err != nil { + return err + } + + if result.Error != "" { + return errors.New(result.Error) + } + + return nil } func main() { + cfg := config.GetConfig() + err := cfg.LoadConfig(config.ConfigFile) + if err != nil { + log.Fatalf("Failed to load config file: %s", err) + } + + listenAddr := cfg.Webserver.ListenAddress + wsHost := fmt.Sprintf("ws://%s:%d/ws", common.ExtractHost(listenAddr), + common.ExtractPort(listenAddr)) + log.Printf("Connecting to websocket host: %s", wsHost) + var Dialer websocket.Dialer - var err error - - WSConn, _, err = Dialer.Dial("ws://localhost:9050/ws", http.Header{}) - + WSConn, _, err = Dialer.Dial(wsHost, http.Header{}) if err != nil { log.Println("Unable to connect to websocket server") return } - log.Println("Connected to websocket!") + log.Println("Authenticating..") - SendWebsocketAuth("blah", "blah") - var wsResp WebsocketEventResponse - err = WSConn.ReadJSON(&wsResp) + reqData := WebsocketAuth{ + Username: cfg.Webserver.AdminUsername, + Password: common.HexEncodeToString(common.GetSHA256([]byte(cfg.Webserver.AdminPassword))), + } + err = SendWebsocketEvent("auth", reqData, &wsResp) if err != nil { - log.Println(err) - return + log.Fatal(err) } - - if wsResp.Error != "" { - log.Fatal(wsResp.Error) - } - log.Println("Authenticated successfully") + log.Println("Getting config..") - - req := WebsocketEvent{ - Event: "GetConfig", - } - - err = WSConn.WriteJSON(req) + err = SendWebsocketEvent("GetConfig", nil, &wsResp) if err != nil { - log.Println(err) - return + log.Fatal(err) } - - err = WSConn.ReadJSON(&wsResp) - if err != nil { - log.Println(err) - return - } - - if wsResp.Error != "" { - log.Fatal(wsResp.Error) - } - log.Printf("Fetched config.") dataJSON, err := common.JSONEncode(&wsResp.Data) @@ -124,112 +122,70 @@ func main() { log.Fatal(err) } - resultCfg.Name = "TEST" - - req = WebsocketEvent{ - Event: "SaveConfig", - Data: resultCfg, - } - log.Println("Saving config..") - err = WSConn.WriteJSON(req) + origBotName := resultCfg.Name + resultCfg.Name = "TEST" + err = SendWebsocketEvent("SaveConfig", resultCfg, &wsResp) if err != nil { log.Fatal(err) } - - err = WSConn.ReadJSON(&wsResp) - if err != nil { - log.Println(err) - return - } - - if wsResp.Error != "" { - log.Fatal(wsResp.Error) - } - log.Println("Saved config!") + resultCfg.Name = origBotName + err = SendWebsocketEvent("SaveConfig", resultCfg, &wsResp) + if err != nil { + log.Fatal(err) + } + log.Println("Saved config (restored original bot name)!") + log.Println("Getting account info..") - - req = WebsocketEvent{ - Event: "GetAccountInfo", - } - - err = WSConn.WriteJSON(req) + err = SendWebsocketEvent("GetAccountInfo", nil, &wsResp) if err != nil { - log.Println(err) - return - } - - err = WSConn.ReadJSON(&wsResp) - if err != nil { - log.Println(err) - return - } - - if wsResp.Error != "" { - log.Fatal(wsResp.Error) + log.Fatal(err) } + log.Println("Got account info!") log.Println("Getting tickers..") - - req = WebsocketEvent{ - Event: "GetTickers", - } - - err = WSConn.WriteJSON(req) + err = SendWebsocketEvent("GetTickers", nil, &wsResp) if err != nil { - log.Println(err) - return - } - - err = WSConn.ReadJSON(&wsResp) - if err != nil { - log.Println(err) - return - } - - if wsResp.Error != "" { - log.Fatal(wsResp.Error) + log.Fatal(err) } + log.Println("Got tickers!") log.Println("Getting specific ticker..") - - var tickReq WebsocketTickerRequest - tickReq.Currency = "LTCUSD" - tickReq.Exchange = "Bitfinex" - - req = WebsocketEvent{ - Event: "GetTicker", - Data: tickReq, + dataReq := WebsocketOrderbookTickerRequest{ + Exchange: "Bitfinex", + Currency: "BTCUSD", + AssetType: "SPOT", } - err = WSConn.WriteJSON(req) + err = SendWebsocketEvent("GetTicker", dataReq, &wsResp) if err != nil { - log.Println(err) - return + log.Fatal(err) } + log.Println("Got ticker!") - err = WSConn.ReadJSON(&wsResp) + log.Println("Getting orderbooks..") + err = SendWebsocketEvent("GetOrderbooks", nil, &wsResp) if err != nil { - log.Println(err) - return + log.Fatal(err) } + log.Println("Got orderbooks!") - if wsResp.Error != "" { - log.Fatal(wsResp.Error) + log.Println("Getting specific orderbook..") + err = SendWebsocketEvent("GetOrderbook", dataReq, &wsResp) + if err != nil { + log.Fatal(err) } - - log.Println(wsResp) + log.Println("Got orderbook!") for { - msgType, resp, err := WSConn.ReadMessage() + var wsEvent WebsocketEventResponse + err = WSConn.ReadJSON(&wsEvent) if err != nil { - log.Fatal(err) + break } - log.Println(msgType) - log.Println(string(resp)) + log.Printf("Recv'd: %s", wsEvent.Event) } - time.Sleep(time.Second * 10) WSConn.Close() } diff --git a/websocket.go b/websocket.go index fb3bb8dc..ef11548e 100644 --- a/websocket.go +++ b/websocket.go @@ -17,16 +17,6 @@ const ( WebsocketResponseSuccess = "OK" ) -// WebsocketRoutes adds ws route to the HTTP server -var WebsocketRoutes = Routes{ - Route{ - "ws", - "GET", - "/ws", - WebsocketClientHandler, - }, -} - // WebsocketClient stores information related to the websocket client type WebsocketClient struct { ID int @@ -304,7 +294,7 @@ func WebsocketHandler() { log.Println(err) continue } - hashPW := common.HexEncodeToString(common.GetSHA256([]byte(bot.config.Webserver.AdminUsername))) + hashPW := common.HexEncodeToString(common.GetSHA256([]byte(bot.config.Webserver.AdminPassword))) if auth.Username == bot.config.Webserver.AdminUsername && auth.Password == hashPW { WebsocketClientHub[x].Authenticated = true wsResp := WebsocketEventResponse{