@showcomposer/broker
Version:
communication core for ShowComposer
208 lines (207 loc) • 7.34 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// Logging
const nodelogging_1 = require("@hibas123/nodelogging");
const json = require("big-json");
const deepForEach = require("deep-for-each");
const fs = require("fs");
const get = require("get-value");
const merge = require("merge-deep");
const os = require("os");
const PubSub = require("pubsub-js");
const set = require("set-value");
class SCData {
constructor() {
this.file = "";
this.fileLoaded = false;
this.staticChanged = false;
this.data = {};
this.static = {};
this.subscribers = [];
this.file = os.homedir() + "/SCProject.json";
this.load();
this.staticLastChange = Date.now();
this.lastSave = Date.now();
setInterval(() => {
if (this.staticChanged) {
if (Date.now() - this.lastSave > 10000) {
this.save();
}
}
}, 5000);
}
set(type, cmd) {
const p = cmd.split(":");
this.setPlain(type, cmd, this.base64toString(p[1]));
}
setPlain(type, cmd, value = true) {
const p = cmd.split(":");
const key = p[0];
// Switch between different set-types
switch (type) {
case "LIVE":
set(this.data, key, value);
PubSub.publish(key, "SET LIVE " + key + ":" + this.stringToBase64(value));
break;
case "STATIC":
set(this.data, key, value);
PubSub.publish(key, "SET STATIC " + key + ":" + this.stringToBase64(value));
set(this.static, key, value);
// Save file if necessary and set flags
this.staticChanged = true;
if ((Date.now() - this.staticLastChange) > 250) {
this.save();
}
this.staticLastChange = Date.now();
break;
case "LINK":
// ToDo
break;
case "TICK":
set(this.data, key, value);
PubSub.publish(key, "SET TICK " + key + ":" + this.stringToBase64(value));
break;
}
nodelogging_1.Logging.debug("SET " + key + " to " + value + " (" + type + ")");
return "0";
}
assign(type, key, value = "e30=") {
// Build POJO from encoded string
const assObject = this.base64toPOJO(value);
// Prepare object with nested key to merge at root level
const deepAssObject = {};
set(deepAssObject, key, assObject);
// Switch between different assign-types
switch (type) {
case "LIVE":
this.data = merge(this.data, deepAssObject);
PubSub.publish(key, "ASSIGN LIVE " + key + " " + value);
break;
case "STATIC":
this.data = merge(this.data, deepAssObject);
PubSub.publish(key, "ASSIGN STATIC " + key + " " + value);
this.static = merge(this.static, deepAssObject);
// Save file if necessary and set flags
this.staticChanged = true;
if ((Date.now() - this.staticLastChange) > 250) {
this.save();
}
this.staticLastChange = Date.now();
break;
case "LINK":
// ToDo
break;
case "TICK":
this.data = merge(this.data, deepAssObject);
PubSub.publish(key, "ASSIGN TICK " + key + " " + value);
break;
}
nodelogging_1.Logging.debug("ASSIGN " + JSON.stringify(assObject) + " to " + key + " (" + type + ")");
return "0";
}
sub(key, cb, t) {
const id = this.subscribers.length;
const token = PubSub.subscribe(key, (m, d) => {
cb(m, d, id, t);
});
nodelogging_1.Logging.log("New subscription to " + key);
this.subscribers[id] = token;
return { t: token, id };
}
unsub(token) {
PubSub.unsubscribe(token);
}
unsubId(id) {
if (this.subscribers[id]) {
PubSub.unsubscribe(this.subscribers[id]);
this.subscribers[id] = false;
return true;
}
return false;
}
dump(key) {
const d = get(this.data, key);
nodelogging_1.Logging.debug("DUMP " + key);
return this.POJOtoBase64(d);
}
save() {
if (this.fileLoaded) {
nodelogging_1.Logging.log("Saving project into " + this.file);
const wstream = fs.createWriteStream(this.file);
const stringifyStream = json.createStringifyStream({
body: this.static,
});
stringifyStream.pipe(wstream);
stringifyStream.on("end", () => {
wstream.end();
this.lastSave = Date.now();
this.staticChanged = false;
});
wstream.on("finish", () => {
fs.appendFile(this.file, os.EOL, "utf8", (err) => {
if (err) {
nodelogging_1.Logging.error(err);
}
});
});
wstream.on("error", (err) => {
nodelogging_1.Logging.error("Error Saving project: " + err);
});
}
else {
nodelogging_1.Logging.error("Cannot save to unloaded file!");
}
}
load() {
if (fs.existsSync(this.file)) {
nodelogging_1.Logging.log("Loading project from " + this.file);
const readStream = fs.createReadStream(this.file);
const parseStream = json.createParseStream();
parseStream.on("data", (pojo) => {
deepForEach(pojo, (v, k, s, p) => {
if (typeof v !== "object") {
this.setPlain("STATIC", p, v);
}
});
this.fileLoaded = true;
});
readStream.pipe(parseStream);
}
else {
this.fileLoaded = true;
nodelogging_1.Logging.log("No File, start project with file " + this.file);
}
}
// Base 64 helper methods
base64toPOJO(encoded) {
const buff = Buffer.from(encoded, "base64");
const text = buff.toString("utf8");
return JSON.parse(text);
}
POJOtoBase64(obj) {
const str = JSON.stringify(obj);
if (typeof str !== "string") {
nodelogging_1.Logging.error("Invalid object on POJOtoBase64");
return;
}
const buff = Buffer.from(str, "utf8");
const b64 = buff.toString("base64");
return b64;
}
base64toString(encoded) {
const buff = Buffer.from(encoded, "base64");
return buff.toString("utf8");
}
stringToBase64(str) {
if (typeof str !== "string") {
if (!(str = str.toString())) {
nodelogging_1.Logging.error("Invalid value on stringToBase64");
return;
}
}
const buff = Buffer.from(str, "utf8");
const b64 = buff.toString("base64");
return b64;
}
}
exports.SCData = SCData;