Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure local ws connections are closed on disconnect #255

Merged
merged 1 commit into from
May 2, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 31 additions & 16 deletions lib/editor/tunnel.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class EditorTunnel {

// How long to wait before attempting to reconnect. Start at 500ms - back
// off if connect fails
this.reconnectDelay = 500
this.reconnectDelay = 1500

const forgeURL = new URL(config.forgeURL)
forgeURL.protocol = forgeURL.protocol === 'http:' ? 'ws:' : 'wss:'
Expand Down Expand Up @@ -86,7 +86,7 @@ class EditorTunnel {
unexpectedPacketMonitor = 0
info('Editor tunnel connected')
// Reset reconnectDelay
this.reconnectDelay = 500
this.reconnectDelay = 1500
this.socket.on('message', async (message) => {
// a message coming over the tunnel from a remote editor
const request = JSON.parse(message.toString('utf-8'))
Expand Down Expand Up @@ -261,22 +261,22 @@ class EditorTunnel {
// Assume we need to be reconnecting. If this close is due
// to a request from the platform to turn off editor access,
// .close will get called
const reconnectDelay = this.reconnectDelay
// Bump the delay for next time... 500ms, 1.5s, 4.5s, 10s 10s 10s...
this.reconnectDelay = Math.min(this.reconnectDelay * 3, 10000)
this.reconnectTimeout = setTimeout(() => {
this.connect()
}, reconnectDelay)
this.closeLocalWebSockets()
this.reconnect()
} else {
// A 4004/'No tunnel' response means the platform doesn't think
// we should be connecting - so no point retrying
this.close(code, reason)
}
})
socket.on('error', (err) => {
warn(`Editor tunnel error: ${err}`)
console.warn('socket.error', err)
this.close(1006, err.message) // 1006 = Abnormal Closure
if (err.code === 'ECONNREFUSED') {
warn('Editor tunnel connection refused')
} else {
warn(`Editor tunnel error: ${err}`)
console.warn('socket.error', err)
this.close(1006, err.message) // 1006 = Abnormal Closure
}
})
this.socket = socket
return !!(await this.waitForConnection())
Expand All @@ -285,11 +285,8 @@ class EditorTunnel {
close (code, reason) {
code = code || 1000
reason = reason || 'Normal Closure'
// loop through each local comms ws client and close its connection
Object.keys(this.wsClients || {}).forEach(c => {
this.wsClients[c]?.close()
delete this.wsClients[c]
})

this.closeLocalWebSockets()

// close the socket
if (this.socket) {
Expand Down Expand Up @@ -335,6 +332,24 @@ class EditorTunnel {
}, 2000)
})
}

closeLocalWebSockets () {
// Close all ws clients to the local Node-RED
Object.keys(this.wsClients || {}).forEach(c => {
this.wsClients[c]?.close()
delete this.wsClients[c]
})
}

reconnect () {
warn(`Editor tunnel reconnecting in ${(this.reconnectDelay / 1000).toFixed(1)}s`)
const reconnectDelay = this.reconnectDelay
// Bump the delay for next time... 500ms, 1.5s, 4.5s, 10s 10s 10s...
this.reconnectDelay = Math.min(this.reconnectDelay * 3, 10000)
this.reconnectTimeout = setTimeout(() => {
this.connect()
}, reconnectDelay)
}
}

module.exports = EditorTunnel
Loading