home-assistant-js-websocket
Advanced tools
Comparing version 5.3.0 to 5.4.0
@@ -9,8 +9,7 @@ import { createStore } from "./store.js"; | ||
let store = createStore(); | ||
const refresh = () => fetchCollection(conn).then(state => store.setState(state, true)); | ||
const refresh = () => fetchCollection(conn).then((state) => store.setState(state, true)); | ||
const refreshSwallow = () => refresh().catch((err) => { | ||
// Swallow errors if socket is connecting, closing or closed. | ||
// We will automatically call refresh again when we re-establish the connection. | ||
// Using conn.socket.OPEN instead of WebSocket for better node support | ||
if (conn.socket.readyState == conn.socket.OPEN) { | ||
if (conn.connected) { | ||
throw err; | ||
@@ -47,3 +46,3 @@ } | ||
if (unsubProm) | ||
unsubProm.then(unsub => { | ||
unsubProm.then((unsub) => { | ||
unsub(); | ||
@@ -54,3 +53,3 @@ }); | ||
}; | ||
} | ||
}, | ||
}; | ||
@@ -57,0 +56,0 @@ return conn[key]; |
@@ -0,1 +1,2 @@ | ||
import { ERR_CONNECTION_LOST } from "./errors.js"; | ||
import { MessageBase } from "./types.js"; | ||
@@ -31,5 +32,10 @@ import { HaWebSocket } from "./socket.js"; | ||
suspendReconnectPromise?: Promise<void>; | ||
_queuedMessages?: Array<{ | ||
resolve: () => unknown; | ||
reject?: (err: typeof ERR_CONNECTION_LOST) => unknown; | ||
}>; | ||
socket: HaWebSocket; | ||
constructor(socket: HaWebSocket, options: ConnectionOptions); | ||
get haVersion(): string; | ||
get connected(): boolean; | ||
setSocket(socket: HaWebSocket): void; | ||
@@ -40,3 +46,3 @@ addEventListener(eventType: Events, callback: ConnectionEventListener): void; | ||
suspendReconnectUntil(suspendPromise: Promise<void>): void; | ||
suspend(suspendPromise?: Promise<void>): void; | ||
suspend(): void; | ||
close(): void; | ||
@@ -43,0 +49,0 @@ /** |
@@ -27,2 +27,6 @@ /** | ||
} | ||
get connected() { | ||
// Using conn.socket.OPEN instead of WebSocket for better node support | ||
return this.socket.readyState == this.socket.OPEN; | ||
} | ||
setSocket(socket) { | ||
@@ -49,2 +53,9 @@ const oldSocket = this.socket; | ||
}); | ||
const queuedMessages = this._queuedMessages; | ||
if (queuedMessages) { | ||
this._queuedMessages = undefined; | ||
for (const queuedMsg of queuedMessages) { | ||
queuedMsg.resolve(); | ||
} | ||
} | ||
this.fireEvent("ready"); | ||
@@ -77,8 +88,5 @@ } | ||
} | ||
suspend(suspendPromise) { | ||
if (suspendPromise) { | ||
this.suspendReconnectPromise = suspendPromise; | ||
} | ||
suspend() { | ||
if (!this.suspendReconnectPromise) { | ||
throw new Error("Can't suspend without a suspend promise"); | ||
throw new Error("Suspend promise not set"); | ||
} | ||
@@ -108,2 +116,9 @@ this.socket.close(); | ||
} | ||
if (this._queuedMessages) { | ||
if (commandId) { | ||
throw new Error("Cannot queue with commandId"); | ||
} | ||
this._queuedMessages.push({ resolve: () => this.sendMessage(message) }); | ||
return; | ||
} | ||
if (!commandId) { | ||
@@ -117,2 +132,16 @@ commandId = this._genCmdId(); | ||
return new Promise((resolve, reject) => { | ||
if (this._queuedMessages) { | ||
this._queuedMessages.push({ | ||
reject, | ||
resolve: async () => { | ||
try { | ||
resolve(await this.sendMessagePromise(message)); | ||
} | ||
catch (err) { | ||
reject(err); | ||
} | ||
}, | ||
}); | ||
return; | ||
} | ||
const commandId = this._genCmdId(); | ||
@@ -131,6 +160,11 @@ this.commands.set(commandId, { resolve, reject }); | ||
async subscribeMessage(callback, subscribeMessage) { | ||
// Command ID that will be used | ||
const commandId = this._genCmdId(); | ||
if (this._queuedMessages) { | ||
await new Promise((resolve, reject) => { | ||
this._queuedMessages.push({ resolve, reject }); | ||
}); | ||
} | ||
let info; | ||
await new Promise((resolve, reject) => { | ||
// Command ID that will be used | ||
const commandId = this._genCmdId(); | ||
// We store unsubscribe on info object. That way we can overwrite it in case | ||
@@ -144,2 +178,6 @@ // we get disconnected and we have to subscribe again. | ||
unsubscribe: async () => { | ||
// No need to unsubscribe if we're disconnected | ||
if (!this.connected) { | ||
return; | ||
} | ||
await this.sendMessagePromise(messages.unsubscribeEvents(commandId)); | ||
@@ -232,2 +270,11 @@ this.commands.delete(commandId); | ||
catch (err) { | ||
if (this._queuedMessages) { | ||
const queuedMessages = this._queuedMessages; | ||
this._queuedMessages = undefined; | ||
for (const msg of queuedMessages) { | ||
if (msg.reject) { | ||
msg.reject(ERR_CONNECTION_LOST); | ||
} | ||
} | ||
} | ||
if (err === ERR_INVALID_AUTH) { | ||
@@ -245,2 +292,5 @@ this.fireEvent("reconnect-error", err); | ||
this.suspendReconnectPromise = undefined; | ||
// For the first retry after suspend, we will queue up | ||
// all messages. | ||
this._queuedMessages = []; | ||
} | ||
@@ -247,0 +297,0 @@ reconnect(0); |
@@ -186,2 +186,6 @@ (function (global, factory) { | ||
} | ||
get connected() { | ||
// Using conn.socket.OPEN instead of WebSocket for better node support | ||
return this.socket.readyState == this.socket.OPEN; | ||
} | ||
setSocket(socket) { | ||
@@ -208,2 +212,9 @@ const oldSocket = this.socket; | ||
}); | ||
const queuedMessages = this._queuedMessages; | ||
if (queuedMessages) { | ||
this._queuedMessages = undefined; | ||
for (const queuedMsg of queuedMessages) { | ||
queuedMsg.resolve(); | ||
} | ||
} | ||
this.fireEvent("ready"); | ||
@@ -236,8 +247,5 @@ } | ||
} | ||
suspend(suspendPromise) { | ||
if (suspendPromise) { | ||
this.suspendReconnectPromise = suspendPromise; | ||
} | ||
suspend() { | ||
if (!this.suspendReconnectPromise) { | ||
throw new Error("Can't suspend without a suspend promise"); | ||
throw new Error("Suspend promise not set"); | ||
} | ||
@@ -264,2 +272,9 @@ this.socket.close(); | ||
sendMessage(message, commandId) { | ||
if (this._queuedMessages) { | ||
if (commandId) { | ||
throw new Error("Cannot queue with commandId"); | ||
} | ||
this._queuedMessages.push({ resolve: () => this.sendMessage(message) }); | ||
return; | ||
} | ||
if (!commandId) { | ||
@@ -273,2 +288,16 @@ commandId = this._genCmdId(); | ||
return new Promise((resolve, reject) => { | ||
if (this._queuedMessages) { | ||
this._queuedMessages.push({ | ||
reject, | ||
resolve: async () => { | ||
try { | ||
resolve(await this.sendMessagePromise(message)); | ||
} | ||
catch (err) { | ||
reject(err); | ||
} | ||
}, | ||
}); | ||
return; | ||
} | ||
const commandId = this._genCmdId(); | ||
@@ -287,6 +316,11 @@ this.commands.set(commandId, { resolve, reject }); | ||
async subscribeMessage(callback, subscribeMessage) { | ||
// Command ID that will be used | ||
const commandId = this._genCmdId(); | ||
if (this._queuedMessages) { | ||
await new Promise((resolve, reject) => { | ||
this._queuedMessages.push({ resolve, reject }); | ||
}); | ||
} | ||
let info; | ||
await new Promise((resolve, reject) => { | ||
// Command ID that will be used | ||
const commandId = this._genCmdId(); | ||
// We store unsubscribe on info object. That way we can overwrite it in case | ||
@@ -300,2 +334,6 @@ // we get disconnected and we have to subscribe again. | ||
unsubscribe: async () => { | ||
// No need to unsubscribe if we're disconnected | ||
if (!this.connected) { | ||
return; | ||
} | ||
await this.sendMessagePromise(unsubscribeEvents(commandId)); | ||
@@ -378,2 +416,11 @@ this.commands.delete(commandId); | ||
catch (err) { | ||
if (this._queuedMessages) { | ||
const queuedMessages = this._queuedMessages; | ||
this._queuedMessages = undefined; | ||
for (const msg of queuedMessages) { | ||
if (msg.reject) { | ||
msg.reject(ERR_CONNECTION_LOST); | ||
} | ||
} | ||
} | ||
if (err === ERR_INVALID_AUTH) { | ||
@@ -391,2 +438,5 @@ this.fireEvent("reconnect-error", err); | ||
this.suspendReconnectPromise = undefined; | ||
// For the first retry after suspend, we will queue up | ||
// all messages. | ||
this._queuedMessages = []; | ||
} | ||
@@ -678,8 +728,7 @@ reconnect(0); | ||
let store = createStore(); | ||
const refresh = () => fetchCollection(conn).then(state => store.setState(state, true)); | ||
const refresh = () => fetchCollection(conn).then((state) => store.setState(state, true)); | ||
const refreshSwallow = () => refresh().catch((err) => { | ||
// Swallow errors if socket is connecting, closing or closed. | ||
// We will automatically call refresh again when we re-establish the connection. | ||
// Using conn.socket.OPEN instead of WebSocket for better node support | ||
if (conn.socket.readyState == conn.socket.OPEN) { | ||
if (conn.connected) { | ||
throw err; | ||
@@ -716,3 +765,3 @@ } | ||
if (unsubProm) | ||
unsubProm.then(unsub => { | ||
unsubProm.then((unsub) => { | ||
unsub(); | ||
@@ -723,3 +772,3 @@ }); | ||
}; | ||
} | ||
}, | ||
}; | ||
@@ -726,0 +775,0 @@ return conn[key]; |
@@ -5,3 +5,3 @@ { | ||
"sideEffects": false, | ||
"version": "5.3.0", | ||
"version": "5.4.0", | ||
"description": "Home Assistant websocket client", | ||
@@ -29,9 +29,9 @@ "source": "lib/index.ts", | ||
"husky": "^4.2.5", | ||
"lint-staged": "^10.2.7", | ||
"mocha": "^7.2.0", | ||
"lint-staged": "^10.2.10", | ||
"mocha": "^8.0.1", | ||
"prettier": "^2.0.5", | ||
"reify": "^0.20.12", | ||
"rollup": "^2.12.0", | ||
"rollup": "^2.16.1", | ||
"ts-node": "^8.10.2", | ||
"typescript": "^3.9.3" | ||
"typescript": "^3.9.5" | ||
}, | ||
@@ -38,0 +38,0 @@ "files": [ |
@@ -140,4 +140,7 @@ # :aerial_tramway: JavaScript websocket client for Home Assistant | ||
); | ||
connection.suspend(); | ||
``` | ||
When the suspend promise resolves until the connection is re-established, all messages being send will be delayed until the connection is established. If the first reconnect fails, the queued messages will be rejected. | ||
#### Suspend connection | ||
@@ -144,0 +147,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
112538
2106
461