Skip to content

Commit d1c1738

Browse files
committed
upgrade spot ws
1 parent 8551c72 commit d1c1738

1 file changed

Lines changed: 103 additions & 1 deletion

File tree

src/websocket.js

Lines changed: 103 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import JSONbig from 'json-bigint'
33

44
import httpMethods from 'http-client'
55
import _openWebSocket from 'open-websocket'
6+
import { createHmacSignature, createAsymmetricSignature } from 'signature'
67

78
const endpoints = {
89
base: 'wss://stream.binance.com:9443/ws',
@@ -880,6 +881,107 @@ const getStreamMethods = (opts, variator = '') => {
880881

881882
export const keepStreamAlive = (method, listenKey) => method({ listenKey })
882883

884+
const userWebSocketApi = opts => (cb, transform) => {
885+
const isTestnet = opts.testnet || (opts.httpBase && opts.httpBase.includes('testnet'))
886+
const wsApiUrl = isTestnet
887+
? opts.wsApiTestnet || 'wss://ws-api.testnet.binance.vision/ws-api/v3'
888+
: opts.wsApi || 'wss://ws-api.binance.com:443/ws-api/v3'
889+
890+
let requestId = 1
891+
const errorHandler = userErrorHandler(cb, transform)
892+
const w = openWebSocket(wsApiUrl)
893+
894+
const sendSubscribe = () => {
895+
const timestamp = opts.getTime ? opts.getTime() : Date.now()
896+
const paramsStr = `apiKey=${opts.apiKey}&timestamp=${timestamp}`
897+
898+
const doSend = signature => {
899+
w.send(
900+
JSONbig.stringify({
901+
id: requestId++,
902+
method: 'userDataStream.subscribe.signature',
903+
params: {
904+
apiKey: opts.apiKey,
905+
timestamp,
906+
signature,
907+
},
908+
}),
909+
)
910+
}
911+
912+
if (opts.apiSecret) {
913+
createHmacSignature(paramsStr, opts.apiSecret).then(doSend)
914+
} else if (opts.privateKey) {
915+
doSend(createAsymmetricSignature(paramsStr, opts.privateKey))
916+
}
917+
}
918+
919+
return new Promise((resolve, reject) => {
920+
let resolved = false
921+
922+
w.onopen = () => {
923+
sendSubscribe()
924+
if (opts.emitSocketOpens) {
925+
userOpenHandler(cb, transform)()
926+
}
927+
}
928+
929+
w.onmessage = msg => {
930+
const data = JSONbig.parse(msg.data)
931+
932+
// Control response (subscription/unsubscription)
933+
if ('id' in data) {
934+
if (data.error) {
935+
const err = new Error(data.error.msg || 'WebSocket API error')
936+
err.code = data.error.code
937+
if (!resolved) {
938+
resolved = true
939+
reject(err)
940+
} else if (opts.emitStreamErrors) {
941+
errorHandler(err)
942+
}
943+
} else if (!resolved) {
944+
resolved = true
945+
resolve(options => {
946+
try {
947+
w.send(
948+
JSONbig.stringify({
949+
id: requestId++,
950+
method: 'userDataStream.unsubscribe',
951+
}),
952+
)
953+
} catch (e) {
954+
// Ignore send errors during close
955+
}
956+
w.close(1000, 'Close handle was called', {
957+
keepClosed: true,
958+
...options,
959+
})
960+
})
961+
}
962+
return
963+
}
964+
965+
// User data event - unwrap if in wrapped format
966+
let eventData = data
967+
if (data.event && typeof data.event === 'object') {
968+
eventData = data.event
969+
}
970+
971+
if (eventData.e) {
972+
userEventHandler(cb, transform)({ data: JSONbig.stringify(eventData) })
973+
}
974+
}
975+
976+
w.onerror = event => {
977+
const error = event.error || event.message || new Error('WebSocket error')
978+
if (opts.emitSocketErrors) {
979+
errorHandler(typeof error === 'string' ? new Error(error) : error)
980+
}
981+
}
982+
})
983+
}
984+
883985
const user = (opts, variator) => (cb, transform) => {
884986
const [getDataStream, keepDataStream, closeDataStream] = getStreamMethods(opts, variator)
885987

@@ -1029,7 +1131,7 @@ export default opts => {
10291131
miniTicker,
10301132
allMiniTickers,
10311133
customSubStream,
1032-
user: user(opts),
1134+
user: userWebSocketApi(opts),
10331135

10341136
marginUser: user(opts, 'margin'),
10351137

0 commit comments

Comments
 (0)