Fix preload bridge crash and bump version to 0.2.0
This commit is contained in:
Binary file not shown.
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
BIN
Binary file not shown.
Vendored
BIN
Binary file not shown.
Generated
+73
-7
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "time4midi",
|
"name": "time4midi",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "time4midi",
|
"name": "time4midi",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"knx": "^0.0.1",
|
"knx": "^2.5.4",
|
||||||
"modbus-serial": "^8.0.25",
|
"modbus-serial": "^8.0.25",
|
||||||
"mqtt": "^5.10.4",
|
"mqtt": "^5.10.4",
|
||||||
"serialport": "^13.0.0"
|
"serialport": "^13.0.0"
|
||||||
@@ -1171,6 +1171,27 @@
|
|||||||
],
|
],
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/binary-parser": {
|
||||||
|
"version": "1.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary-parser/-/binary-parser-1.1.5.tgz",
|
||||||
|
"integrity": "sha512-KsW0sfQ3e5Lpk8EVP44okdpOUhUlVaQ5HQ/qBKLpuMgEV29pTIfPvFobs9j4kp/4BqOSZ+kZpC7f4mleVonTRw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/binary-protocol": {
|
||||||
|
"version": "0.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/binary-protocol/-/binary-protocol-0.0.0.tgz",
|
||||||
|
"integrity": "sha512-kcFqbqtZnZEGSY8Jh6dEO6VbxJDZu1tqJc3LODqADPHrDwHQwoTNdGTHW4sLhmNXeWUOZKjfRfopAu5xpRQbPw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"bluebird": "~2.2.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/binary-protocol/node_modules/bluebird": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-NqzuS2y44FmP++Ihv6/PgXpNRB+c282TKq0URBTQdA+EqPpR1Qu44QY8H8667LA39iOIaVHpmRPI4gpthYT8Ug==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/bluebird": {
|
"node_modules/bluebird": {
|
||||||
"version": "3.7.2",
|
"version": "3.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
|
||||||
@@ -2595,6 +2616,15 @@
|
|||||||
"node": ">= 12"
|
"node": ">= 12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/ipaddr.js": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-ku//LD7ie/m9UVGCm9KweBIIHP4mB0maNGvav6Hz778fQCNLQF7iZ+H/UuHuqmjJCHCpA5hw8hOeRKxZl8IlXw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-fullwidth-code-point": {
|
"node_modules/is-fullwidth-code-point": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||||
@@ -2755,9 +2785,26 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/knx": {
|
"node_modules/knx": {
|
||||||
"version": "0.0.1",
|
"version": "2.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/knx/-/knx-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/knx/-/knx-2.5.4.tgz",
|
||||||
"integrity": "sha512-6AikhvtVK/U4CKL0/+vrLXsg8e/CNTUxmdKHgeLgWDObb/ggdr8BXeB7xmPjmnA+1ieDS6liFIkuHAPAlD0k9Q==",
|
"integrity": "sha512-h+WMbx2NPgCL1Vr4X8xAsTV9E+72XjPviKRv67iJLomapENO25ZsRGq8egvqUJwtnsordJGOxxUA4o1jMOzQYw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "^6.14.4",
|
||||||
|
"binary-parser": "1.1.5",
|
||||||
|
"binary-protocol": "0.0.0",
|
||||||
|
"ipaddr.js": "1.2.0",
|
||||||
|
"log-driver": "1.2.7",
|
||||||
|
"machina": "^4.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/knx/node_modules/@types/node": {
|
||||||
|
"version": "6.14.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.13.tgz",
|
||||||
|
"integrity": "sha512-J1F0XJ/9zxlZel5ZlbeSuHW2OpabrUAqpFuC2sm2I3by8sERQ8+KCjNKUcq8QHuzpGMWiJpo9ZxeHrqrP2KzQw==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/lazy-val": {
|
"node_modules/lazy-val": {
|
||||||
@@ -2771,9 +2818,17 @@
|
|||||||
"version": "4.18.1",
|
"version": "4.18.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz",
|
||||||
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
|
"integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==",
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/log-driver": {
|
||||||
|
"version": "1.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz",
|
||||||
|
"integrity": "sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg==",
|
||||||
|
"license": "ISC",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lowercase-keys": {
|
"node_modules/lowercase-keys": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz",
|
||||||
@@ -2797,6 +2852,17 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/machina": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/machina/-/machina-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-OOlFrW1rd783S6tF36v5Ie/TM64gfvSl9kYLWL2cPA31J71HHWW3XrgSe1BZSFAPkh8532CMJMLv/s9L2aopiA==",
|
||||||
|
"dependencies": {
|
||||||
|
"lodash": "^4.17.5"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/matcher": {
|
"node_modules/matcher": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz",
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "time4midi",
|
"name": "time4midi",
|
||||||
"version": "0.1.0",
|
"version": "0.2.0",
|
||||||
"description": "Cross-platform timeline editor for MIDI notes and Art-Net values, slaved to incoming timecode.",
|
"description": "Cross-platform timeline editor for MIDI notes and Art-Net values, slaved to incoming timecode.",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"author": "J.H. Artworks",
|
"author": "J.H. Artworks",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"electron-builder": "^26.15.3"
|
"electron-builder": "^26.15.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"knx": "^0.0.1",
|
"knx": "^2.5.4",
|
||||||
"modbus-serial": "^8.0.25",
|
"modbus-serial": "^8.0.25",
|
||||||
"mqtt": "^5.10.4",
|
"mqtt": "^5.10.4",
|
||||||
"serialport": "^13.0.0"
|
"serialport": "^13.0.0"
|
||||||
|
|||||||
+73
-8
@@ -4,10 +4,30 @@ const dgram = require("node:dgram");
|
|||||||
const fs = require("node:fs/promises");
|
const fs = require("node:fs/promises");
|
||||||
const os = require("node:os");
|
const os = require("node:os");
|
||||||
const { pathToFileURL } = require("node:url");
|
const { pathToFileURL } = require("node:url");
|
||||||
const mqtt = require("mqtt");
|
function loadOptionalDependency(packageName) {
|
||||||
const { SerialPort } = require("serialport");
|
try {
|
||||||
const ModbusRTU = require("modbus-serial");
|
return {
|
||||||
const knx = require("knx");
|
module: require(packageName),
|
||||||
|
error: null
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[time4midi] Optional dependency "${packageName}" failed to load:`, error);
|
||||||
|
return {
|
||||||
|
module: null,
|
||||||
|
error
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mqttDependency = loadOptionalDependency("mqtt");
|
||||||
|
const serialportDependency = loadOptionalDependency("serialport");
|
||||||
|
const modbusDependency = loadOptionalDependency("modbus-serial");
|
||||||
|
const knxDependency = loadOptionalDependency("knx");
|
||||||
|
|
||||||
|
const mqtt = mqttDependency.module;
|
||||||
|
const SerialPort = serialportDependency.module?.SerialPort || null;
|
||||||
|
const ModbusRTU = modbusDependency.module || null;
|
||||||
|
const knx = knxDependency.module || null;
|
||||||
|
|
||||||
const ARTNET_PORT = 6454;
|
const ARTNET_PORT = 6454;
|
||||||
const SACN_PORT = 5568;
|
const SACN_PORT = 5568;
|
||||||
@@ -34,6 +54,11 @@ function emitStatus(target, message) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function dependencyError(label, dependency) {
|
||||||
|
const detail = dependency.error?.message || "Modul nicht verfuegbar";
|
||||||
|
return new Error(`${label} Modul nicht verfuegbar: ${detail}`);
|
||||||
|
}
|
||||||
|
|
||||||
function addStatusApi(target, handler) {
|
function addStatusApi(target, handler) {
|
||||||
target.statusListeners.add(handler);
|
target.statusListeners.add(handler);
|
||||||
handler({
|
handler({
|
||||||
@@ -120,7 +145,7 @@ const serialState = {
|
|||||||
|
|
||||||
const modbusTcpState = {
|
const modbusTcpState = {
|
||||||
...createStatusEmitter(),
|
...createStatusEmitter(),
|
||||||
client: new ModbusRTU(),
|
client: null,
|
||||||
connected: false,
|
connected: false,
|
||||||
signature: "",
|
signature: "",
|
||||||
config: {
|
config: {
|
||||||
@@ -134,7 +159,7 @@ const modbusTcpState = {
|
|||||||
|
|
||||||
const modbusRtuState = {
|
const modbusRtuState = {
|
||||||
...createStatusEmitter(),
|
...createStatusEmitter(),
|
||||||
client: new ModbusRTU(),
|
client: null,
|
||||||
connected: false,
|
connected: false,
|
||||||
signature: "",
|
signature: "",
|
||||||
config: {
|
config: {
|
||||||
@@ -635,6 +660,11 @@ function configureMqtt(nextConfig) {
|
|||||||
return mqttState.config;
|
return mqttState.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mqtt) {
|
||||||
|
emitStatus(mqttState, dependencyError("MQTT", mqttDependency).message);
|
||||||
|
return mqttState.config;
|
||||||
|
}
|
||||||
|
|
||||||
const options = { reconnectPeriod: 1000 };
|
const options = { reconnectPeriod: 1000 };
|
||||||
if (mqttState.config.clientId) options.clientId = mqttState.config.clientId;
|
if (mqttState.config.clientId) options.clientId = mqttState.config.clientId;
|
||||||
if (mqttState.config.username) options.username = mqttState.config.username;
|
if (mqttState.config.username) options.username = mqttState.config.username;
|
||||||
@@ -705,11 +735,18 @@ function closeSerialPort() {
|
|||||||
async function configureSerial(nextConfig) {
|
async function configureSerial(nextConfig) {
|
||||||
serialState.config = normalizeSerialConfig(nextConfig);
|
serialState.config = normalizeSerialConfig(nextConfig);
|
||||||
await closeSerialPort();
|
await closeSerialPort();
|
||||||
|
if (serialState.config.enabled && !SerialPort) {
|
||||||
|
emitStatus(serialState, dependencyError("Serial", serialportDependency).message);
|
||||||
|
return serialState.config;
|
||||||
|
}
|
||||||
emitStatus(serialState, "");
|
emitStatus(serialState, "");
|
||||||
return serialState.config;
|
return serialState.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ensureSerialPortOpen() {
|
async function ensureSerialPortOpen() {
|
||||||
|
if (!SerialPort) {
|
||||||
|
throw dependencyError("Serial", serialportDependency);
|
||||||
|
}
|
||||||
if (!serialState.config.enabled) {
|
if (!serialState.config.enabled) {
|
||||||
throw new Error("Serial deaktiviert");
|
throw new Error("Serial deaktiviert");
|
||||||
}
|
}
|
||||||
@@ -768,6 +805,9 @@ async function sendSerial(payload) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function listSerialPorts() {
|
async function listSerialPorts() {
|
||||||
|
if (!SerialPort) {
|
||||||
|
throw dependencyError("Serial", serialportDependency);
|
||||||
|
}
|
||||||
const ports = await SerialPort.list();
|
const ports = await SerialPort.list();
|
||||||
return ports.map((port) => ({
|
return ports.map((port) => ({
|
||||||
path: port.path,
|
path: port.path,
|
||||||
@@ -799,9 +839,11 @@ async function listNetworkInterfaces() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function disconnectModbusClient(state) {
|
async function disconnectModbusClient(state) {
|
||||||
if (state.client?.isOpen) {
|
const client = state.client;
|
||||||
|
state.client = null;
|
||||||
|
if (client?.isOpen) {
|
||||||
try {
|
try {
|
||||||
await state.client.close();
|
await client.close();
|
||||||
} catch (_error) {
|
} catch (_error) {
|
||||||
// Best effort close.
|
// Best effort close.
|
||||||
}
|
}
|
||||||
@@ -813,6 +855,10 @@ async function disconnectModbusClient(state) {
|
|||||||
async function configureModbusTcp(nextConfig) {
|
async function configureModbusTcp(nextConfig) {
|
||||||
modbusTcpState.config = normalizeModbusTcpConfig(nextConfig);
|
modbusTcpState.config = normalizeModbusTcpConfig(nextConfig);
|
||||||
await disconnectModbusClient(modbusTcpState);
|
await disconnectModbusClient(modbusTcpState);
|
||||||
|
if (modbusTcpState.config.enabled && !ModbusRTU) {
|
||||||
|
emitStatus(modbusTcpState, dependencyError("Modbus TCP", modbusDependency).message);
|
||||||
|
return modbusTcpState.config;
|
||||||
|
}
|
||||||
emitStatus(modbusTcpState, "");
|
emitStatus(modbusTcpState, "");
|
||||||
return modbusTcpState.config;
|
return modbusTcpState.config;
|
||||||
}
|
}
|
||||||
@@ -820,11 +866,18 @@ async function configureModbusTcp(nextConfig) {
|
|||||||
async function configureModbusRtu(nextConfig) {
|
async function configureModbusRtu(nextConfig) {
|
||||||
modbusRtuState.config = normalizeModbusRtuConfig(nextConfig);
|
modbusRtuState.config = normalizeModbusRtuConfig(nextConfig);
|
||||||
await disconnectModbusClient(modbusRtuState);
|
await disconnectModbusClient(modbusRtuState);
|
||||||
|
if (modbusRtuState.config.enabled && !ModbusRTU) {
|
||||||
|
emitStatus(modbusRtuState, dependencyError("Modbus RTU", modbusDependency).message);
|
||||||
|
return modbusRtuState.config;
|
||||||
|
}
|
||||||
emitStatus(modbusRtuState, "");
|
emitStatus(modbusRtuState, "");
|
||||||
return modbusRtuState.config;
|
return modbusRtuState.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ensureModbusTcpConnected() {
|
async function ensureModbusTcpConnected() {
|
||||||
|
if (!ModbusRTU) {
|
||||||
|
throw dependencyError("Modbus TCP", modbusDependency);
|
||||||
|
}
|
||||||
if (!modbusTcpState.config.enabled) {
|
if (!modbusTcpState.config.enabled) {
|
||||||
throw new Error("Modbus TCP deaktiviert");
|
throw new Error("Modbus TCP deaktiviert");
|
||||||
}
|
}
|
||||||
@@ -833,6 +886,7 @@ async function ensureModbusTcpConnected() {
|
|||||||
return modbusTcpState.client;
|
return modbusTcpState.client;
|
||||||
}
|
}
|
||||||
await disconnectModbusClient(modbusTcpState);
|
await disconnectModbusClient(modbusTcpState);
|
||||||
|
modbusTcpState.client = new ModbusRTU();
|
||||||
await modbusTcpState.client.connectTCP(modbusTcpState.config.host, {
|
await modbusTcpState.client.connectTCP(modbusTcpState.config.host, {
|
||||||
port: modbusTcpState.config.port,
|
port: modbusTcpState.config.port,
|
||||||
timeout: modbusTcpState.config.timeout,
|
timeout: modbusTcpState.config.timeout,
|
||||||
@@ -846,6 +900,9 @@ async function ensureModbusTcpConnected() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function ensureModbusRtuConnected() {
|
async function ensureModbusRtuConnected() {
|
||||||
|
if (!ModbusRTU) {
|
||||||
|
throw dependencyError("Modbus RTU", modbusDependency);
|
||||||
|
}
|
||||||
if (!modbusRtuState.config.enabled) {
|
if (!modbusRtuState.config.enabled) {
|
||||||
throw new Error("Modbus RTU deaktiviert");
|
throw new Error("Modbus RTU deaktiviert");
|
||||||
}
|
}
|
||||||
@@ -857,6 +914,7 @@ async function ensureModbusRtuConnected() {
|
|||||||
return modbusRtuState.client;
|
return modbusRtuState.client;
|
||||||
}
|
}
|
||||||
await disconnectModbusClient(modbusRtuState);
|
await disconnectModbusClient(modbusRtuState);
|
||||||
|
modbusRtuState.client = new ModbusRTU();
|
||||||
await modbusRtuState.client.connectRTUBuffered(modbusRtuState.config.path, {
|
await modbusRtuState.client.connectRTUBuffered(modbusRtuState.config.path, {
|
||||||
baudRate: modbusRtuState.config.baudRate,
|
baudRate: modbusRtuState.config.baudRate,
|
||||||
parity: modbusRtuState.config.parity,
|
parity: modbusRtuState.config.parity,
|
||||||
@@ -929,11 +987,18 @@ function disconnectKnx() {
|
|||||||
async function configureKnx(nextConfig) {
|
async function configureKnx(nextConfig) {
|
||||||
knxState.config = normalizeKnxConfig(nextConfig);
|
knxState.config = normalizeKnxConfig(nextConfig);
|
||||||
await disconnectKnx();
|
await disconnectKnx();
|
||||||
|
if (knxState.config.enabled && !knx) {
|
||||||
|
emitStatus(knxState, dependencyError("KNX", knxDependency).message);
|
||||||
|
return knxState.config;
|
||||||
|
}
|
||||||
emitStatus(knxState, "");
|
emitStatus(knxState, "");
|
||||||
return knxState.config;
|
return knxState.config;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function ensureKnxConnection() {
|
async function ensureKnxConnection() {
|
||||||
|
if (!knx) {
|
||||||
|
throw dependencyError("KNX", knxDependency);
|
||||||
|
}
|
||||||
if (!knxState.config.enabled) {
|
if (!knxState.config.enabled) {
|
||||||
throw new Error("KNX deaktiviert");
|
throw new Error("KNX deaktiviert");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user