Skip to content
Snippets Groups Projects
main.js 6.61 KiB
Newer Older
  • Learn to ignore specific revisions
  • const {InstanceBase, Regex, runEntrypoint, InstanceStatus, combineRgb} = require('@companion-module/base')
    
    Tobias Ullerich's avatar
    Tobias Ullerich committed
    const UpgradeScripts = require('./upgrades')
    const UpdateActions = require('./actions')
    const UpdateFeedbacks = require('./feedbacks')
    
    Tobias Ullerich's avatar
    Tobias Ullerich committed
    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');
    
    Tobias Ullerich's avatar
    Tobias Ullerich committed
    
    class ModuleInstance extends InstanceBase {
    
        isInitialized = false
        // language=RegExp
    
        wsRegex = '^wss?:\\/\\/([\\da-z.-]+)(:\\d{1,5})?(?:\\/(.*))?$'
    
            'pad-name-changed': new PadNameUpdate(),
    
            'pad-status-changed': new PadStatusUpdate(),
    
            'current-page-changed': new CurrentPageUpdate(),
            'current-page-request': new CurrentPageRequest()
    
    
        constructor(internal) {
            super(internal)
        }
    
        async init(config) {
            this.config = config
    
            this.initWebSocket()
            this.isInitialized = true
    
    
    Tobias Ullerich's avatar
    Tobias Ullerich committed
            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,
                },
    
    Tobias Ullerich's avatar
    Tobias Ullerich committed
        async updateFeedbacks() {
            await UpdateFeedbacks(this)
    
        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}`)
                }
    
                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});
    
    Tobias Ullerich's avatar
    Tobias Ullerich committed
    }
    
    runEntrypoint(ModuleInstance, UpgradeScripts)