81 lines
2.7 KiB
JavaScript
81 lines
2.7 KiB
JavaScript
import { Emitter as EventEmitter } from 'strict-event-emitter'
|
|
import { networkInterfaces } from 'node:os'
|
|
import WebSocket from 'ws'
|
|
|
|
import { CONNECTION_TIMEOUT } from '../constants.js'
|
|
|
|
const DISCONNECT_CODES = {
|
|
NORMAL: 1000,
|
|
TIMEOUT: 1006,
|
|
}
|
|
|
|
export default class LoupedeckWSConnection extends EventEmitter {
|
|
constructor({ host } = {}) {
|
|
super()
|
|
this.host = host
|
|
// Track last interaction time
|
|
this.lastTick = Date.now()
|
|
// How long until declaring a timed out connetion
|
|
this.connectionTimeout = CONNECTION_TIMEOUT
|
|
}
|
|
// Automatically find Loupedeck IP by scanning network interfaces
|
|
static discover() {
|
|
const results = []
|
|
const interfaces = Object.values(networkInterfaces()).flat()
|
|
for (const iface of interfaces) {
|
|
if (iface.address.startsWith('100.127')) {
|
|
results.push({
|
|
connectionType: this,
|
|
productId: 0x04,
|
|
host: iface.address.replace(/.2$/, '.1')
|
|
})
|
|
}
|
|
}
|
|
return results
|
|
}
|
|
checkConnected() {
|
|
this._keepAliveTimer = setTimeout(this.checkConnected.bind(this), this.connectionTimeout * 2)
|
|
if (Date.now() - this.lastTick > this.connectionTimeout) this.connection.terminate()
|
|
}
|
|
close() {
|
|
if (!this.connection) return
|
|
const closed = new Promise(res => this.connection.once('close', res))
|
|
this.connection.close()
|
|
return closed
|
|
}
|
|
connect() {
|
|
this.address = `ws://${this.host}`
|
|
this.connection = new WebSocket(this.address)
|
|
this.connection.on('open', this.onConnect.bind(this))
|
|
this.connection.on('message', this.onReceive.bind(this))
|
|
this.connection.on('close', this.onDisconnect.bind(this))
|
|
return new Promise(res => {
|
|
this._connectionResolver = res
|
|
})
|
|
}
|
|
isReady() {
|
|
return this.connection !== undefined && this.connection.readyState === this.connection.OPEN
|
|
}
|
|
onConnect() {
|
|
this.emit('connect', { address: this.address })
|
|
this._keepAliveTimer = setTimeout(this.checkConnected.bind(this), this.connectionTimeout * 2)
|
|
this._connectionResolver()
|
|
}
|
|
onDisconnect(errCode) {
|
|
let error = null
|
|
switch (errCode) {
|
|
case DISCONNECT_CODES.TIMEOUT:
|
|
error = new Error('Connection timeout - was the device disconnected?')
|
|
}
|
|
clearTimeout(this._keepAliveTimer)
|
|
this.emit('disconnect', error)
|
|
}
|
|
onReceive(buff) {
|
|
this.lastTick = Date.now()
|
|
this.emit('message', buff)
|
|
}
|
|
send(buff) {
|
|
this.connection.send(buff)
|
|
}
|
|
}
|