Skip to content

Commit 9905b8a

Browse files
committed
added startup ready check for each extension and server, fixed autopilot error in pattern matching, fixed incorrect byRef function return
1 parent 625a94f commit 9905b8a

File tree

44 files changed

+2743
-2708
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2743
-2708
lines changed

backend/data_center/modules/server_socket.js

Lines changed: 85 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,11 @@ const localConfig =
126126

127127
// callback to main server to save the updated server config
128128
saveServerConfigFunc: null,
129+
// startup extension check for readiness interval
130+
StartupIntervalHandle: null,
131+
StartupInterval: 200,
132+
StartupMaxTime: 100, //give extension 10seconds (StartupInterval*StartupMaxTime) to startup
133+
StartupMaxTimeCounter: 0,
129134
}
130135
const triggersandactions =
131136
{
@@ -240,6 +245,48 @@ const triggersandactions =
240245
}
241246
],
242247
}
248+
249+
250+
// check for extension status so we can send a message out when all have reported read
251+
/**
252+
* checks for extensions sending 'ready' message and send out a 'StreamRollerReady' when all extensions have responded
253+
*/
254+
function extensionReadinessCheckScheduler ()
255+
{
256+
clearTimeout(localConfig.StartupIntervalHandle)
257+
localConfig.StartupIntervalHandle = setInterval(() =>
258+
{
259+
extensionReadinessCheck()
260+
}, localConfig.StartupInterval);
261+
}
262+
/**
263+
* Extension readiness check
264+
*/
265+
function extensionReadinessCheck ()
266+
{
267+
let AllExtensionsReady = true; // negative check
268+
for (var key in localConfig.extensions)
269+
{
270+
if (localConfig.extensions[key].state != "ready")
271+
AllExtensionsReady = false;
272+
}
273+
//are we out of time or extensions finished loading
274+
if (localConfig.StartupMaxTimeCounter++ > localConfig.StartupMaxTime
275+
|| (AllExtensionsReady && localConfig.extensions != {} && localConfig.server_socket != null))
276+
{
277+
// list extensions that failed to load in time
278+
if (localConfig.StartupMaxTimeCounter++ > localConfig.StartupMaxTime)
279+
{
280+
for (var ext in localConfig.extensions)
281+
{
282+
if (localConfig.extensions[ext].state != "ready")
283+
console.log(`server startup time out for ${ext} `)
284+
}
285+
}
286+
mh.broadcastMessage(localConfig.server_socket, sr_api.ServerPacket("StreamRollerReady", localConfig.extensionname, {}))
287+
clearInterval(localConfig.StartupIntervalHandle)
288+
}
289+
}
243290
// ============================================================================
244291
// FUNCTION: start
245292
// ============================================================================
@@ -268,7 +315,15 @@ function start (app, server, exts, serverConfig, saveServerConfigFunc)
268315
// create our extension array
269316
exts.forEach((elem, i) =>
270317
{
271-
localConfig.extensions[elem] = {};
318+
// extensions without backend servers may not send a running message via the socket
319+
// and will set it via a function callback from the init function.
320+
// That will happen before we get here so we need to make sure we don't overwrite
321+
// the running flags for these extensions
322+
if (!localConfig.extensions[elem])
323+
{
324+
localConfig.extensions[elem] = {}
325+
localConfig.extensions[elem].state = "loading";
326+
}
272327
});
273328
localConfig.backend_server = server;
274329
cm.initcrypto();
@@ -317,6 +372,7 @@ function onConnect (socket)
317372
{
318373
socket.emit("connected", socket.id);
319374
socket.join(localConfig.channel);
375+
extensionReadinessCheckScheduler();
320376
sendAddressTrigger();
321377
}
322378
// ============================================================================
@@ -373,9 +429,14 @@ function onMessage (socket, server_packet)
373429
mh.errorMessage(socket, "Missing type/from field", server_packet);
374430
return;
375431
}
376-
// add this socket to the extension if it doesn't already exist
432+
// add this socket to the extension list if it doesn't already exist
433+
// these will be extension not started by the server
377434
if (typeof (localConfig.extensions[server_packet.from]) === "undefined" || !localConfig.extensions[server_packet.from])
435+
{
378436
localConfig.extensions[server_packet.from] = {};
437+
// added new extension so restart the check
438+
extensionReadinessCheckScheduler();
439+
}
379440
// check we have a valid socket for this extension, don't need to check if the extension exists as it will have been added above
380441
if (typeof (localConfig.extensions[server_packet.from].socket) === "undefined" || !localConfig.extensions[server_packet.from].socket)
381442
{
@@ -388,7 +449,7 @@ function onMessage (socket, server_packet)
388449
else
389450
{
390451
// note that we currently only have one slot per connection. this works for extensions that are only loaded once
391-
// but for webpage stuff we will need to allow more than one sockect for that extension name
452+
// but for webpage stuff we will need to allow more than one socket for that extension name
392453
// we need to append the socket id to the extension name to fix this!!!
393454
if (localConfig.extensions[server_packet.from].socket.id != socket.id)
394455
{
@@ -403,7 +464,11 @@ function onMessage (socket, server_packet)
403464
localConfig.connected_extensionlist[server_packet.from] = localConfig.extensions[server_packet.from].socket.connected
404465
}
405466
// process the clients request
406-
if (server_packet.type === "RequestSoftwareVersion")
467+
if (server_packet.type === "ExtensionConnected")
468+
localConfig.extensions[server_packet.from] = { state: "connected" };
469+
else if (server_packet.type === "ExtensionReady")
470+
localConfig.extensions[server_packet.from] = { state: "ready" };
471+
else if (server_packet.type === "RequestSoftwareVersion")
407472
mh.sendSoftwareVersion(socket, server_packet.from);
408473
else if (server_packet.type === "RequestConfig")
409474
mh.sendConfig(socket, server_packet.from);
@@ -771,7 +836,7 @@ function dataMonitorScheduler ()
771836
// FUNCTION: sendAddressTrigger
772837
// ============================================================================
773838
/**
774-
* Finds the trigger using the passed messagetype
839+
* sends "trigger_StreamRollerIPChanged" message
775840
* @returns trigger
776841
*/
777842
function sendAddressTrigger ()
@@ -815,7 +880,7 @@ function findTriggerByMessageType (messagetype)
815880
for (let i = 0; i < triggersandactions.triggers.length; i++)
816881
{
817882
if (triggersandactions.triggers[i].messagetype.toLowerCase() == messagetype.toLowerCase())
818-
return triggersandactions.triggers[i];
883+
return structuredClone(triggersandactions.triggers[i]);
819884
}
820885
logger.err(localConfig.SYSTEM_LOGGING_TAG + localConfig.extensionname +
821886
".findTriggerByMessageType", "failed to find trigger", messagetype);
@@ -845,8 +910,21 @@ function sendTrigger (data)
845910
)
846911
);
847912
}
913+
/**
914+
* Used by locally started extensions that have client webpages with the socket connection
915+
* these might not always be loading in a browser so we fake the ready flag on startup.
916+
* @param {string} ext
917+
*/
918+
function readyMessage (ext)
919+
{
920+
if (!localConfig.extensions[ext])
921+
{
922+
localConfig.extensions[ext] = {}
923+
localConfig.extensions[ext].state = "ready"
924+
}
925+
}
848926
// ============================================================================
849927
// EXPORTS:
850928
// ============================================================================
851-
export { start, triggersandactions };
929+
export { start, triggersandactions, readyMessage };
852930

backend/data_center/server.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ import * as logger from "./modules/logger.js";
4444
import * as ServerSocket from "./modules/server_socket.js";
4545
import sr_api from "./public/streamroller-message-api.cjs";
4646

47+
/*
48+
process.on('unhandledRejection', (reason, promise) =>
49+
{
50+
console.log('Unhandled Promise Rejection:');
51+
console.log('Reason:', reason);
52+
console.log('Stack Trace:', reason?.stack || 'No stack trace available');
53+
});
54+
*/
4755
// testing startup time
4856
let DEBUG_TIMING = false;
4957
let debugStartTime = performance.now()
@@ -313,6 +321,10 @@ async function loadExtensions (extensionFolder)
313321
);
314322
return x;
315323
})
324+
.catch((err) =>
325+
{
326+
console.log("error loading module", err)
327+
})
316328
return x;
317329
}
318330
else
@@ -345,7 +357,8 @@ async function loadExtensions (extensionFolder)
345357
app, "http://" + serverConfig.HOST,
346358
serverConfig.PORT,
347359
// add a slight offset to the heartbeat so they don't all end up synced
348-
serverConfig.heartbeat + (Math.floor(Math.random() * 100)));
360+
serverConfig.heartbeat + (Math.floor(Math.random() * 100)),
361+
ServerSocket.readyMessage);
349362
else
350363
logger.err("[" + serverConfig.SYSTEM_LOGGING_TAG + "]server.js", "Error: Extension module " + files[index] + " did not export an initialise function");
351364
if (DEBUG_TIMING)

extensions/autopilot/autopilot.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ import * as server from "./server/server.js"
5151
* @param {number} port
5252
* @param {number} heartbeat
5353
*/
54-
function initialise (app, host, port, heartbeat)
54+
function initialise (app, host, port, heartbeat, readyMessagefn)
5555
{
5656
config.heartBeatTimeout = heartbeat;
5757
app.use("/autopilot/", express.static(__dirname + "/public"));
@@ -72,6 +72,7 @@ function initialise (app, host, port, heartbeat)
7272
}
7373
);
7474
});
75+
readyMessagefn(config.EXTENSION_NAME)
7576
} catch (err)
7677
{
7778
logger.err(config.SYSTEM_LOGGING_TAG + config.EXTENSION_NAME + ".initialise", "initialise failed:", err);

extensions/autopilot/server/server.js

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -177,9 +177,7 @@ function onDataCenterConnect (socket)
177177
*/
178178
function onDataCenterMessage (server_packet)
179179
{
180-
// -------------------------------------------------------------------------------------------------
181-
// RECEIVED CONFIG
182-
// -------------------------------------------------------------------------------------------------
180+
183181
if (server_packet.type === "ConfigFile")
184182
{
185183
// check it is our config
@@ -587,54 +585,63 @@ function ProcessReceivedTrigger (pairing, receivedTrigger)
587585
let match = true
588586
// we have the correct extension, channel and message type
589587
// lets check the variables to see if those are a match
588+
589+
// this just covers { MATCHER_sender: '1', sender: '' } part of teh parameter.
590590
pairing.trigger.data.forEach((param) =>
591591
{
592592
for (var i in param)
593593
{
594+
let receivedParam = ""
595+
if (typeof receivedTrigger.data.parameters[i] !== "undefined" && receivedTrigger.data.parameters[i] !== null)
596+
receivedParam = receivedTrigger.data.parameters[i].toString().toLowerCase()
597+
let checkParam = ""
598+
if (typeof param[i] !== "undefined" && param[i] !== null)
599+
checkParam = param[i].toString().toLowerCase()
594600
try
595601
{
596602
// don't check the MATCHER variables as these are used to determine how to perform the match (Start of line etc)
597603
if (i.indexOf("MATCHER_") != 0 && i != "cooldown" && i != "lastrun")
598604
{
599605
// get the relevant matcher for this value
600606
let searchtype = param["MATCHER_" + i]
601-
if (typeof (receivedTrigger.data.parameters[i]) == "string")// && typeof param[i] === "string")
607+
608+
if (receivedParam)// && typeof checkParam === "string")
602609
{
603610
switch (searchtype)
604611
{
605612
case "2"://match anywhere
606-
if (param[i] != "" && receivedTrigger.data.parameters[i].toLowerCase().indexOf(param[i].toLowerCase()) == -1)
613+
if (checkParam != "" && receivedParam.indexOf(checkParam) == -1)
607614
match = false;
608615
break;
609616
case "3"://match start of line only
610-
if (param[i] != "" && receivedTrigger.data.parameters[i].toLowerCase().indexOf(param[i].toLowerCase()) != 0)
617+
if (checkParam != "" && receivedParam.indexOf(checkParam) != 0)
611618
match = false;
612619
break;
613620
case "4"://doesn't match
614-
if (param[i] != "" && receivedTrigger.data.parameters[i].toLowerCase().indexOf(param[i].toLowerCase()) == 0)
621+
if (checkParam != "" && receivedParam.indexOf(checkParam) == 0)
615622
match = false;
616623
break;
617624
case "5"://match complete word only
618-
if (param[i] != "" && receivedTrigger.data.parameters[i].toLowerCase().indexOf(param[i].toLowerCase()) == -1)
625+
if (checkParam != "" && receivedParam.indexOf(checkParam) == -1)
619626
{
620627
match = false;
621628
}
622629
else
623630
{
624-
let wordArray = receivedTrigger.data.parameters[i].split(" ")
631+
let wordArray = receivedParam.split(" ")
625632
match = false;
626-
if (wordArray.includes(param[i]))
633+
if (wordArray.includes(checkParam))
627634
match = true;
628635
}
629636
break;
630637
default:
631638
// check for exact match
632-
if (param[i] != "" && receivedTrigger.data.parameters[i].toLowerCase() != param[i].toLowerCase())
639+
if (checkParam != "" && receivedParam != checkParam)
633640
match = false;
634641
}
635642
}
636643
//check non string types for not matching
637-
else if (param[i] != "" && receivedTrigger.data.parameters[i] != param[i])
644+
else if (checkParam != "" && receivedParam != checkParam)
638645
match = false;
639646
}
640647
}
@@ -738,7 +745,7 @@ function TriggerAction (action, triggerParams)
738745
// remove the first number of words the user specified
739746
for (var x = 0; x < wordNumber; x++)
740747
sourceArray.splice(0, 1)
741-
tempAction = sourceArray.join(" ").trim()
748+
tempAction = tempAction.replace("%%" + sourceVar + "%%", sourceArray.join(" ").trim())
742749
}
743750
else
744751
{
@@ -747,7 +754,7 @@ function TriggerAction (action, triggerParams)
747754
sourceData.replaceAll("%%", "")
748755
// split the data into an array so we can index the work the user wants
749756
const sourceArray = sourceData.split(" ");
750-
tempAction = sourceArray[wordNumber]
757+
tempAction = tempAction.replace("%%" + sourceVar + "%%", sourceArray[wordNumber])
751758
}
752759
}
753760
else

0 commit comments

Comments
 (0)