Major rework to server.
This commit is contained in:
parent
fd01385fe8
commit
451af8155d
@ -1,2 +1,3 @@
|
|||||||
#Port you want the server to run on. It is best to use something uncomon
|
CONFIG_PATH=.yasd
|
||||||
PORT=8899
|
CONFIG_FILE=deck_config.json
|
||||||
|
WEBSERVER_PORT=8899
|
36
apps/server/Main.js
Normal file
36
apps/server/Main.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
require('dotenv').config();
|
||||||
|
const sd = require('./lib/Deck');
|
||||||
|
const web = require('./webserver/WebServer');
|
||||||
|
const cm = require('./lib/ConfigManager');
|
||||||
|
const pl = require('./lib/PluginLoader');
|
||||||
|
|
||||||
|
const EventEmitter = require('events');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extend the default EventEmitter to have the ability to return an object.
|
||||||
|
* Normal normal events work as expected
|
||||||
|
* https://stackoverflow.com/questions/42802931/node-js-how-can-i-return-a-value-from-an-event-listener
|
||||||
|
*/
|
||||||
|
class EventObjectEmitter extends EventEmitter {
|
||||||
|
emitObject(event, obj = {}){
|
||||||
|
this.emit(event, obj);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
global.eventBus = new EventObjectEmitter();
|
||||||
|
|
||||||
|
console.log("Staring")
|
||||||
|
|
||||||
|
sd.init();
|
||||||
|
web.init();
|
||||||
|
|
||||||
|
global.pluginloader = new pl();
|
||||||
|
pluginloader.loadFromFolder();
|
||||||
|
|
||||||
|
//config last to be loaded
|
||||||
|
//It fires off the config_changed event that signals the app is ready
|
||||||
|
cm.init();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
console.log("Ready!")
|
@ -1,20 +0,0 @@
|
|||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
|
|
||||||
router.get('/', (req, res) => {
|
|
||||||
res.status(200).send("Debug");
|
|
||||||
});
|
|
||||||
|
|
||||||
router.get('/showconfig', (req, res)=>{
|
|
||||||
res.status(200).send('CONFIG DATA');
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/clearscreen', (req, res)=>{
|
|
||||||
res.sendStatus(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.post('/resetconfig', (req, res)=> {
|
|
||||||
res.status(200).send('CONFIG RESET');
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = router;
|
|
@ -1,15 +0,0 @@
|
|||||||
const express = require('express')
|
|
||||||
const router = express.Router();
|
|
||||||
const debugRoutes = require('./debug/routes');
|
|
||||||
const setRoutes = require('./set/routes');
|
|
||||||
const unsetRoutes = require('./unset/routes');
|
|
||||||
|
|
||||||
router.get('/', (req, res) => {
|
|
||||||
res.sendStatus(200);
|
|
||||||
});
|
|
||||||
|
|
||||||
router.use('/debug', debugRoutes);
|
|
||||||
router.use('/set', setRoutes);
|
|
||||||
router.use('/unset', unsetRoutes);
|
|
||||||
|
|
||||||
module.exports = router;
|
|
@ -1,8 +0,0 @@
|
|||||||
const express = require('express');
|
|
||||||
const router = express.Router();
|
|
||||||
|
|
||||||
router.get('/', (req, res) => {
|
|
||||||
res.status(200).send("Unset");
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = router;
|
|
@ -1,29 +0,0 @@
|
|||||||
require('dotenv').config();
|
|
||||||
const express = require('express');
|
|
||||||
const cors = require('cors');
|
|
||||||
const app = express();
|
|
||||||
const port = process.env.PORT;
|
|
||||||
const apiRoutes = require('./api/routes');
|
|
||||||
const { openStreamDeck } = require('@elgato-stream-deck/node');
|
|
||||||
|
|
||||||
const myStreamDeck = openStreamDeck();
|
|
||||||
|
|
||||||
myStreamDeck.on('down', (keyIndex) => {
|
|
||||||
console.log('key %d down', keyIndex)
|
|
||||||
})
|
|
||||||
|
|
||||||
myStreamDeck.on('up', (keyIndex) => {
|
|
||||||
console.log('key %d up', keyIndex)
|
|
||||||
})
|
|
||||||
|
|
||||||
app.use(cors())
|
|
||||||
|
|
||||||
app.get('/', (req, res) => {
|
|
||||||
res.status(200).send({some: 'json'});
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use('/api', apiRoutes);
|
|
||||||
|
|
||||||
app.listen(port, () => {
|
|
||||||
console.log(`Stream deck server listening on port ${port}`);
|
|
||||||
});
|
|
132
apps/server/lib/ConfigManager.js
Normal file
132
apps/server/lib/ConfigManager.js
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const homedir = require('os').homedir();
|
||||||
|
const configPath = [homedir, process.env.CONFIG_PATH].join('/');
|
||||||
|
const fullConfigPath = [configPath, process.env.CONFIG_FILE].join('/');
|
||||||
|
const deckButton = require('./DeckButton');
|
||||||
|
const EVENTS = require('./Events');
|
||||||
|
|
||||||
|
let configState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the configManager.
|
||||||
|
* This will check for the config file and folder on disk and create a blank configuration if one does not exist.
|
||||||
|
*/
|
||||||
|
function init(){
|
||||||
|
console.log(" - Starting configManager.js")
|
||||||
|
|
||||||
|
//check for existance of config folder in user home dir
|
||||||
|
try {
|
||||||
|
if(fs.existsSync(fullConfigPath)){
|
||||||
|
console.log(" - Config file exists");
|
||||||
|
} else {
|
||||||
|
console.log(" - No config file found. Creating one now");
|
||||||
|
let blankConfigObject = {"backgroundImage": "",pages:[{pagename: "Blank Page",buttons: []}]}
|
||||||
|
for (let i = 0; i < 32; i++) {
|
||||||
|
blankConfigObject.pages[0].buttons.push(new deckButton('', "Test Button: " + i, "#000000", "builtin:nullAction:"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//Make config folder.
|
||||||
|
fs.mkdirSync(configPath, {recursive: true}, (err) => {
|
||||||
|
if(err) throw err;
|
||||||
|
});
|
||||||
|
|
||||||
|
//Make config file.
|
||||||
|
fs.writeFileSync(fullConfigPath, JSON.stringify(blankConfigObject,null,2), (err) => {
|
||||||
|
if(err) throw err;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(" - " + error)
|
||||||
|
}
|
||||||
|
|
||||||
|
//Announce the loaded config on the bus
|
||||||
|
eventBus.emit(EVENTS.CONFIG_READY, this.getConfig());
|
||||||
|
|
||||||
|
eventBus.on(EVENTS.UPDATE_BUTTON, data => {
|
||||||
|
console.log("Update button with: " + JSON.stringify(data))
|
||||||
|
updateButton(data.pageNumber, data.buttonIndex, data.iconPath, data.label, data.color, data.pressAction, data.releaseAction, data.toggleable, data.toggleIcon)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will read the config from the defined configuration path.
|
||||||
|
* @returns
|
||||||
|
* An object of pages.
|
||||||
|
* Each page is an object with a name and an array of deckButton objects.
|
||||||
|
* Each array is 32 in length to match the StreamDeckXL.
|
||||||
|
* All smaller StreamDecks fit within this array
|
||||||
|
*/
|
||||||
|
function getConfig(){
|
||||||
|
const data = JSON.parse(fs.readFileSync(fullConfigPath));
|
||||||
|
configState = data;
|
||||||
|
|
||||||
|
for (let i = 0; i < data.pages.length; i++) {
|
||||||
|
const page = data.pages[i];
|
||||||
|
for (let j = 0; j < page.buttons.length; j++) {
|
||||||
|
const deckBtn = deckButton.from(page.buttons[j]);
|
||||||
|
configState.pages[i].buttons[j] = deckBtn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return configState;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the current config state to the disk
|
||||||
|
*/
|
||||||
|
function writeConfig(){
|
||||||
|
fs.writeFileSync(fullConfigPath, JSON.stringify(configState, null, 2), err => {
|
||||||
|
if(err){
|
||||||
|
console.error(err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//Local function to modify config
|
||||||
|
/**
|
||||||
|
* Call to notify the event bus of a new config
|
||||||
|
*/
|
||||||
|
function configChanged(){
|
||||||
|
writeConfig();
|
||||||
|
eventBus.emit('config_changed', configState);
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPage(){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateButton(pageNumber, buttonIndex, iconPath, label, color, pressAction, releaseAction, toggleable, toggleIcon){
|
||||||
|
let button = configState.pages[pageNumber].buttons[buttonIndex];
|
||||||
|
|
||||||
|
if(iconPath){
|
||||||
|
button.iconPath = iconPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(label){
|
||||||
|
button.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(color){
|
||||||
|
button.color = color;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pressAction){
|
||||||
|
button.pressAction = pressAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(releaseAction){
|
||||||
|
button.releaseAction = releaseAction;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(toggleable){
|
||||||
|
button.toggleable = toggleable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(toggleIcon){
|
||||||
|
button.toggleIcon = toggleIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
configChanged()
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {init, getConfig, writeConfig}
|
78
apps/server/lib/Deck.js
Normal file
78
apps/server/lib/Deck.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
const { openStreamDeck } = require('@elgato-stream-deck/node');
|
||||||
|
const util = require('./util');
|
||||||
|
const EVENTS = require('./Events');
|
||||||
|
|
||||||
|
let myStreamDeck;
|
||||||
|
let deckConfig;
|
||||||
|
let iconBuffers=[];
|
||||||
|
let activePage = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function init(){
|
||||||
|
console.log(" - Starting deck.js")
|
||||||
|
|
||||||
|
eventBus.on(EVENTS.CONFIG_READY, config => {
|
||||||
|
deckConfig = config;
|
||||||
|
generateIcons().then(()=>{
|
||||||
|
drawPage(activePage)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
eventBus.on(EVENTS.CONFIG_CHANGED, newConfig => {
|
||||||
|
console.log("Config changed event received in DECK");
|
||||||
|
deckConfig = newConfig;
|
||||||
|
generateIcons().then(()=>{
|
||||||
|
drawPage(activePage)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
eventBus.on(EVENTS.GET_ACTIVE_DECK, (e)=>{
|
||||||
|
e.deck = myStreamDeck;
|
||||||
|
})
|
||||||
|
|
||||||
|
myStreamDeck = openStreamDeck();
|
||||||
|
myStreamDeck.clearPanel();
|
||||||
|
|
||||||
|
registerCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerCallbacks(){
|
||||||
|
myStreamDeck.on('down', (keyIndex) => {
|
||||||
|
deckConfig.pages[0].buttons[keyIndex].press()
|
||||||
|
});
|
||||||
|
|
||||||
|
myStreamDeck.on('up', (keyIndex) => {
|
||||||
|
deckConfig.pages[0].buttons[keyIndex].release()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function drawPage(pageNum){
|
||||||
|
activePage = pageNum;
|
||||||
|
for (let i = 0; i < myStreamDeck.NUM_KEYS; i++) {
|
||||||
|
const color = util.hexToRGB(deckConfig.pages[pageNum].buttons[i].color)
|
||||||
|
myStreamDeck.fillKeyColor(i, color.r, color.g, color.b)
|
||||||
|
const buffer = iconBuffers[pageNum][i];
|
||||||
|
if(buffer) myStreamDeck.fillKeyBuffer(i, iconBuffers[pageNum][i])
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generateIcons(){
|
||||||
|
for (let i = 0; i < deckConfig.pages.length; i++) {
|
||||||
|
const page = deckConfig.pages[i];
|
||||||
|
iconBuffers.push([]);
|
||||||
|
for (let j = 0; j < page.buttons.length; j++) {
|
||||||
|
const deckBtn = deckConfig.pages[i].buttons[j];
|
||||||
|
if(deckBtn.iconPath != ''){
|
||||||
|
let buffer = await util.buttonImageToBuffer(deckBtn.iconPath, myStreamDeck.ICON_SIZE)
|
||||||
|
iconBuffers[i][j] = buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { init }
|
59
apps/server/lib/DeckButton.js
Normal file
59
apps/server/lib/DeckButton.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
module.exports = class deckButton {
|
||||||
|
constructor(iconPath, label, color, pressAction, releaseAction=null, toggleable=false, toggleIcon=null){
|
||||||
|
this.iconPath = iconPath;
|
||||||
|
this.label = label;
|
||||||
|
this.color = color;
|
||||||
|
this.pressAction = pressAction;
|
||||||
|
this.releaseAction = releaseAction;
|
||||||
|
this.toggleable = toggleable;
|
||||||
|
this.toggleIcon = toggleIcon;
|
||||||
|
}
|
||||||
|
|
||||||
|
press(){
|
||||||
|
if(!this.pressAction){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let action = this.pressAction.split(':');
|
||||||
|
try {
|
||||||
|
const o = pluginloader.plugins[action[0]];
|
||||||
|
const f = o[action[1]]
|
||||||
|
const a = f(action[2])
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Press Referenced plugin not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
release(){
|
||||||
|
if(!this.releaseAction){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let action = this.releaseAction.split(':');
|
||||||
|
try {
|
||||||
|
const o = pluginloader.plugins[action[0]];
|
||||||
|
const f = o[action[1]]
|
||||||
|
const a = f(action[2])
|
||||||
|
} catch (error) {
|
||||||
|
console.log("Release Referenced plugin not found.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON() {
|
||||||
|
return {
|
||||||
|
"iconPath": this.iconPath,
|
||||||
|
"label": this.label,
|
||||||
|
"color": this.color,
|
||||||
|
"pressAction": this.pressAction,
|
||||||
|
"releaseAction": this.releaseAction,
|
||||||
|
"toggleable": this.toggleable,
|
||||||
|
"toggleIcon": this.toggleIcon
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static from(json) {
|
||||||
|
return Object.assign(new deckButton(), json)
|
||||||
|
}
|
||||||
|
}
|
8
apps/server/lib/Events.js
Normal file
8
apps/server/lib/Events.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
UPDATE_BUTTON: "update_button",
|
||||||
|
UPDATE_PAGE: "update_page",
|
||||||
|
CONFIG_READY: "config_ready",
|
||||||
|
CONFIG_CHANGED: "config_changed",
|
||||||
|
GET_CONFIG: "get_config",
|
||||||
|
GET_ACTIVE_DECK: "get_deck",
|
||||||
|
}
|
25
apps/server/lib/PluginLoader.js
Normal file
25
apps/server/lib/PluginLoader.js
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads modules from the plugins folder.
|
||||||
|
* Will expose the plugin on the event bus.
|
||||||
|
* @example
|
||||||
|
*/
|
||||||
|
class PluginLoader {
|
||||||
|
constructor(){
|
||||||
|
this.plugins = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadFromFolder() {
|
||||||
|
const dirList = fs.readdirSync(path.resolve(__dirname, "../plugins"));
|
||||||
|
for (let file in dirList) {
|
||||||
|
console.log(" - Found plugin: " + dirList[file])
|
||||||
|
const pluginName = dirList[file].replace('.js', '');
|
||||||
|
const module = require("../plugins/" + dirList[file]);
|
||||||
|
this.plugins = {...this.plugins, [pluginName]: module};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = PluginLoader;
|
60
apps/server/lib/util.js
Normal file
60
apps/server/lib/util.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const sharp = require('sharp');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a promise to fill the button image buffer
|
||||||
|
* @param {*} imgPath
|
||||||
|
* @param {*} iconSize
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function buttonImageToBuffer(imgPath, iconSize){
|
||||||
|
const buffer = await sharp(path.resolve(imgPath))
|
||||||
|
.flatten()
|
||||||
|
.resize(iconSize, iconSize)
|
||||||
|
.raw()
|
||||||
|
.toBuffer()
|
||||||
|
.catch( err => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
return Promise.resolve(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the buffer to fill the SD Panel
|
||||||
|
* @param {*} imgPath
|
||||||
|
* @param {*} iconSize
|
||||||
|
* @param {*} cols
|
||||||
|
* @param {*} rows
|
||||||
|
* @param {*} callback
|
||||||
|
*/
|
||||||
|
async function panelImageToBuffer(imgPath, iconSize, cols, rows, callback){
|
||||||
|
await sharp(path.resolve(imgPath))
|
||||||
|
.flatten()
|
||||||
|
.resize(iconSize*cols, iconSize*rows)
|
||||||
|
.raw()
|
||||||
|
.toBuffer()
|
||||||
|
.then( data => {
|
||||||
|
callback(data)
|
||||||
|
})
|
||||||
|
.catch( err => {
|
||||||
|
console.log(err)
|
||||||
|
callback(null)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
|
||||||
|
* @param {hex color code} hex
|
||||||
|
* @returns Object with r g b values.
|
||||||
|
*/
|
||||||
|
function hexToRGB(hex){
|
||||||
|
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||||
|
return result ? {
|
||||||
|
r: parseInt(result[1], 16),
|
||||||
|
g: parseInt(result[2], 16),
|
||||||
|
b: parseInt(result[3], 16)
|
||||||
|
} : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {buttonImageToBuffer, panelImageToBuffer, hexToRGB}
|
@ -3,16 +3,17 @@
|
|||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "nodemon index.js",
|
"dev": "nodemon Main.js",
|
||||||
"start": "node index.js"
|
"start": "node Main.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@elgato-stream-deck/node": "5.3.1",
|
"@elgato-stream-deck/node": "5.3.1",
|
||||||
"express": "^4.17.3",
|
"express": "^4.17.3",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"open": "^8.4.0",
|
"open": "^8.4.0",
|
||||||
"robotjs": "^0.6.0",
|
"dotenv": "16.0.0",
|
||||||
"dotenv": "16.0.0"
|
"@nut-tree/nut-js": "2.0.1",
|
||||||
|
"sharp": "0.30.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"nodemon": "^2.0.15"
|
"nodemon": "^2.0.15"
|
||||||
|
34
apps/server/plugins/builtin.js
Normal file
34
apps/server/plugins/builtin.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* Placeholder action
|
||||||
|
*/
|
||||||
|
function nullAction(){
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes the active page.
|
||||||
|
* @param {The desired page} page
|
||||||
|
*/
|
||||||
|
function changePage(page){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the brightness of the streamdeck
|
||||||
|
* @param {The relative change in brightness.} relativeChange
|
||||||
|
* @example
|
||||||
|
* changeBrightness(5) - Plus 5% brightness
|
||||||
|
* changeBrightness(-5) - Minus 5% brightness
|
||||||
|
*/
|
||||||
|
function changeBrightness(relativeChange){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets desired brightness on the streamdeck. (0 - 100)
|
||||||
|
* @param {Percent brightness} percent
|
||||||
|
*/
|
||||||
|
function setBrightness(percent){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports={changePage, changeBrightness, setBrightness, nullAction}
|
36
apps/server/plugins/keyboard.js
Normal file
36
apps/server/plugins/keyboard.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
const {keyboard, Key } = require('@nut-tree/nut-js');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A few predefined shortcuts for common actions like copy, paste, etc...
|
||||||
|
*/
|
||||||
|
const SHORTCUTS = {
|
||||||
|
copy: [Key.LeftControl, Key.C],
|
||||||
|
paste: [Key.LeftControl, Key.V],
|
||||||
|
cut: [Key.LeftControl, Key.X],
|
||||||
|
altf4: [Key.LeftAlt, Key.F4]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will type a string with a provided delay.
|
||||||
|
* @param {A string or sequence of keys to type. Wrapper for @nut-tree/nut-js keyboard class} string
|
||||||
|
* @param {Delay between keypresses in milliseconds.} delay
|
||||||
|
*/
|
||||||
|
function typeString(string, delay = 0){
|
||||||
|
keyboard.config.autoDelayMs = delay
|
||||||
|
keyboard.type(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Will type a sequence of keys.
|
||||||
|
* You can also call on some predefined shortcuts.
|
||||||
|
* @param {An array of keys using the nutjs key import or key codes} keys
|
||||||
|
* @example
|
||||||
|
* typeCommnad(Key.LeftControl, Key.C)
|
||||||
|
* typeCommand(SHORTCUTS.copy)
|
||||||
|
*/
|
||||||
|
function typeCommand(keys){
|
||||||
|
keyboard.pressKey(...keys);
|
||||||
|
keyboard.releaseKey(...keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {SHORTCUTS, typeCommand, typeString}
|
30
apps/server/webserver/WebServer.js
Normal file
30
apps/server/webserver/WebServer.js
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
const EVENTS = require('../lib/Events');
|
||||||
|
const express = require('express');
|
||||||
|
const cors = require('cors');
|
||||||
|
const app = express();
|
||||||
|
const port = 8899;
|
||||||
|
const api = require('./api/routes');
|
||||||
|
|
||||||
|
function init(){
|
||||||
|
eventBus.on(EVENTS.CONFIG_READY, config => {
|
||||||
|
});
|
||||||
|
|
||||||
|
eventBus.on(EVENTS.CONFIG_CHANGED, newConfig => {
|
||||||
|
console.log("Config changed event received in WEB");
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(cors());
|
||||||
|
app.use(express.json())
|
||||||
|
app.use('/api', api)
|
||||||
|
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.sendStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Stream deck server listening on port ${port}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {init}
|
14
apps/server/webserver/api/buttons.js
Normal file
14
apps/server/webserver/api/buttons.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const EVENTS = require('../../lib/Events');
|
||||||
|
|
||||||
|
router.get('/', (req, res) => {
|
||||||
|
res.sendStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post('/updateButton', (req, res) => {
|
||||||
|
eventBus.emit(EVENTS.UPDATE_BUTTON, req.body)
|
||||||
|
res.sendStatus(200);
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router;
|
14
apps/server/webserver/api/info.js
Normal file
14
apps/server/webserver/api/info.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const EVENTS = require('../../lib/Events');
|
||||||
|
|
||||||
|
router.get('/', (req, res) => {
|
||||||
|
res.sendStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.get('/device', (req, res) => {
|
||||||
|
const deckInfo = eventBus.emitObject(EVENTS.GET_ACTIVE_DECK, {deck: {}});
|
||||||
|
res.status(200).send(JSON.stringify(deckInfo.deck.device.deviceProperties))
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
@ -1,8 +1,9 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
const EVENTS = require('../../lib/Events');
|
||||||
|
|
||||||
router.get('/', (req, res) => {
|
router.get('/', (req, res) => {
|
||||||
res.status(200).send("Set");
|
res.sendStatus(200);
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
16
apps/server/webserver/api/routes.js
Normal file
16
apps/server/webserver/api/routes.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
|
||||||
|
const info = require('./info');
|
||||||
|
const buttons = require('./buttons');
|
||||||
|
const pages = require('./pages');
|
||||||
|
|
||||||
|
router.get('/', (req, res) => {
|
||||||
|
res.sendStatus(200);
|
||||||
|
});
|
||||||
|
|
||||||
|
router.use('/info', info);
|
||||||
|
router.use('/buttons', buttons);
|
||||||
|
router.use('/pages', pages)
|
||||||
|
|
||||||
|
module.exports = router;
|
Loading…
Reference in New Issue
Block a user