Files
gocryptotrader/cmd/websocket_client/main.go
Gareth Kirwan b4e45e9a1b Websocket: Restructure files and types (#1859)
* Websocket: Rename stream package

* Websocket: Rename Websocket to Manager

* Websocket: Replace explicit errs with common.NilGuard

* Websocket: Move websocket_types.go to types.go

* Websocket: Minor field comment and alignment in types

* Webosocket: Rename WebsocketConnection to Connection

* Alphapoint: Make gorilla ws import explicit

Just to avoid confusion with our own packages.

* Websocket: Move stream_match to match

* Websocket: Move websocket_connection to connection

* Websocket: Move websocket.go to manager.go

* Websocket: Break out all subscription methods into subscriptions.go

* Websocket: Move connection type into its file

* Websocket: Remove PositionUpdated

Type is not used anywhere

* Kraken: Use local constant for pong

Was the only use of websocket.Pong and doesn't really feel right to
represent kraken's api resp in one of our packages

* Websocket: Move connection sub-types to connection package

* Websocket: Move manager types into manager

* Websocket: Move ConnectionWrapper into manager

* Websocket: Move websocket_test to manager_test

* Websocket: Privatise connectionWrapper

* Websocket: Remaining types into types.go

These really belong somewhere else mostly, but this will do for now

* Websocket: Tidy up connection method vars

* Gofumpt: Moving package imports around

* Websocket: Rename errDuplicateConnectionSetup

* Websocket: Fix duplicate import of gws

* Websocket: Fix gofumpt -extra

* Websocket: Standardise import of gws across other pkgs

* Kraken: Remove unused sub conf consts

These were replaced by the generic Levels and Depth fields on all subs

* Websocket: Privitise ConnectioWrapper fields

* Websocket: inline single use var WebsocketNotAuthenticatedUsingRest

* Websocket: Move documentation to template

* Bithumb: Assertify TestWsHandleData
2025-04-10 16:25:02 +10:00

205 lines
4.6 KiB
Go

package main
import (
"errors"
"fmt"
"log"
"net"
"net/http"
"strconv"
gws "github.com/gorilla/websocket"
"github.com/thrasher-corp/gocryptotrader/common"
"github.com/thrasher-corp/gocryptotrader/common/crypto"
"github.com/thrasher-corp/gocryptotrader/config"
"github.com/thrasher-corp/gocryptotrader/encoding/json"
"github.com/thrasher-corp/gocryptotrader/exchanges/asset"
)
// Vars for the websocket client
var (
WSConn *gws.Conn
)
// WebsocketEvent is the struct used for websocket events
type WebsocketEvent struct {
Exchange string `json:"exchange,omitempty"`
AssetType string `json:"assetType,omitempty"`
Event string
Data any
}
// 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 any `json:"data"`
Error string `json:"error"`
}
// WebsocketOrderbookTickerRequest is a struct used for ticker and orderbook
// requests
type WebsocketOrderbookTickerRequest struct {
Exchange string `json:"exchangeName"`
Currency string `json:"currency"`
AssetType asset.Item `json:"assetType"`
}
// SendWebsocketEvent sends a websocket event message
func SendWebsocketEvent(event string, reqData any, result *WebsocketEventResponse) error {
req := WebsocketEvent{
Event: event,
}
if reqData != nil {
req.Data = reqData
}
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.File, true)
if err != nil {
log.Fatalf("Failed to load config file: %s", err)
}
listenAddr := cfg.RemoteControl.WebsocketRPC.ListenAddress
wsHost := fmt.Sprintf("ws://%s/ws", net.JoinHostPort(common.ExtractHost(listenAddr),
strconv.Itoa(common.ExtractPort(listenAddr))))
log.Printf("Connecting to websocket host: %s", wsHost)
var dialer gws.Dialer
var resp *http.Response
WSConn, resp, err = dialer.Dial(wsHost, http.Header{})
if err != nil {
log.Println("Unable to connect to websocket server")
return
}
resp.Body.Close()
log.Println("Connected to websocket!")
hash, err := crypto.GetSHA256([]byte(cfg.RemoteControl.Password))
if err != nil {
log.Println("Unable to generate SHA256 hash from remote control password:", err)
return
}
log.Println("Authenticating..")
var wsResp WebsocketEventResponse
reqData := WebsocketAuth{
Username: cfg.RemoteControl.Username,
Password: crypto.HexEncodeToString(hash),
}
err = SendWebsocketEvent("auth", reqData, &wsResp)
if err != nil {
log.Fatal(err)
}
log.Println("Authenticated successfully")
log.Println("Getting config..")
err = SendWebsocketEvent("GetConfig", nil, &wsResp)
if err != nil {
log.Fatal(err)
}
log.Printf("Fetched config.")
dataJSON, err := json.Marshal(&wsResp.Data)
if err != nil {
log.Fatal(err)
}
var resultCfg config.Config
err = json.Unmarshal(dataJSON, &resultCfg)
if err != nil {
log.Fatal(err)
}
log.Println("Saving config..")
origBotName := resultCfg.Name
resultCfg.Name = "TEST"
err = SendWebsocketEvent("SaveConfig", resultCfg, &wsResp)
if err != nil {
log.Fatal(err)
}
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..")
err = SendWebsocketEvent("GetAccountInfo", nil, &wsResp)
if err != nil {
log.Fatal(err)
}
log.Println("Got account info!")
log.Println("Getting tickers..")
err = SendWebsocketEvent("GetTickers", nil, &wsResp)
if err != nil {
log.Fatal(err)
}
log.Println("Got tickers!")
log.Println("Getting specific ticker..")
dataReq := WebsocketOrderbookTickerRequest{
Exchange: "Bitfinex",
Currency: "BTCUSD",
AssetType: asset.Spot,
}
err = SendWebsocketEvent("GetTicker", dataReq, &wsResp)
if err != nil {
log.Fatal(err)
}
log.Println("Got ticker!")
log.Println("Getting orderbooks..")
err = SendWebsocketEvent("GetOrderbooks", nil, &wsResp)
if err != nil {
log.Fatal(err)
}
log.Println("Got orderbooks!")
log.Println("Getting specific orderbook..")
err = SendWebsocketEvent("GetOrderbook", dataReq, &wsResp)
if err != nil {
log.Fatal(err)
}
log.Println("Got orderbook!")
for {
var wsEvent WebsocketEvent
err = WSConn.ReadJSON(&wsEvent)
if err != nil {
break
}
log.Printf("Recv'd: %s", wsEvent.Event)
}
WSConn.Close()
}