Initial commit

This commit is contained in:
Marcelo
2025-11-20 15:27:34 -06:00
commit cc72c9fc5d
3221 changed files with 737477 additions and 0 deletions

121
node_modules/node-red-node-ping/88-ping.html generated vendored Normal file
View File

@@ -0,0 +1,121 @@
<script type="text/html" data-template-name="ping">
<div class="form-row" id="div-node-input-host">
<label for="node-input-host"><i class="fa fa-dot-circle-o"></i> <span data-i18n="ping.label.target"></span></label>
<input type="text" id="node-input-host" placeholder="192.168.0.1, www.google.com">
</div>
<div class="form-row">
<label for="node-protocol"><i class="fa fa-gear"></i> <span data-i18n="ping.label.protocol"></label>
<select type="text" id="node-input-protocol" style="width: 70%">
<option value="Automatic" data-i18n="ping.label.protocol_option.auto"></option>
<option value="IPv4" data-i18n="ping.label.protocol_option.ipv4"></option>
<option value="IPv6" data-i18n="ping.label.protocol_option.ipv6"></option>
</select>
</div>
<div class="form-row">
<label for="node-input-mode"><i class="fa fa-wrench"></i> <span data-i18n="ping.label.mode"></label>
<select type="text" id="node-input-mode" style="width: 70%">
<option value="timed" data-i18n="ping.label.mode_option.timed"></option>
<option value="triggered" data-i18n="ping.label.mode_option.triggered"></option>
</select>
</div>
<div class="form-row" id="div-node-input-timer">
<label for="node-input-timer"><i class="fa fa-repeat"></i> <span data-i18n="ping.label.ping"></label>
<input type="text" id="node-input-timer" placeholder="20">
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="node-red:common.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]node-red:common.label.name">
</div>
<div class="form-tips" id="node-ping-tip"><span data-i18n="ping.label.tip"></span></div>
</script>
<script type="text/javascript">
var timerParameterValidator = function(node,v){
var mode = getMode(node)
if(mode === "triggered"){
return true;
}
if(v == ""){
return false;
}
return RED.validators.number()(v);
}
var hostParameterValidator = function(node,v){
var mode = getMode(node)
if(mode === "triggered"){
return true;
}
return v != ""
}
var getMode = function(node){
if(node){
return node.mode
} else {
let $mode = $( "#node-input-mode" );
return $mode.val();
}
}
RED.nodes.registerType("ping",{
category: "network-input",
color:"#fdf0c2",
defaults: {
protocol: {value:"Automatic"},
mode: {value:"timed"},
name: {value:""},
host: {value:"", validate: function(v){
return hostParameterValidator(this,v) ;
}
},
timer: {value:"20", validate: function(v){
return timerParameterValidator(this,v) ;
}
},
inputs: {value:0}
},
inputs:0,
outputs:1,
icon: "alert.png",
paletteLabel: function() {
return this._("ping.ping");
},
label: function() {
let lbl = this.name||this.host||this._("ping.ping");
if (lbl.split(',').length > 1){
lbl = this._("ping.ping");
}
return lbl;
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function () {
let node = this;
let $timer = $("#div-node-input-timer");
let $tip = $("#node-ping-tip");
$("#node-input-mode").val(node.mode);
let $mode = $( "#node-input-mode" );
function updateControlsVisibility(){
node.mode = $mode.val();
switch (node.mode) {
case "triggered":
node.inputs = 1;
node._def.inputs = 1
$timer.hide();
$tip.show();
break;
default:
node.inputs = 0;
node._def.inputs = 0;
$timer.show();
$tip.hide();
break;
}
}
$mode.change(updateControlsVisibility);
updateControlsVisibility();
}
});
</script>

253
node_modules/node-red-node-ping/88-ping.js generated vendored Normal file
View File

@@ -0,0 +1,253 @@
module.exports = function(RED) {
"use strict";
var spawn = require("child_process").spawn;
var plat = require("os").platform();
function doPing(node, host, msg, arrayMode) {
const defTimeout = 5000;
var ex, ex6, hostOptions, commandLineOptions;
if (typeof host === "string") {
hostOptions = {
host: host,
timeout: defTimeout
}
} else {
hostOptions = host;
hostOptions.timeout = isNaN(parseInt(hostOptions.timeout)) ? defTimeout : parseInt(hostOptions.timeout);
}
//clamp timeout between 1 and 30 sec
hostOptions.timeout = hostOptions.timeout < 1000 ? 1000 : hostOptions.timeout;
hostOptions.timeout = hostOptions.timeout > 30000 ? 30000 : hostOptions.timeout;
var timeoutS = Math.round(hostOptions.timeout / 1000); //whole numbers only
msg.payload = false;
msg.topic = hostOptions.host;
//only include the extra msg object if operating in advance/array mode.
if (arrayMode) {
msg.ping = hostOptions
}
var cmd = "ping";
//User Selected Protocol
if (plat == "linux" || plat == "android") {
if (node.protocol === "IPv4") {
commandLineOptions = ["-n", "-4", "-w", timeoutS, "-c", "1"]; //IPv4
} else if (node.protocol === "IPv6") {
commandLineOptions = ["-n", "-6", "-w", timeoutS, "-c", "1"]; //IPv6
} else {
commandLineOptions = ["-n", "-w", timeoutS, "-c", "1"]; //Automatic
}
} else if (plat.match(/^win/)) {
if (node.protocol === "IPv4") {
commandLineOptions = ["-n", "1", "-4", "-w", hostOptions.timeout]; //IPv4
} else if (node.protocol === "IPv6") {
commandLineOptions = ["-n", "1", "-6", "-w", hostOptions.timeout]; //IPv6
} else {
commandLineOptions = ["-n", "1", "-w", hostOptions.timeout]; //Automatic
}
} else if (plat == "darwin" || plat == "freebsd") {
if (node.protocol === "IPv4") {
commandLineOptions = ["-n", "-t", timeoutS, "-c", "1"]; //IPv4
} else if (node.protocol === "IPv6") {
cmd = "ping6";
commandLineOptions = ["-n", "-t", timeoutS, "-c", "1"]; //IPv6
} else {
commandLineOptions = ["-n", "-t", timeoutS, "-c", "1"]; //Automatic
}
} else {
node.error("Sorry - your platform - "+plat+" - is not recognised.", msg);
return; //dont pass go - just return!
}
//spawn with timeout in case of os issue
ex = spawn(cmd, [...commandLineOptions, hostOptions.host]);
//monitor every spawned process & SIGINT if too long
var spawnTout = setTimeout(() => {
node.log(`ping - Host '${hostOptions.host}' process timeout - sending SIGINT`)
try {
if (ex && ex.pid) { ex.kill("SIGINT"); }
}
catch(e) {console.warn(e); }
}, hostOptions.timeout+1000); //add 1s for grace
var res = false;
var line = "";
var fail = false;
//var regex = /from.*time.(.*)ms/;
var regex = /=.*[<|=]([0-9]*).*TTL|ttl..*=([0-9\.]*)/;
var tryPing6 = false;
//catch error msg from ping
ex.stderr.setEncoding('utf8');
ex.stderr.on("data", function (data) {
if (!data.includes('Usage')) { // !data: only get the error and not how to use the ping command
if (data.includes('invalid') && data.includes('6')) { //if IPv6 not supported in version of ping try ping6
tryPing6 = true;
}
else if (data.includes('Network is unreachable')) {
node.status({shape:"ring",fill:"red"});
node.error(data + " Please check that your service provider or network device has IPv6 enabled", msg);
node.hadErr = true;
}
else {
node.status({shape:"ring",fill:"grey"});
node.hadErr = true;
}
}
});
ex.stdout.on("data", function (data) {
line += data.toString();
});
ex.on("exit", function (err) {
clearTimeout(spawnTout);
});
ex.on("error", function (err) {
fail = true;
if (err.code === "ENOENT") {
node.error(err.code + " ping command not found", msg);
}
else if (err.code === "EACCES") {
node.error(err.code + " can't run ping command", msg);
}
else {
node.error(err.code, msg);
}
});
ex.on("close", function (code) {
if (tryPing6 === false) {
if (fail) { fail = false; return; }
var m = regex.exec(line)||"";
if (m !== "") {
if (m[1]) { res = Number(m[1]); }
if (m[2]) { res = Number(m[2]); }
}
if (code === 0) { msg.payload = res }
try { node.send(msg); }
catch(e) {console.warn(e)}
}
else {
//fallback to ping6 for OS's that have not updated/out of date
if (plat == "linux" || plat == "android") {
commandLineOptions = ["-n", "-w", timeoutS, "-c", "1"];
} else if (plat == "darwin" || plat == "freebsd") {
commandLineOptions = ["-n", "-c", "1"] //NOTE: -X / timeout does not work on mac OSX and most freebsd systems
} else {
node.error("Sorry IPv6 on your platform - "+plat+" - is not supported.", msg);
}
//spawn with timeout in case of os issue
ex6 = spawn("ping6", [...commandLineOptions, hostOptions.host]);
//monitor every spawned process & SIGINT if too long
var spawnTout = setTimeout(() => {
node.log(`ping6 - Host '${hostOptions.host}' process timeout - sending SIGINT`)
try {
if (ex6 && ex6.pid) { ex6.kill("SIGINT"); }
}
catch(e) {console.warn(e); }
}, hostOptions.timeout+1000); //add 1s for grace
//catch error msg from ping6
ex6.stderr.setEncoding('utf8');
ex6.stderr.on("data", function (data) {
if (!data.includes('Usage')) { // !data: only get the error and not how to use the ping6 command
if (data.includes('Network is unreachable')) {
node.error(data + " Please check that your service provider or network device has IPv6 enabled", msg);
node.status({shape:"ring",fill:"red"});
}
else {
node.status({shape:"ring",fill:"grey"});
}
node.hadErr = true;
}
});
ex6.stdout.on("data", function (data) {
line += data.toString();
});
ex6.on("exit", function (err) {
clearTimeout(spawnTout);
});
ex6.on("error", function (err) {
fail = true;
if (err.code === "ENOENT") {
node.error(err.code + " ping6 command not found", msg);
}
else if (err.code === "EACCES") {
node.error(err.code + " can't run ping6 command", msg);
}
else {
node.error(err.code, msg);
}
});
ex6.on("close", function (code) {
if (fail) { fail = false; return; }
var m = regex.exec(line)||"";
if (m !== "") {
if (m[1]) { res = Number(m[1]); }
if (m[2]) { res = Number(m[2]); }
}
if (code === 0) { msg.payload = res }
try { node.send(msg); }
catch(e) {console.warn(e)}
});
}
});
}
function PingNode(n) {
RED.nodes.createNode(this,n);
this.protocol = n.protocol||'Automatic';
this.mode = n.mode;
this.host = n.host;
this.timer = n.timer * 1000;
this.hadErr = false;
var node = this;
function generatePingList(str) {
return (str + "").split(",").map((e) => (e + "").trim()).filter((e) => e != "");
}
function clearPingInterval() {
if (node.tout) { clearInterval(node.tout); }
}
if (node.mode === "triggered") {
clearPingInterval();
} else if (node.timer) {
node.tout = setInterval(function() {
if (node.hadErr) { node.hadErr = false; node.status({}); }
let pingables = generatePingList(node.host);
for (let index = 0; index < pingables.length; index++) {
const element = pingables[index];
if (element) { doPing(node, element, {}, false); }
}
}, node.timer);
}
this.on("input", function (msg) {
let node = this;
if (node.hadErr) { node.hadErr = false; node.status({}); }
let payload = node.host || msg.payload;
if (typeof payload == "string") {
let pingables = generatePingList(payload)
for (let index = 0; index < pingables.length; index++) {
const element = pingables[index];
if (element) { doPing(node, element, RED.util.cloneMessage(msg), false); }
}
} else if (Array.isArray(payload) ) {
for (let index = 0; index < payload.length; index++) {
const element = payload[index];
if (element) { doPing(node, element, RED.util.cloneMessage(msg), true); }
}
}
});
this.on("close", function() {
clearPingInterval();
});
}
RED.nodes.registerType("ping",PingNode);
}

14
node_modules/node-red-node-ping/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,14 @@
Copyright 2016-2019 JS Foundation and other contributors, https://js.foundation/
Copyright 2013-2016 IBM Corp.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

43
node_modules/node-red-node-ping/README.md generated vendored Normal file
View File

@@ -0,0 +1,43 @@
node-red-node-ping
==================
A <a href="http://nodered.org" target="_new">Node-RED</a> node to ping a
remote server, for use as a keep-alive check.
Install
-------
Either use the Editor - Menu - Manage Palette - Import option or run the following command in your Node-RED user directory - typically `~/.node-red`
npm install node-red-node-ping
**Gotchas**
1 Ubuntu Snap containers are strict and do not like giving external commands (like ping) external access. To allow ping to work you must manually add the network-observe interface
sudo snap connect node-red:network-observe
2 On some versions on Raspbian (Raspberry Pi) `ping` seems to be a root only command.
The fix is to allow it as follows
sudo setcap cap_net_raw=ep /bin/ping
sudo setcap cap_net_raw=ep /bin/ping6
Usage
-----
Pings 1 or more devices and returns the trip time in mS as `msg.payload`.
Returns boolean `false` if no response received, or if the host is unresolveable.
`msg.error` will contain any error message if necessary.
`msg.topic` contains the ip address of the target host.
There are 2 modes - `Timed` and `Triggered`.
* Timed mode - this is the default mode that pings your devices on a timed basis. Default ping is every 20 seconds but can be configured.
* Triggered mode - this mode permits you to trigger the ping by an input message. If the `Target` is left blank and `msg.payload` is a string or array, you can ping 1 or more devices on demand.
Refer to the built in help on the side-bar info panel for more details.

View File

@@ -0,0 +1,15 @@
{
"ping": {
"ping": "ping",
"label": {
"target": "Ziel",
"ping": "Ping (S)",
"mode": "Modus",
"mode_option": {
"timed": "Zeitgesteuert",
"triggered": "Getriggert"
},
"tip": "Hinweis: Ziel-Eintrag leer lassen, damit über msg.payload der Hosts dynamisch gesetzt werden kann"
}
}
}

View File

@@ -0,0 +1,69 @@
<script type="text/html" data-help-name="ping">
<p>Pings a machine and returns the trip time in mS as <code>msg.payload</code>.</p>
<h3>Output</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">number</span></dt>
<dd> the trip time in mS, or boolean <i>false</i> if no response.</dd>
<dt>topic <span class="property-type">string</span></dt>
<dd> the target host or ip address.</dd>
<dt>[ping] <span class="property-type">object</span></dt>
<dd> an object containing <code>host</code> and any other properties sent in the array object.<br>
<b>Note</b>: This object is only appended when using triggered mode and an array for input payload. It is
intended for advanced users and permits scenarios where you need additional properties to be tagged into your result for use downstream.</dd>
</dl>
<h3>Details</h3>
<p>Returns <b>false</b> if no response received, or if the host is unresolveable.</p>
<p>Default ping is every 20 seconds but can be configured.</p>
<h4>Protocol...</h4>
<ul>
<li><b>Automatic</b><br>
<P>Will use any Protocol, IPv4 or IPv6, to reach host; based on your operating system network settings</P>
</li>
<li><b>IPv4</b><br>
<P>Forces use of IPv4 to reach host. Will fail if no route availibe</P>
</li>
<li><b>IPv6</b><br>
<P>Forces use of IPv6 to reach host. Will fail if no route availibe</P>
</li>
</ul>
<h4>Mode...</h4>
<ul>
<li><b>Timed</b><br>
<P>In Timed mode, the fields <code>Target</code> and <code>Ping (S)</code> must be populated.</P>
<p>Target must be a CSV list of hosts / IPs e.g. <code>"192.168.0.1"</code> or <code>"192.168.0.1, www.google.com"</code></p>
<p>Ping (S) is the number of seconds between pings</p>
</li>
<li><b>Triggered</b><br>
<p>In Triggered mode, you must connect an input wire and pass a <code>msg</code> in to trigger the ping operation.</p>
<p>If <code>Target</code> is populated, this will be used as the host/ip. The Target must be is a CSV list of
hosts / IPs e.g. <code>"192.168.0.1"</code> or <code>"192.168.0.1, www.google.com"</code></p>
<p>If Target is left empty, you can pass a CSV string or an array of hosts in <code>msg.payload</code>.
<ul>
<li><b>string</b> - a CSV list of hosts / IPs e.g. <code>"192.168.0.1"</code> or <code>"192.168.0.1, www.google.com"</code> </li>
<li><b>array</b> - an array of hosts as strings or objects. <b>Note</b>: The object must contain at minimum <code>.host</code>.
Optionally, you can add a <code>timeout</code> property between 1000 & 30000 (default is 5000 / 5 seconds).
Additionally, you can add whatever other properties you wish to this object and when the ping result is returned, it will
be passed to the next node in <code>msg.ping</code> for use downstream</li>
<li>Example array payload input: <pre>[
"192.168.0.99",
{
"host":"192.168.0.1",
"name":"The router"
},
{
"host":"myapiserver.com",
"name":"external API",
"timeout": 20000,
"support":"support@myapiserver.com"
}
]</pre> </li>
</ul>
</p>
</li>
</ul>
<p><b>Note</b>: if running inside Ubuntu Snap you will need to manually start the network-observe interface.
<code>snap connect node-red:network-observe</code>.</p>
</script>

View File

@@ -0,0 +1,21 @@
{
"ping": {
"ping": "ping",
"label": {
"target": "Target",
"ping": "Ping (S)",
"mode": "Mode",
"mode_option": {
"timed": "Timed",
"triggered": "Triggered"
},
"protocol": "Protocol",
"protocol_option": {
"auto": "Automatic",
"ipv4": "IPv4",
"ipv6": "IPv6"
},
"tip": "Note: Leave Target field blank to allow msg.payload to set hosts dynamically."
}
}
}

View File

@@ -0,0 +1,66 @@
<script type="text/html" data-help-name="ping">
<p>pingを送信し<code>msg.payload</code></p>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload <span class="property-type">数値</span></dt>
<dd> ミリ秒で表したトリップタイムレスポンスが無い場合ブール値<i>false</i></dd>
<dt>topic <span class="property-type">文字列</span></dt>
<dd> ターゲットホスト名もしくはIPアドレス</dd>
<dt>[ping] <span class="property-type">オブジェクト</span></dt>
<dd>要素が<code>host</code> <br>
<b></b>: </dd>
</dl>
<h3>詳細</h3>
<p>ホスト名が解決できなかったりレスポンスが得られなければ<b>false</b></p>
<p>デフォルトでは20秒ごとにpingを送りますが設定で変更できます</p>
<h4>Protocol...</h4>
<ul>
<li><b>Automatic</b><br>
<P>Will use any Protocol, IPv4 or IPv6, to reach host; based on your operating system network settings</P>
</li>
<li><b>IPv4</b><br>
<P>Forces use of IPv4 to reach host. Will fail if no route availibe</P>
</li>
<li><b>IPv6</b><br>
<P>Forces use of IPv6 to reach host. Will fail if no route availibe</P>
</li>
</ul>
<h4>モード...</h4>
<ul>
<li><b>時間</b><br>
<P><code>時間</code><code>Target</code><code>Ping()</code></P>
<p><code>ターゲット</code>/IP: <code>"192.168.0.1"</code> <code>"192.168.0.1, www.google.com"</code></p>
<p><code>Ping()</code>ping</p>
</li>
<li><b>トリガー</b><br>
<p><code>トリガー</code><code>msg</code>ping
<p><code>ターゲット</code>IP使 /IP: <code>"192.168.0.1"</code> <code>"192.168.0.1, www.google.com"</code></p>
<p><code>ターゲット</code><code>msg.payload</code>
<ul>
<li><code>文字列</code> - /IP : <code>"192.168.0.1"</code> <code>"192.168.0.1, www.google.com"</code> </li>
<li><code>配列</code> - : <code>.host</code><code>timeout</code> 100030000(5000/5) ping<code>msg.ping</code></li>
<li>配列ペイロードの例: <pre>[
"192.168.0.99",
{
"host":"192.168.0.1",
"name":"ルータ"
},
{
"host":"myapiserver.com",
"name":"拡張API",
"timeout": 20000,
"support":"support@myapiserver.com"
}
]</pre> </li>
</ul>
</p>
</li>
</ul>
<p><b>補足</b>: Ubuntu Snapnetwork-observe
<code>snap connect node-red:network-observe</code></p>
</script>

View File

@@ -0,0 +1,21 @@
{
"ping": {
"ping": "ping",
"label": {
"target": "ターゲット",
"ping": "Ping (秒)",
"mode": "モード",
"mode_option": {
"timed": "時間",
"triggered": "トリガー"
},
"protocol": "プロトコル",
"protocol_option": {
"auto": "自動の",
"ipv4": "IPv4",
"ipv6": "IPv6"
},
"tip": "注: msg.payloadでホスト名を動的に指定する場合は、ターゲットフィールドを空にします。"
}
}
}

27
node_modules/node-red-node-ping/package.json generated vendored Normal file
View File

@@ -0,0 +1,27 @@
{
"name" : "node-red-node-ping",
"version" : "0.3.3",
"description" : "A Node-RED node to ping a remote server, for use as a keep-alive check.",
"dependencies" : {
},
"repository" : {
"type":"git",
"url":"https://github.com/node-red/node-red-nodes.git",
"directory": "tree/master/io/ping"
},
"license": "Apache-2.0",
"keywords": [ "node-red", "ping", "keepalive" ],
"node-red" : {
"nodes" : {
"ping": "88-ping.js"
}
},
"author": {
"name": "Dave Conway-Jones",
"email": "ceejay@vnet.ibm.com",
"url": "http://nodered.org"
},
"contributors": [
{ "name": "@Steve-Mcl" }
]
}