Select Git revision
-
Robert Goldmann authoredRobert Goldmann authored
To learn more about this project, read the wiki.
main.js 6.61 KiB
const {InstanceBase, Regex, runEntrypoint, InstanceStatus, combineRgb} = require('@companion-module/base')
const UpgradeScripts = require('./upgrades')
const UpdateActions = require('./actions')
const UpdateFeedbacks = require('./feedbacks')
const WebSocket = require('ws')
const ProjectUpdate = require("./receive/project_update");
const Project = require("./project");
const PadNameUpdate = require("./receive/pad_name_update");
const PadStatusUpdate = require("./receive/pad_status_update");
const CurrentPageUpdate = require("./receive/current_page_update");
const CurrentPageRequest = require("./receive/current_page_request");
const uuid = require('uuid');
const presets = require('./presets');
class ModuleInstance extends InstanceBase {
isInitialized = false
// language=RegExp
wsRegex = '^wss?:\\/\\/([\\da-z.-]+)(:\\d{1,5})?(?:\\/(.*))?$'
messageHandlers = {
'project-current': new ProjectUpdate(),
'pad-name-changed': new PadNameUpdate(),
'pad-status-changed': new PadStatusUpdate(),
'current-page-changed': new CurrentPageUpdate(),
'current-page-request': new CurrentPageRequest()
};
currentProject = new Project({});
constructor(internal) {
super(internal)
}
async init(config) {
this.config = config
this.initWebSocket()
this.isInitialized = true
this.updateActions()
await this.updateFeedbacks()
this.setPresetDefinitions(presets());
}
// When module gets deleted
async destroy() {
this.isInitialized = false
if (this.reconnect_timer) {
clearTimeout(this.reconnect_timer)
this.reconnect_timer = null
}
if (this.ws) {
this.ws.close(1000)
delete this.ws
}
}
async configUpdated(config) {
this.config = config
this.initWebSocket()
}
// Return config fields for web config
getConfigFields() {
return [
{
type: 'textinput',
id: 'host',
label: 'PlayWall IP',
default: '127.0.0.1',
width: 8,
regex: Regex.IP,
},
{
type: 'textinput',
id: 'port',
label: 'PlayWall Port',
default: '9876',
width: 4,
regex: Regex.PORT,
},
{
type: 'checkbox',
id: 'debug_messages',
label: 'Debug messages',
tooltip: 'Log incomming and outcomming messages',
width: 6,
},
{
type: 'checkbox',
id: 'reconnect',
label: 'Reconnect',
tooltip: 'Reconnect on WebSocket error (after 5 secs)',
width: 6,
default: true,
},
]
}
updateActions() {
UpdateActions(this)
}
async updateFeedbacks() {
await UpdateFeedbacks(this)
}
// Websocket handling
maybeReconnect() {
if (this.isInitialized && this.config.reconnect) {
if (this.reconnect_timer) {
clearTimeout(this.reconnect_timer)
}
this.reconnect_timer = setTimeout(() => {
this.initWebSocket()
}, 1000)
}
}
initWebSocket() {
if (this.reconnect_timer) {
clearTimeout(this.reconnect_timer)
this.reconnect_timer = null
}
if (this.config.host == null || this.config.port == null) {
this.log('debug', `PlayWall host '${this.config.host}' or port '${this.config.port}' is invalid`);
this.updateStatus(InstanceStatus.BadConfig, `PlayWall host '${this.config.host}' or port '${this.config.port}' is invalid`)
return
}
const url = `ws://${this.config.host}:${this.config.port}/api`
if (!url || url.match(new RegExp(this.wsRegex)) === null) {
this.updateStatus(InstanceStatus.BadConfig, `WS URL is not defined or invalid`)
return
}
this.updateStatus(InstanceStatus.Connecting)
if (this.ws) {
this.ws.close(1000)
delete this.ws
}
this.ws = new WebSocket(url)
this.ws.on('open', () => {
this.updateStatus(InstanceStatus.Ok)
this.log('debug', `Connection opened`)
this.sendToWebSocket('project-current', {});
})
this.ws.on('close', (code) => {
this.log('debug', `Connection closed with code ${code}`)
this.updateStatus(InstanceStatus.Disconnected, `Connection closed with code ${code}`)
this.maybeReconnect();
})
this.ws.on('message', this.messageReceivedFromWebSocket.bind(this))
this.ws.on('error', (data) => {
this.log('error', `WebSocket error: ${data}`)
})
}
sendToWebSocket(type, payload) {
this.ws.send(JSON.stringify({
'type': type,
'messageId': uuid.v4(),
'payload': payload
}));
}
messageReceivedFromWebSocket(data) {
if (this.config.debug_messages) {
this.log('debug', `Message received: ${data}`)
}
const message = JSON.parse(data)
if (message.type != null) {
if (this.messageHandlers[message.type] != null) {
this.messageHandlers[message.type].handleMessage(this, message)
} else {
this.log('debug', `Cannot handle incoming message of type ${message.type}`)
}
} else if (message.updateType != null) {
if (this.messageHandlers[message.updateType] != null) {
this.messageHandlers[message.updateType].handleMessage(this, message)
} else {
this.log('debug', `Cannot handle incoming message of updateType ${message.updateType}`)
}
} else {
this.log('debug', `Cannot handle incoming message ${data}`)
}
}
updateVariables() {
this.setVariableDefinitions([...Array(this.currentProject.getPadCount()).keys()].map(index => {
return {variableId: `pad-${index}`, name: `Pad Index ${index + 1}`}
}))
}
updateVariablesForCurrentPage() {
let pads = this.currentProject.getAllPadsOfCurrentPage();
for (let i in pads) {
let pad = pads[i];
this.log('debug', `Update variable 'pad-${pad.position}'`);
this.setVariableValues({[`pad-${pad.position}`]: pad.name});
}
}
}
runEntrypoint(ModuleInstance, UpgradeScripts)