merge and refactor error handling in nodes

This commit is contained in:
Andreas Martens
2021-01-29 16:09:17 +00:00
68 changed files with 1629 additions and 676 deletions

View File

@@ -94,6 +94,8 @@ module.exports = function(RED) {
sendopts.inReplyTo = msg.inReplyTo;
sendopts.replyTo = msg.replyTo;
sendopts.references = msg.references;
sendopts.headers = msg.headers;
sendopts.priority = msg.priority;
}
sendopts.subject = msg.topic || msg.title || "Message from Node-RED"; // subject line
if (msg.hasOwnProperty("envelope")) { sendopts.envelope = msg.envelope; }
@@ -118,7 +120,18 @@ module.exports = function(RED) {
var payload = RED.util.ensureString(msg.payload);
sendopts.text = payload; // plaintext body
if (/<[a-z][\s\S]*>/i.test(payload)) { sendopts.html = payload; } // html body
if (msg.attachments) { sendopts.attachments = msg.attachments; } // add attachments
if (msg.attachments && Array.isArray(msg.attachments)) {
sendopts.attachments = msg.attachments;
for (var a=0; a < sendopts.attachments.length; a++) {
if (sendopts.attachments[a].hasOwnProperty("content")) {
if (typeof sendopts.attachments[a].content !== "string" && !Buffer.isBuffer(sendopts.attachments[a].content)) {
node.error(RED._("email.errors.invalidattachment"),msg);
node.status({fill:"red",shape:"ring",text:"email.status.sendfail"});
return;
}
}
}
}
}
smtpTransport.sendMail(sendopts, function(error, info) {
if (error) {

View File

@@ -2,7 +2,8 @@
<p>Sends the <code>msg.payload</code> as an email, with a subject of <code>msg.topic</code>.</p>
<p>The default message recipient can be configured in the node, if it is left
blank it should be set using the <code>msg.to</code> property of the incoming message. If left blank
you can also specify any or all of: <code>msg.cc</code>, <code>msg.bcc</code>, <code>msg.replyTo</code>, <code>msg.inReplyTo</code>, <code>msg.references</code> properties.</p>
you can also specify any or all of: <code>msg.cc</code>, <code>msg.bcc</code>, <code>msg.replyTo</code>,
<code>msg.inReplyTo</code>, <code>msg.references</code>, <code>msg.headers</code>, or <code>msg.priority</code> properties.</p>
<p>You may optionally set <code>msg.from</code> in the payload which will override the <code>userid</code>
default value.</p>
<h3>GMail users</h3>

View File

@@ -60,7 +60,8 @@
"fetchfail": "Failed to fetch folder: __folder__",
"parsefail": "Failed to parse message",
"messageerror": "Fetch message error: __error__",
"refreshtoolarge": "Refresh interval too large. Limiting to 2147483 seconds"
"refreshtoolarge": "Refresh interval too large. Limiting to 2147483 seconds",
"invalidattachment": "Invalid attachment content. Must be String or buffer"
}
}
}

View File

@@ -2,7 +2,7 @@
<script type="text/html" data-help-name="e-mail">
<p><code>msg.payload</code>email<code>msg.topic</code></p>
<p>メッセージの受信者のデフォルトはノードに設定できます空のままとした場合は入力メッセージの<code>msg.to</code><code>msg.cc</code><code>msg.bcc</code><code>msg.replyTo</code><code>msg.inReplyTo</code><code>msg.references</code></p>
<p>メッセージの受信者のデフォルトはノードに設定できます空のままとした場合は入力メッセージの<code>msg.to</code><code>msg.cc</code><code>msg.bcc</code><code>msg.replyTo</code><code>msg.inReplyTo</code><code>msg.references</code>, <code>msg.headers</code>, <code>msg.priority</code></p>
<p><code>msg.from</code><code>ID</code></p>
<p>ペイロードはHTML形式とすることも可能です</p>
<p>ペイロードにバイナリバッファを指定すると添付ファイルに変換しますファイル名は<code>msg.filename</code><code>msg.description</code></p>

View File

@@ -1,13 +1,13 @@
{
"name": "node-red-node-email",
"version": "1.8.1",
"version": "1.8.3",
"description": "Node-RED nodes to send and receive simple emails.",
"dependencies": {
"imap": "^0.8.19",
"poplib": "^0.1.7",
"mailparser": "^3.0.0",
"nodemailer": "~6.4.10",
"smtp-server": "^3.7.0"
"mailparser": "^3.0.1",
"nodemailer": "~6.4.17",
"smtp-server": "^3.8.0"
},
"repository": {
"type": "git",

View File

@@ -1,7 +1,7 @@
<!-- PUSHBULLET CONFIG -->
<script type="text/x-red" data-template-name="pushbullet-config">
<script type="text/html" data-template-name="pushbullet-config">
<div class="form-row">
<label for="node-config-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-config-input-name" placeholder="Name">
@@ -30,7 +30,7 @@
<!-- PUSHBULLET OUT -->
<script type="text/x-red" data-template-name="pushbullet">
<script type="text/html" data-template-name="pushbullet">
<div class="form-row">
<label for="node-input-config"><i class="fa fa-user"></i> Config</label>
<input type="text" id="node-input-config">
@@ -72,12 +72,9 @@
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">
</div>
<div class="form-tips" id="pushbullet-migration-info" style="display: none;">
<p><i class="fa fa-random"></i> Configuration node has been migrated, please click Ok and then re-deploy flow to save settings.</p>
</div>
</script>
<script type="text/x-red" data-help-name="pushbullet">
<script type="text/html" data-help-name="pushbullet">
<p>Uses PushBullet to push <code>msg.payload</code> to a device that has the PushBullet app installed.</p>
<p>Optionally uses <code>msg.topic</code> to set the title, if not already set in the properties.</p>
<p>Optionally uses <code>msg.pushtype</code> to set the type of the push, if not already set in the properties.</p>
@@ -122,7 +119,6 @@
});
}
}
try {
getName(this.credentials.deviceid);
}
@@ -131,7 +127,6 @@
getName(data.deviceid);
});
}
return this.name||this.devicename||this.title||"pushbullet";
},
labelStyle: function() {
@@ -139,9 +134,6 @@
},
oneditsave: function() {
this.devicename = undefined;
if(this.migrationData) {
$.ajax('pushbullet/'+this.id+'/migrate?save=true');
}
},
oneditprepare: function() {
var node = this, ddConfig = $('#node-input-config'), ddDevice = $('#node-input-deviceid'), ddPushtype = $('#node-input-pushtype');
@@ -181,7 +173,6 @@
addCurrent = false;
}
}
if(currentDevice) {
if(addCurrent && currentDevice !== "_msg_") {
ddDevice.append('<option value="'+currentDevice+'">'+currentDevice+'</option>');
@@ -191,75 +182,13 @@
});
}
}
function checkMigration(cb) {
$.getJSON('pushbullet/'+node.id+'/migrate', function(data) {
var showMigration = false;
node.migrationData = data.config;
if(data.migrated) {
if(data.config) {
var configId = data.config;
var configType = 'pushbullet-config';
var configTypeDef = RED.nodes.getType(configType);
RED.nodes.add({
type: configType,
id: configId,
name: "Imported",
users: [node.id],
label: configTypeDef.label,
_def: configTypeDef,
});
}
if(node.credentials) {
if(node.credentials.pushkey) {
if(ddConfig.find('option[value="'+data.config+'"]').length === 0) {
ddConfig.append('<option value="'+data.config+'">Imported</option>');
}
ddConfig.val(data.config);
showMigration = true;
}
else {
ddConfig.val("_ADD_");
}
if(node.credentials.deviceid) {
ddDevice.append('<option value="'+node.credentials.deviceid+'">Imported</option>');
ddDevice.val(node.credentials.deviceid);
showMigration = true;
}
else {
ddDevice.val("");
}
}
}
if(showMigration) {
ddPushtype.val("note");
node.dirty = true;
$('#pushbullet-migration-info').show();
}
if(cb) {
cb(showMigration);
}
});
}
checkMigration(function(migrated) {
if(!migrated) {
ddConfig.change(function() {
if(ddConfig.val() && ddConfig.val() !== "_ADD_") {
updateDeviceList();
}
});
}
});
}
});
</script>
<!-- PUSHBULLET IN -->
<script type="text/x-red" data-template-name="pushbullet in">
<script type="text/html" data-template-name="pushbullet in">
<div class="form-row">
<label for="node-input-config"><i class="fa fa-user"></i> Config</label>
<input type="text" id="node-input-config" placeholder="Node-RED">
@@ -277,7 +206,7 @@
</div>
</script>
<script type="text/x-red" data-help-name="pushbullet in">
<script type="text/html" data-help-name="pushbullet in">
<p>Receives Pushbullets from all devices. Messages contain the following data:</p>
<p><code>msg.pushtype</code>: type of message</p>
<p><code>msg.topic</code>: topic information from the push</p>

View File

@@ -34,23 +34,11 @@ module.exports = function(RED) {
});
PushbulletConfig.prototype.initialise = function() {
if (this.initialised) {
return;
}
if (this.initialised) { return; }
this.emitter = new EventEmitter();
this.initialised = true;
var self = this;
// sort migration from old node
var apikey;
if (this.n._migrate) {
apikey = this.n._apikey;
this.credentials = {apikey:apikey};
}
else if (this.credentials) {
apikey = this.credentials.apikey;
}
var apikey = this.credentials.apikey;
if (apikey) {
try {
@@ -254,84 +242,23 @@ module.exports = function(RED) {
this._inputNodes.push(handler);
};
function migrateOldSettings(n) {
if (n.config === undefined) {
var newid, config, apikey, deviceid, pushkeys;
try {
pushkeys = RED.settings.pushbullet || require(process.env.NODE_RED_HOME+"/../pushkey.js");
}
catch(err) { }
var cred = RED.nodes.getCredentials(n.id);
// get old apikey
if (cred && cred.hasOwnProperty("pushkey")) {
apikey = cred.pushkey;
}
else if (pushkeys) {
apikey = pushkeys.pushbullet;
}
// get old device
if (cred && cred.hasOwnProperty("deviceid")) {
deviceid = cred.deviceid;
}
else if (pushkeys) {
deviceid = pushkeys.deviceid;
}
if (apikey) {
newid = (1+Math.random()*4294967295).toString(16);
config = new PushbulletConfig({
id: newid,
type: 'pushbullet-config',
name: n.name,
_migrate: true,
_apikey: apikey,
});
}
if (!(apikey || deviceid)) {
return false;
}
// override configuration properties to compatible migrated ones
n.pushtype = "note";
n.deviceid = deviceid;
return {
deviceid: deviceid,
apikey: apikey,
config: config,
id: newid
};
}
return false;
}
function PushbulletOut(n) {
RED.nodes.createNode(this, n);
var self = this;
this.migrated = migrateOldSettings(n);
this.title = n.title;
this.chan = n.chan;
this.pushtype = n.pushtype;
this.pusher = null;
var configNode;
if (this.migrated) {
this.warn('Settings migrated from previous version of Pushbullet Node, please edit node to update settings.');
this.status({fill: 'yellow', shape: 'ring', text: 'Node migrated'});
this.deviceid = this.migrated.deviceid;
configNode = this.migrated.config;
}
else {
this.status({});
configNode = RED.nodes.getNode(n.config);
try {
this.deviceid = this.credentials.deviceid;
}
catch(err) { }
this.status({});
configNode = RED.nodes.getNode(n.config);
try {
this.deviceid = this.credentials.deviceid;
}
catch(err) { }
if (configNode) {
configNode.initialise();
@@ -462,27 +389,6 @@ module.exports = function(RED) {
}
};
RED.httpAdmin.get('/pushbullet/:id/migrate', RED.auth.needsPermission('pushbullet.read'), function(req, res) {
var node = RED.nodes.getNode(req.params.id);
if (node && node.migrated) {
if (req.query.save) {
var promise;
if (node.migrated.apikey) {
promise = RED.nodes.addCredentials(node.migrated.id, {apikey: node.migrated.apikey});
}
if (node.migrated.deviceid) {
when(promise).then(function() {
RED.nodes.addCredentials(req.params.id, {deviceid: node.migrated.deviceid});
});
}
}
res.send(JSON.stringify({migrated: true, config: node.migrated.id}));
}
else {
res.send("{}");
}
});
RED.httpAdmin.get('/pushbullet/:id/devices', RED.auth.needsPermission('pushbullet.read'), function(req, res) {
var config = RED.nodes.getNode(req.params.id);
var cred = RED.nodes.getCredentials(req.params.id);

View File

@@ -642,7 +642,12 @@ module.exports = function(RED) {
node.status({});
} else {
node.status({fill:"red",shape:"ring",text:"twitter.status.failed"});
node.error(result.body.errors[0].message,msg);
if ('error' in result.body && typeof result.body.error === 'string') {
node.error(result.body.error,msg);
} else {
node.error(result.body.errors[0].message,msg);
}
}
}).catch(function(err) {
node.status({fill:"red",shape:"ring",text:"twitter.status.failed"});

View File

@@ -1,6 +1,6 @@
{
"name": "node-red-node-twitter",
"version": "1.1.6",
"version": "1.1.7",
"description": "A Node-RED node to talk to Twitter",
"dependencies": {
"twitter-ng": "0.6.2",

View File

@@ -109,7 +109,7 @@
</script>
<script type="text/html" data-template-name="xmpp-server">
<div class="form-row node-input-server">
<div class="form-row">
<label for="node-config-input-server"><i class="fa fa-bookmark"></i> Server</label>
<input class="input-append-left" type="text" id="node-config-input-server" placeholder="blah.im" style="width: 40%;" >
<label for="node-config-input-port" style="margin-left: 10px; width: 35px; "> Port</label>

View File

@@ -12,13 +12,13 @@ module.exports = function(RED) {
this.username = n.user.split('@')[0];
// The user may elect to just specify the jid in the settings,
// in which case extract the server from the jid and default the port
if("undefined" === typeof n.server || n.server === ""){
if ("undefined" === typeof n.server || n.server === "") {
this.server = n.user.split('@')[1];
}
else{
this.server = n.server;
}
if("undefined" === typeof n.port || n.port === ""){
if ("undefined" === typeof n.port || n.port === "") {
this.port = 5222;
}
else{
@@ -33,7 +33,7 @@ module.exports = function(RED) {
// The basic xmpp client object, this will be referred to as "xmpp" in the nodes.
// note we're not actually connecting here.
var proto = "xmpp";
if(this.port === 5223){
if (this.port === 5223) {
proto = "xmpps";
}
if (RED.settings.verbose || LOGITALL) {
@@ -55,7 +55,7 @@ module.exports = function(RED) {
// function for a node to tell us it has us as config
this.register = function(xmppThat) {
if (RED.settings.verbose || LOGITALL) {that.log("registering "+xmppThat.id);}
if (RED.settings.verbose || LOGITALL) {that.log("registering "+xmppThat.id); }
that.users[xmppThat.id] = xmppThat;
// So we could start the connection here, but we already have the logic in the nodes that takes care of that.
// if (Object.keys(that.users).length === 1) {
@@ -65,7 +65,7 @@ module.exports = function(RED) {
// function for a node to tell us it's not using us anymore
this.deregister = function(xmppThat,done) {
if (RED.settings.verbose || LOGITALL) {that.log("deregistering "+xmppThat.id);}
if (RED.settings.verbose || LOGITALL) {that.log("deregistering "+xmppThat.id); }
delete that.users[xmppThat.id];
if (that.closing) {
return done();
@@ -84,8 +84,8 @@ module.exports = function(RED) {
this.lastUsed = undefined;
// function for a node to tell us it has just sent a message to our server
// so we know which node to blame if it all goes Pete Tong
this.used = function(xmppThat){
if (RED.settings.verbose || LOGITALL) {that.log(xmppThat.id+" sent a message to the xmpp server");}
this.used = function(xmppThat) {
if (RED.settings.verbose || LOGITALL) {that.log(xmppThat.id+" sent a message to the xmpp server"); }
that.lastUsed = xmppThat;
}
@@ -101,20 +101,20 @@ module.exports = function(RED) {
that.log(stanza);
}
var err = stanza.getChild('error');
if(err){
if (err) {
var textObj = err.getChild('text');
var text = "node-red:common.status.error";
if("undefined" !== typeof textObj){
if ("undefined" !== typeof textObj) {
text = textObj.getText();
}
else{
textObj = err.getChild('code');
if("undefined" !== typeof textObj){
if ("undefined" !== typeof textObj) {
text = textObj.getText();
}
}
if (RED.settings.verbose || LOGITALL) {that.log("Culprit: "+that.lastUsed);}
if("undefined" !== typeof that.lastUsed){
if (RED.settings.verbose || LOGITALL) {that.log("Culprit: "+that.lastUsed); }
if ("undefined" !== typeof that.lastUsed) {
that.lastUsed.status({fill:"red",shape:"ring",text:text});
that.lastUsed.warn(text);
}
@@ -122,20 +122,20 @@ module.exports = function(RED) {
that.log("We did wrong: "+text);
that.log(stanza);
}
// maybe throw the message or summit
//that.error(text);
}
}
}
else if(stanza.is('presence')){
if(['subscribe','subscribed','unsubscribe','unsubscribed'].indexOf(stanza.attrs.type) > -1){
if (RED.settings.verbose || LOGITALL) {that.log("got a subscription based message");}
switch(stanza.attrs.type){
else if (stanza.is('presence')) {
if (['subscribe','subscribed','unsubscribe','unsubscribed'].indexOf(stanza.attrs.type) > -1) {
if (RED.settings.verbose || LOGITALL) {that.log("got a subscription based message"); }
switch(stanza.attrs.type) {
case 'subscribe':
// they're asking for permission let's just say yes
var response = xml('presence',
{type:'subscribed', to:stanza.attrs.from});
{type:'subscribed', to:stanza.attrs.from});
// if an error comes back we can't really blame anyone else
that.used(that);
that.client.send(response);
@@ -145,25 +145,26 @@ module.exports = function(RED) {
}
}
}
else if(stanza.is('iq')){
if (RED.settings.verbose || LOGITALL) {that.log("got an iq query");}
if(stanza.attrs.type === 'error'){
if (RED.settings.verbose || LOGITALL) {that.log("oh noes, it's an error");}
if(stanza.attrs.id === that.lastUsed.id){
else if (stanza.is('iq')) {
if (RED.settings.verbose || LOGITALL) {that.log("got an iq query"); }
if (stanza.attrs.type === 'error') {
if (RED.settings.verbose || LOGITALL) {that.log("oh noes, it's an error"); }
if (stanza.attrs.id === that.lastUsed.id) {
that.lastUsed.status({fill:"red", shape:"ring", text:stanza.getChild('error')});
that.lastUsed.warn(stanza.getChild('error'));
}
}
else if(stanza.attrs.type === 'result'){
// To-Do check for 'bind' result with our current jid
else if (stanza.attrs.type === 'result') {
// AM To-Do check for 'bind' result with our current jid
var query = stanza.getChild('query');
if (RED.settings.verbose || LOGITALL) {that.log("result!");}
if (RED.settings.verbose || LOGITALL) {that.log(query);}
if (RED.settings.verbose || LOGITALL) {that.log("result!"); }
if (RED.settings.verbose || LOGITALL) {that.log(query); }
}
}
}
});
// We shouldn't have any errors here that the input/output nodes can't handle
// if you need to see everything though; uncomment this block
// this.client.on('error', err => {
@@ -176,18 +177,19 @@ module.exports = function(RED) {
// provide some presence so people can see we're online
that.connected = true;
await that.client.send(xml('presence'));
if (RED.settings.verbose || LOGITALL) {that.log('connected as '+that.username+' to ' +that.server+':'+that.port);}
// await that.client.send(xml('presence', {type: 'available'},xml('status', {}, 'available')));
if (RED.settings.verbose || LOGITALL) {that.log('connected as '+that.username+' to ' +that.server+':'+that.port); }
});
// if the connection has gone away, not sure why!
this.client.on('offline', () => {
that.connected = false;
if (RED.settings.verbose || LOGITALL) {that.log('connection closed');}
if (RED.settings.verbose || LOGITALL) {that.log('connection closed'); }
});
// gets called when the node is destroyed, e.g. if N-R is being stopped.
this.on("close", async done => {
if(that.client.connected){
if (that.client.connected) {
await that.client.send(xml('presence', {type: 'unavailable'}));
try{
if (RED.settings.verbose || LOGITALL) {
@@ -195,10 +197,10 @@ module.exports = function(RED) {
}
await that.client.stop().then(that.log("XMPP client stopped")).catch(error=>{that.warn("Got an error whilst closing xmpp session: "+error)});
}
catch(e){
catch(e) {
that.warn(e);
}
}
}
done();
});
}
@@ -223,6 +225,51 @@ module.exports = function(RED) {
xmpp.send(stanza);
}
// separated out since we want the same functionality from both in and out nodes
function errorHandler(node, err){
if (!node.quiet) {
node.quiet = true;
// if the error has a "stanza" then we've probably done something wrong and the
// server is unhappy with us
if (err.hasOwnProperty("stanza")) {
if (err.stanza.name === 'stream:error') { node.error("stream:error - bad login id/pwd ?",err); }
else { node.error(err.stanza.name,err); }
node.status({fill:"red",shape:"ring",text:"bad login"});
}
// The error might be a string
else if (err == "TimeoutError") {
// OK, this happens with OpenFire, suppress it.
node.status({fill:"grey",shape:"dot",text:"opening"});
node.log("Timed out! ",err);
// node.status({fill:"red",shape:"ring",text:"XMPP timeout"});
}
else if (err === "XMPP authentication failure") {
node.error(err,err);
node.status({fill:"red",shape:"ring",text:"XMPP authentication failure"});
}
// or it might have a name that tells us what's wrong
else if (err.name === "SASLError") {
node.error("Authorization error! "+err.condition,err);
node.status({fill:"red",shape:"ring",text:"XMPP authorization failure"});
}
// or it might have the errno set.
else if (err.errno === "ETIMEDOUT") {
node.error("Timeout connecting to server",err);
node.status({fill:"red",shape:"ring",text:"timeout"});
}
else if (err.errno === "ENOTFOUND") {
node.error("Server doesn't exist "+xmpp.options.service,err);
node.status({fill:"red",shape:"ring",text:"bad address"});
}
// nothing we've seen before!
else {
node.error("Unknown error: "+err,err);
node.status({fill:"red",shape:"ring",text:"node-red:common.status.error"});
}
}
}
function XmppInNode(n) {
RED.nodes.createNode(this,n);
@@ -239,7 +286,7 @@ module.exports = function(RED) {
var node = this;
var xmpp = this.serverConfig.client;
/* connection states
online: We are connected
offline: disconnected and will not autoretry
@@ -294,51 +341,17 @@ module.exports = function(RED) {
node.status({fill:"grey",shape:"dot",text:"disconnecting"});
});
// we'll not add a offline catcher, as the error catcher should populate the status for us
// Should we listen on other's status (chatstate) or a chatroom state (groupbuddy)?
xmpp.on('error', err => {
if (RED.settings.verbose || LOGITALL) { node.log("XMPP Error: "+err); }
if(!node.quiet) {
node.quiet = true;
if (err.hasOwnProperty("stanza")) {
if (err.stanza.name === 'stream:error') { node.error("stream:error - bad login id/pwd ?",err); }
else { node.error(err.stanza.name,err); }
node.status({fill:"red",shape:"ring",text:"bad login"});
}
else {
if (err.errno === "ETIMEDOUT") {
node.error("Timeout connecting to server",err);
node.status({fill:"red",shape:"ring",text:"timeout"});
}
if (err.errno === "ENOTFOUND") {
node.error("Server doesn't exist "+xmpp.options.service,err);
node.status({fill:"red",shape:"ring",text:"bad address"});
}
else if (err === "XMPP authentication failure") {
node.error("Authentication failure! "+err,err);
node.status({fill:"red",shape:"ring",text:"XMPP authentication failure"});
}
else if (err.name === "SASLError") {
node.error("Authorization error! "+err.condition,err);
node.status({fill:"red",shape:"ring",text:"XMPP authorization failure"});
}
else if (err == "TimeoutError") {
// Suppress it!
node.warn("Timed out! ");
node.status({fill:"grey",shape:"dot",text:"opening"});
//node.status({fill:"red",shape:"ring",text:"XMPP timeout"});
}
else {
node.error(err,err);
node.status({fill:"red",shape:"ring",text:"node-red:common.status.error"});
}
}
}
errorHandler(node, err);
});
// Meat of it, a stanza object contains chat messages (and other things)
xmpp.on('stanza', async (stanza) =>{
if (RED.settings.verbose || LOGITALL) {node.log(stanza);}
// node.log("Received stanza");
if (RED.settings.verbose || LOGITALL) {node.log(stanza); }
if (stanza.is('message')) {
if (stanza.attrs.type == 'chat') {
var body = stanza.getChild('body');
@@ -349,18 +362,19 @@ module.exports = function(RED) {
msg.topic = stanza.attrs.from
}
else { msg.topic = ids[0]; }
// if (RED.settings.verbose || LOGITALL) {node.log("Received a message from "+stanza.attrs.from); }
if (!node.join && ((node.from === "") || (node.from === stanza.attrs.to))) {
node.send([msg,null]);
}
}
}
else if(stanza.attrs.type == 'groupchat'){
else if (stanza.attrs.type == 'groupchat') {
const parts = stanza.attrs.from.split("/");
var conference = parts[0];
var from = parts[1];
var body = stanza.getChild('body');
var payload = "";
if("undefined" !== typeof body){
if ("undefined" !== typeof body) {
payload = body.getText();
}
var msg = { topic:from, payload:payload, room:conference };
@@ -371,23 +385,23 @@ module.exports = function(RED) {
}
}
}
else if(stanza.is('presence')){
if(['subscribe','subscribed','unsubscribe','unsubscribed'].indexOf(stanza.attrs.type) > -1){
else if (stanza.is('presence')) {
if (['subscribe','subscribed','unsubscribe','unsubscribed'].indexOf(stanza.attrs.type) > -1) {
// this isn't for us, let the config node deal with it.
}
else{
var statusText="";
if(stanza.attrs.type === 'unavailable'){
if (stanza.attrs.type === 'unavailable') {
// the user might not exist, but the server doesn't tell us that!
statusText = "offline";
}
var status = stanza.getChild('status');
if("undefined" !== typeof status){
if ("undefined" !== typeof status) {
statusText = status.getText();
}
// right, do we care if there's no status?
if(statusText !== ""){
if (statusText !== "") {
var from = stanza.attrs.from;
var state = stanza.attrs.show;
var msg = {topic:from, payload: {presence:state, status:statusText} };
@@ -403,16 +417,20 @@ module.exports = function(RED) {
}
});
// xmpp.on('subscribe', from => {
// xmpp.acceptSubscription(from);
// });
//register with config
this.serverConfig.register(this);
// Now actually make the connection
try {
if(xmpp.status === "online"){
if (xmpp.status === "online") {
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
}
else{
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
if(xmpp.status === "offline"){
if (xmpp.status === "offline") {
if (RED.settings.verbose || LOGITALL) {
node.log("starting xmpp client");
}
@@ -505,49 +523,18 @@ module.exports = function(RED) {
xmpp.on('error', function(err) {
if (RED.settings.verbose || LOGITALL) { node.log(err); }
if(!node.quiet) {
node.quiet = true;
if (err.hasOwnProperty("stanza")) {
if (err.stanza.name === 'stream:error') { node.error("stream:error - bad login id/pwd ?",err); }
else { node.error(err.stanza.name,err); }
node.status({fill:"red",shape:"ring",text:"bad login"});
}
else {
if (err.errno === "ETIMEDOUT") {
node.error("Timeout connecting to server",err);
node.status({fill:"red",shape:"ring",text:"timeout"});
}
else if (err.errno === "ENOTFOUND") {
node.error("Server doesn't exist "+xmpp.options.service,err);
node.status({fill:"red",shape:"ring",text:"bad address"});
}
else if (err === "XMPP authentication failure") {
node.error(err,err);
node.status({fill:"red",shape:"ring",text:"XMPP authentication failure"});
}
else if (err == "TimeoutError") {
// OK, this happens with OpenFire, suppress it.
node.status({fill:"grey",shape:"dot",text:"opening"});
node.log("Timed out! ",err);
// node.status({fill:"red",shape:"ring",text:"XMPP timeout"});
}
else {
node.error("Unknown error: "+err,err);
node.status({fill:"red",shape:"ring",text:"node-red:common.status.error"});
}
}
}
errorHandler(node, err)
});
//register with config
this.serverConfig.register(this);
// Now actually make the connection
if(xmpp.status === "online"){
if (xmpp.status === "online") {
node.status({fill:"green",shape:"dot",text:"online"});
}
else{
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
if(xmpp.status === "offline"){
if (xmpp.status === "offline") {
xmpp.start().catch(error => {
node.error("Bad xmpp configuration; service: "+xmpp.options.service+" jid: "+node.serverConfig.jid);
node.warn(error);
@@ -562,31 +549,31 @@ module.exports = function(RED) {
if (msg.presence) {
if (['away', 'dnd', 'xa', 'chat'].indexOf(msg.presence) > -1 ) {
var stanza = xml('presence',
{"show":msg.presence},
xml('status',{},msg.payload));
{"show":msg.presence},
xml('status',{},msg.payload));
node.serverConfig.used(node);
xmpp.send(stanza);
}
else { node.warn("Can't set presence - invalid value: "+msg.presence); }
}
else if(msg.command){
if(msg.command === "subscribe"){
else if (msg.command) {
if (msg.command === "subscribe") {
var stanza = xml('presence',
{type:'subscribe', to: msg.payload});
{type:'subscribe', to: msg.payload});
node.serverConfig.used(node);
xmpp.send(stanza);
}
else if(msg.command === "get"){
else if (msg.command === "get") {
var to = node.to || msg.topic || "";
var stanza = xml('iq',
{type:'get', id:node.id, to: to},
xml('query', 'http://jabber.org/protocol/muc#admin',
xml('item',{affiliation:msg.payload})));
{type:'get', id:node.id, to: to},
xml('query', 'http://jabber.org/protocol/muc#admin',
xml('item',{affiliation:msg.payload})));
node.serverConfig.used(node);
if (RED.settings.verbose || LOGITALL) {node.log("sending stanza "+stanza.toString());}
if (RED.settings.verbose || LOGITALL) {node.log("sending stanza "+stanza.toString()); }
xmpp.send(stanza);
}
}
else {
var to = node.to || msg.topic || "";
@@ -624,7 +611,7 @@ module.exports = function(RED) {
});
node.on("close", function(removed, done) {
if (RED.settings.verbose || LOGITALL) {node.log("Closing");}
if (RED.settings.verbose || LOGITALL) {node.log("Closing"); }
node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"});
node.serverConfig.deregister(node, done);
});

View File

@@ -1,6 +1,6 @@
{
"name": "node-red-node-xmpp",
"version": "0.3.0",
"version": "0.3.1",
"description": "A Node-RED node to talk to an XMPP server",
"dependencies": {
"@xmpp/client": "^0.11.1"