@@ -2,7 +2,9 @@ package binance
22
33import (
44 "encoding/json"
5+ "errors"
56 "fmt"
7+ "net/http"
68 "strings"
79 "time"
810
1719 BaseCombinedTestnetURL = "wss://stream.testnet.binance.vision/stream?streams="
1820 BaseWsApiMainURL = "wss://ws-api.binance.com:443/ws-api/v3"
1921 BaseWsApiTestnetURL = "wss://ws-api.testnet.binance.vision/ws-api/v3"
22+ BaseWsAnnouncementURL = "wss://api.binance.com/sapi/wss"
2023
2124 // WebsocketTimeout is an interval for sending ping/pong messages if WebsocketKeepalive is enabled
2225 WebsocketTimeout = time .Second * 600
@@ -135,20 +138,20 @@ func WsCombinedPartialDepthServe(symbolLevels map[string]string, handler WsParti
135138 event .Symbol = strings .ToUpper (symbol )
136139 data := j .Get ("data" ).MustMap ()
137140 event .LastUpdateID , _ = data ["lastUpdateId" ].(json.Number ).Int64 ()
138- bidsLen := len (data ["bids" ].([]interface {} ))
141+ bidsLen := len (data ["bids" ].([]any ))
139142 event .Bids = make ([]Bid , bidsLen )
140143 for i := 0 ; i < bidsLen ; i ++ {
141- item := data ["bids" ].([]interface {} )[i ].([]interface {} )
144+ item := data ["bids" ].([]any )[i ].([]any )
142145 event .Bids [i ] = Bid {
143146 Price : item [0 ].(string ),
144147 Quantity : item [1 ].(string ),
145148 }
146149 }
147- asksLen := len (data ["asks" ].([]interface {} ))
150+ asksLen := len (data ["asks" ].([]any ))
148151 event .Asks = make ([]Ask , asksLen )
149152 for i := 0 ; i < asksLen ; i ++ {
150153
151- item := data ["asks" ].([]interface {} )[i ].([]interface {} )
154+ item := data ["asks" ].([]any )[i ].([]any )
152155 event .Asks [i ] = Ask {
153156 Price : item [0 ].(string ),
154157 Quantity : item [1 ].(string ),
@@ -258,20 +261,20 @@ func wsCombinedDepthServe(endpoint string, handler WsDepthHandler, errHandler Er
258261 event .Time , _ = data ["E" ].(json.Number ).Int64 ()
259262 event .LastUpdateID , _ = data ["u" ].(json.Number ).Int64 ()
260263 event .FirstUpdateID , _ = data ["U" ].(json.Number ).Int64 ()
261- bidsLen := len (data ["b" ].([]interface {} ))
264+ bidsLen := len (data ["b" ].([]any ))
262265 event .Bids = make ([]Bid , bidsLen )
263266 for i := 0 ; i < bidsLen ; i ++ {
264- item := data ["b" ].([]interface {} )[i ].([]interface {} )
267+ item := data ["b" ].([]any )[i ].([]any )
265268 event .Bids [i ] = Bid {
266269 Price : item [0 ].(string ),
267270 Quantity : item [1 ].(string ),
268271 }
269272 }
270- asksLen := len (data ["a" ].([]interface {} ))
273+ asksLen := len (data ["a" ].([]any ))
271274 event .Asks = make ([]Ask , asksLen )
272275 for i := 0 ; i < asksLen ; i ++ {
273276
274- item := data ["a" ].([]interface {} )[i ].([]interface {} )
277+ item := data ["a" ].([]any )[i ].([]any )
275278 event .Asks [i ] = Ask {
276279 Price : item [0 ].(string ),
277280 Quantity : item [1 ].(string ),
@@ -872,6 +875,80 @@ func WsApiInitReadWriteConn() (*websocket.Conn, error) {
872875 return conn , err
873876}
874877
878+ type WsAnnouncementEvent struct {
879+ CatalogID int64 `json:"catalogId"`
880+ CatalogName string `json:"catalogName"`
881+ PublishDate int64 `json:"publishDate"`
882+ Title string `json:"title"`
883+ Body string `json:"body"`
884+ Disclaimer string `json:"disclaimer"`
885+ }
886+
887+ type WsAnnouncementParam struct {
888+ Random string
889+ Topic string
890+ RecvWindow int64
891+ Timestamp int64
892+ Signature string
893+ ApiKey string
894+ }
895+ type WsAnnouncementHandler func (event * WsAnnouncementEvent )
896+
897+ // WsAnnouncementServe establishes a WebSocket connection to listen for Binance announcements.
898+ // See API documentation: https://developers.binance.com/docs/cms/announcement
899+ //
900+ // Parameters:
901+ //
902+ // params - Should be created using client.CreateAnnouncementParam
903+ // handler - Callback function to handle incoming announcement messages
904+ // errHandler - Error callback function for connection errors
905+ //
906+ // Returns:
907+ //
908+ // doneC - Channel that closes when the connection terminates
909+ // stopC - Channel that can be closed to stop the connection
910+ // err - Any initial connection error
911+ func WsAnnouncementServe (params WsAnnouncementParam , handler WsAnnouncementHandler , errHandler ErrHandler ) (doneC , stopC chan struct {}, err error ) {
912+ if UseTestnet {
913+ return nil , nil , errors .New ("not support testnet" )
914+ }
915+ endpoint := fmt .Sprintf ("%s?random=%s&topic=%s&recvWindow=%d×tamp=%d&signature=%s" ,
916+ BaseWsAnnouncementURL , params .Random , params .Topic , params .RecvWindow , params .Timestamp , params .Signature ,
917+ )
918+
919+ cfg := newWsConfig (endpoint )
920+ cfg .Header = & http.Header {}
921+ cfg .Header .Add ("X-MBX-APIKEY" , params .ApiKey )
922+ wsHandler := func (message []byte ) {
923+ event := struct {
924+ Type string `json:"type"`
925+ Topic string `json:"topic"`
926+ Data string `json:"data"`
927+ }{}
928+
929+ err := json .Unmarshal (message , & event )
930+ if err != nil {
931+ errHandler (err )
932+ return
933+ }
934+
935+ if event .Type != "DATA" {
936+ errHandler (errors .New ("type is not DATA: " + event .Type ))
937+ return
938+ }
939+
940+ if event .Topic != "com_announcement_en" {
941+ errHandler (errors .New ("topic is not com_announcement_en: " + event .Topic ))
942+ return
943+ }
944+
945+ e := new (WsAnnouncementEvent )
946+ json .Unmarshal ([]byte (event .Data ), & e )
947+ handler (e )
948+ }
949+ return wsServe (cfg , wsHandler , errHandler )
950+ }
951+
875952// getWsApiEndpoint return the base endpoint of the API WS according the UseTestnet flag
876953func getWsApiEndpoint () string {
877954 if UseTestnet {
0 commit comments