mirror of
https://github.com/node-red/node-red-nodes.git
synced 2023-10-10 13:36:58 +02:00
xmpp auto create rooms correctly and auto join every 60 secs if required
This commit is contained in:
parent
cafdb26832
commit
c368e3bcd4
@ -97,6 +97,7 @@ module.exports = function(RED) {
|
|||||||
// this means we need to figure out which node might have sent it
|
// this means we need to figure out which node might have sent it
|
||||||
// we also deal with subscriptions (i.e. presence information) here
|
// we also deal with subscriptions (i.e. presence information) here
|
||||||
this.client.on('stanza', async (stanza) => {
|
this.client.on('stanza', async (stanza) => {
|
||||||
|
//console.log("STAN",stanza.toString())
|
||||||
if (stanza.is('message')) {
|
if (stanza.is('message')) {
|
||||||
if (stanza.attrs.type == 'error') {
|
if (stanza.attrs.type == 'error') {
|
||||||
if (RED.settings.verbose || LOGITALL) {
|
if (RED.settings.verbose || LOGITALL) {
|
||||||
@ -106,27 +107,27 @@ module.exports = function(RED) {
|
|||||||
var err = stanza.getChild('error');
|
var err = stanza.getChild('error');
|
||||||
if (err) {
|
if (err) {
|
||||||
var textObj = err.getChild('text');
|
var textObj = err.getChild('text');
|
||||||
var text = "node-red:common.status.error";
|
var text = "error";
|
||||||
if (typeof textObj !== "undefined") {
|
if (typeof textObj !== "undefined") {
|
||||||
text = textObj.getText();
|
text = textObj.getText();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
textObj = err.getChild('code');
|
textObj = err.getAttr('code');
|
||||||
if (typeof textObj !== "undefined") {
|
if (typeof textObj !== "undefined") {
|
||||||
text = textObj.getText();
|
text = textObj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (RED.settings.verbose || LOGITALL) {that.log("Culprit: "+that.lastUsed.id); }
|
if (RED.settings.verbose || LOGITALL) {that.log("Culprit: "+that.lastUsed.id); }
|
||||||
if (typeof that.lastUsed !== "undefined") {
|
if (typeof that.lastUsed !== "undefined") {
|
||||||
that.lastUsed.status({fill:"red",shape:"ring",text:text});
|
that.lastUsed.status({fill:"red",shape:"ring",text:"error "+text});
|
||||||
that.lastUsed.warn(text);
|
that.lastUsed.warn("Error "+text);
|
||||||
if (that.lastUsed.join) {
|
if (that.lastUsed.join) {
|
||||||
// it was trying to MUC things up
|
// it was trying to MUC things up
|
||||||
clearMUC(that);
|
clearMUC(that);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (RED.settings.verbose || LOGITALL) {
|
if (RED.settings.verbose || LOGITALL) {
|
||||||
that.log("We did wrong: "+text);
|
that.log("We did wrong: Error "+text);
|
||||||
that.log(stanza);
|
that.log(stanza);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,6 +152,24 @@ module.exports = function(RED) {
|
|||||||
that.log("Was told we've "+stanza.attrs.type+" from "+stanza.attrs.from+" but we don't really care");
|
that.log("Was told we've "+stanza.attrs.type+" from "+stanza.attrs.from+" but we don't really care");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (stanza.attrs.to.indexOf(that.jid) !== -1) {
|
||||||
|
var _x = stanza.getChild("x")
|
||||||
|
if (_x !== undefined) {
|
||||||
|
var _stat = _x.getChildren("status");
|
||||||
|
for (var i = 0; i<_stat.length; i++) {
|
||||||
|
if (_stat[i].attrs.code == 201) {
|
||||||
|
if (RED.settings.verbose || LOGITALL) {that.log("created new room"); }
|
||||||
|
var stanza = xml('iq',
|
||||||
|
{type:'set', id:that.id, from:that.jid, to:stanza.attrs.from.split('/')[0]},
|
||||||
|
xml('query', 'http://jabber.org/protocol/muc#owner',
|
||||||
|
xml('x', {xmlns:'jabber:x:data', type:'submit'})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
that.client.send(stanza);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (stanza.is('iq')) {
|
else if (stanza.is('iq')) {
|
||||||
if (RED.settings.verbose || LOGITALL) {that.log("got an iq query"); }
|
if (RED.settings.verbose || LOGITALL) {that.log("got an iq query"); }
|
||||||
@ -188,18 +207,22 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
// gets called when the node is destroyed, e.g. if N-R is being stopped.
|
// gets called when the node is destroyed, e.g. if N-R is being stopped.
|
||||||
this.on("close", async done => {
|
this.on("close", async done => {
|
||||||
if (that.client.connected) {
|
const rooms = Object.keys(this.MUCs)
|
||||||
await that.client.send(xml('presence', {type: 'unavailable'}));
|
for (const room of rooms) {
|
||||||
try{
|
await that.client.send(xml('presence', {to:room, type:'unavailable'}));
|
||||||
if (RED.settings.verbose || LOGITALL) {
|
|
||||||
that.log("Calling stop() after close, status is "+that.client.status);
|
|
||||||
}
|
|
||||||
await that.client.stop().then(that.log("XMPP client stopped")).catch(error=>{that.warn("Got an error whilst closing xmpp session: "+error)});
|
|
||||||
}
|
|
||||||
catch(e) {
|
|
||||||
that.warn(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// if (that.client.connected) {
|
||||||
|
await that.client.send(xml('presence', {type:'unavailable'}));
|
||||||
|
try{
|
||||||
|
if (RED.settings.verbose || LOGITALL) {
|
||||||
|
that.log("Calling stop() after close, status is "+that.client.status);
|
||||||
|
}
|
||||||
|
await that.client.stop().then(that.log("XMPP client stopped")).catch(error=>{that.warn("Got an error whilst closing xmpp session: "+error)});
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
that.warn(e);
|
||||||
|
}
|
||||||
|
// }
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -227,9 +250,7 @@ module.exports = function(RED) {
|
|||||||
// Yes, there's a race condition, but it's not a huge problem to send two messages
|
// Yes, there's a race condition, but it's not a huge problem to send two messages
|
||||||
// so we don't care.
|
// so we don't care.
|
||||||
if (name in node.serverConfig.MUCs) {
|
if (name in node.serverConfig.MUCs) {
|
||||||
if (RED.settings.verbose || LOGITALL) {
|
if (RED.settings.verbose || LOGITALL) { node.log("already joined MUC "+name); }
|
||||||
node.log("already joined MUC "+name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var stanza = xml('presence',
|
var stanza = xml('presence',
|
||||||
@ -240,8 +261,8 @@ module.exports = function(RED) {
|
|||||||
);
|
);
|
||||||
node.serverConfig.used(node);
|
node.serverConfig.used(node);
|
||||||
node.serverConfig.MUCs[name] = "joined";
|
node.serverConfig.MUCs[name] = "joined";
|
||||||
|
if (RED.settings.verbose || LOGITALL) { node.log("JOINED "+name); }
|
||||||
xmpp.send(stanza);
|
xmpp.send(stanza);
|
||||||
if (RED.settings.verbose || LOGITALL) { node.log("JOINED",name); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,7 +314,7 @@ module.exports = function(RED) {
|
|||||||
// nothing we've seen before!
|
// nothing we've seen before!
|
||||||
else {
|
else {
|
||||||
node.error("Unknown error: "+err,err);
|
node.error("Unknown error: "+err,err);
|
||||||
node.status({fill:"red",shape:"ring",text:"node-red:common.status.error"});
|
node.status({fill:"red",shape:"ring",text:"error"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -312,10 +333,21 @@ module.exports = function(RED) {
|
|||||||
this.quiet = false;
|
this.quiet = false;
|
||||||
// MUC == Multi-User-Chat == chatroom
|
// MUC == Multi-User-Chat == chatroom
|
||||||
//this.muc = this.join && (this.from !== "")
|
//this.muc = this.join && (this.from !== "")
|
||||||
// list of possible rooms - queried from server
|
|
||||||
this.roomsFound = {};
|
|
||||||
var node = this;
|
var node = this;
|
||||||
|
|
||||||
|
var joinrooms = function() {
|
||||||
|
if (node.from[0] === "") {
|
||||||
|
// try to get list of all rooms and join them all.
|
||||||
|
getItems(node.serverConfig.server, node.serverConfig.id, xmpp);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// if we want to use a chatroom, we need to tell the server we want to join it
|
||||||
|
for (var i=0; i<node.from.length; i++) {
|
||||||
|
joinMUC(node, xmpp, node.from[i]+'/'+node.nick);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var xmpp = this.serverConfig.client;
|
var xmpp = this.serverConfig.client;
|
||||||
|
|
||||||
/* connection states
|
/* connection states
|
||||||
@ -333,7 +365,7 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
// if we're already connected, then do the actions now, otherwise register a callback
|
// if we're already connected, then do the actions now, otherwise register a callback
|
||||||
// if (xmpp.status === "online") {
|
// if (xmpp.status === "online") {
|
||||||
// node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
|
// node.status({fill:"green",shape:"dot",text:"connected"});
|
||||||
// if (node.muc) {
|
// if (node.muc) {
|
||||||
// joinMUC(node, xmpp, node.from+'/'+node.nick);
|
// joinMUC(node, xmpp, node.from+'/'+node.nick);
|
||||||
// }
|
// }
|
||||||
@ -341,28 +373,20 @@ module.exports = function(RED) {
|
|||||||
// sod it, register it anyway, that way things will work better on a reconnect:
|
// sod it, register it anyway, that way things will work better on a reconnect:
|
||||||
xmpp.on('online', async address => {
|
xmpp.on('online', async address => {
|
||||||
node.quiet = false;
|
node.quiet = false;
|
||||||
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
|
node.status({fill:"green",shape:"dot",text:"connected"});
|
||||||
if (node.join) {
|
if (node.join) {
|
||||||
if (node.from[0] === "") {
|
node.jointick = setInterval(function() { joinrooms(); }, 60000);
|
||||||
// try to get list of all rooms and join them all.
|
joinrooms();
|
||||||
getItems(this.serverConfig.server,this.serverConfig.id,xmpp);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// if we want to use a chatroom, we need to tell the server we want to join it
|
|
||||||
for (var i=0; i<node.from.length; i++) {
|
|
||||||
joinMUC(node, xmpp, node.from[i]+'/'+node.nick);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
xmpp.on('connecting', async address => {
|
xmpp.on('connecting', async address => {
|
||||||
if (!node.quiet) {
|
if (!node.quiet) {
|
||||||
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
|
node.status({fill:"grey",shape:"dot",text:"connecting"});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
xmpp.on('connect', async address => {
|
xmpp.on('connect', async address => {
|
||||||
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connected"});
|
node.status({fill:"grey",shape:"dot",text:"connected"});
|
||||||
});
|
});
|
||||||
xmpp.on('opening', async address => {
|
xmpp.on('opening', async address => {
|
||||||
node.status({fill:"grey",shape:"dot",text:"opening"});
|
node.status({fill:"grey",shape:"dot",text:"opening"});
|
||||||
@ -374,7 +398,7 @@ module.exports = function(RED) {
|
|||||||
node.status({fill:"grey",shape:"dot",text:"closing"});
|
node.status({fill:"grey",shape:"dot",text:"closing"});
|
||||||
});
|
});
|
||||||
xmpp.on('close', async address => {
|
xmpp.on('close', async address => {
|
||||||
node.status({fill:"grey",shape:"dot",text:"closed"});
|
node.status({fill:"grey",shape:"ring",text:"closed"});
|
||||||
});
|
});
|
||||||
xmpp.on('disconnecting', async address => {
|
xmpp.on('disconnecting', async address => {
|
||||||
node.status({fill:"grey",shape:"dot",text:"disconnecting"});
|
node.status({fill:"grey",shape:"dot",text:"disconnecting"});
|
||||||
@ -391,6 +415,7 @@ module.exports = function(RED) {
|
|||||||
xmpp.on('stanza', async (stanza) => {
|
xmpp.on('stanza', async (stanza) => {
|
||||||
if (RED.settings.verbose || LOGITALL) { node.log(stanza); }
|
if (RED.settings.verbose || LOGITALL) { node.log(stanza); }
|
||||||
if (stanza.is('message')) {
|
if (stanza.is('message')) {
|
||||||
|
// console.log(stanza.toString())
|
||||||
if (stanza.attrs.type == 'chat') {
|
if (stanza.attrs.type == 'chat') {
|
||||||
var body = stanza.getChild('body');
|
var body = stanza.getChild('body');
|
||||||
if (body) {
|
if (body) {
|
||||||
@ -470,15 +495,16 @@ module.exports = function(RED) {
|
|||||||
getItems(_items[i].attrs.jid,this.serverConfig.jid,xmpp);
|
getItems(_items[i].attrs.jid,this.serverConfig.jid,xmpp);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.roomsFound[_items[i].attrs.name] = _items[i].attrs.jid;
|
|
||||||
var name = _items[i].attrs.jid+'/'+node.serverConfig.username;
|
var name = _items[i].attrs.jid+'/'+node.serverConfig.username;
|
||||||
if (!(name in node.serverConfig.MUCs)) {
|
if (!(name in node.serverConfig.MUCs)) {
|
||||||
if (RED.settings.verbose || LOGITALL) {this.log("Need to Join room:"+name); }
|
if (RED.settings.verbose || LOGITALL) { node.log("Need to Join room:"+name); }
|
||||||
joinMUC(node, xmpp, name)
|
joinMUC(node, xmpp, name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (RED.settings.verbose || LOGITALL) { node.log("Already joined:"+name); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (RED.settings.verbose || LOGITALL) {this.log("ROOMS:"+this.server+this.roomsFound); }
|
|
||||||
}
|
}
|
||||||
if (query && query.attrs.hasOwnProperty("xmlns") && query.attrs["xmlns"] === "http://jabber.org/protocol/disco#info") {
|
if (query && query.attrs.hasOwnProperty("xmlns") && query.attrs["xmlns"] === "http://jabber.org/protocol/disco#info") {
|
||||||
var fe = [];
|
var fe = [];
|
||||||
@ -507,26 +533,30 @@ module.exports = function(RED) {
|
|||||||
// Now actually make the connection
|
// Now actually make the connection
|
||||||
try {
|
try {
|
||||||
if (xmpp.status === "online") {
|
if (xmpp.status === "online") {
|
||||||
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
|
node.status({fill:"green",shape:"dot",text:"connected"});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
|
node.status({fill:"grey",shape:"dot",text:"connecting"});
|
||||||
if (xmpp.status === "offline") {
|
if (xmpp.status === "offline") {
|
||||||
if (RED.settings.verbose || LOGITALL) {
|
if (RED.settings.verbose || LOGITALL) {
|
||||||
node.log("starting xmpp client");
|
node.log("starting xmpp client");
|
||||||
}
|
}
|
||||||
xmpp.start().catch(error => {node.warn("Got error on start: "+error); node.warn("XMPP Status is now: "+xmpp.status)});
|
xmpp.start().catch(error => {
|
||||||
|
node.warn("Got error on start: "+error);
|
||||||
|
node.warn("XMPP Status is now: "+xmpp.status)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(e) {
|
catch(e) {
|
||||||
node.error("Bad xmpp configuration; service: "+xmpp.options.service+" jid: "+node.serverConfig.jid);
|
node.error("Bad xmpp configuration; service: "+xmpp.options.service+" jid: "+node.serverConfig.jid);
|
||||||
node.warn(e.stack);
|
node.warn(e.stack);
|
||||||
node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"});
|
node.status({fill:"red",shape:"ring",text:"disconnected"});
|
||||||
}
|
}
|
||||||
|
|
||||||
node.on("close", function(removed, done) {
|
node.on("close", function(removed, done) {
|
||||||
node.status({fill:"red",shape:"ring",text:"node-red:common.status.disconnected"});
|
if (node.jointick) { clearInterval(node.jointick); }
|
||||||
|
node.status({fill:"grey",shape:"ring",text:"disconnected"});
|
||||||
node.serverConfig.deregister(node, done);
|
node.serverConfig.deregister(node, done);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -563,7 +593,7 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
// if we're already connected, then do the actions now, otherwise register a callback
|
// if we're already connected, then do the actions now, otherwise register a callback
|
||||||
// if (xmpp.status === "online") {
|
// if (xmpp.status === "online") {
|
||||||
// node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
|
// node.status({fill:"green",shape:"dot",text:"connected"});
|
||||||
// if (node.muc){
|
// if (node.muc){
|
||||||
// // if we want to use a chatroom, we need to tell the server we want to join it
|
// // if we want to use a chatroom, we need to tell the server we want to join it
|
||||||
// joinMUC(node, xmpp, node.from+'/'+node.nick);
|
// joinMUC(node, xmpp, node.from+'/'+node.nick);
|
||||||
@ -572,7 +602,7 @@ module.exports = function(RED) {
|
|||||||
// sod it, register it anyway, that way things will work better on a reconnect:
|
// sod it, register it anyway, that way things will work better on a reconnect:
|
||||||
xmpp.on('online', function(data) {
|
xmpp.on('online', function(data) {
|
||||||
node.quiet = false;
|
node.quiet = false;
|
||||||
node.status({fill:"green",shape:"dot",text:"node-red:common.status.connected"});
|
node.status({fill:"green",shape:"dot",text:"connected"});
|
||||||
if (node.muc) {
|
if (node.muc) {
|
||||||
// if we want to use a chatroom, we need to tell the server we want to join it
|
// if we want to use a chatroom, we need to tell the server we want to join it
|
||||||
joinMUC(node, xmpp, node.from+'/'+node.nick);
|
joinMUC(node, xmpp, node.from+'/'+node.nick);
|
||||||
@ -581,11 +611,11 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
xmpp.on('connecting', async address => {
|
xmpp.on('connecting', async address => {
|
||||||
if (!node.quiet) {
|
if (!node.quiet) {
|
||||||
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
|
node.status({fill:"grey",shape:"dot",text:"connecting"});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
xmpp.on('connect', async address => {
|
xmpp.on('connect', async address => {
|
||||||
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connected"});
|
node.status({fill:"grey",shape:"dot",text:"connected"});
|
||||||
});
|
});
|
||||||
xmpp.on('opening', async address => {
|
xmpp.on('opening', async address => {
|
||||||
node.status({fill:"grey",shape:"dot",text:"opening"});
|
node.status({fill:"grey",shape:"dot",text:"opening"});
|
||||||
@ -609,6 +639,11 @@ module.exports = function(RED) {
|
|||||||
errorHandler(node, err)
|
errorHandler(node, err)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
xmpp.on('stanza', async (stanza) => {
|
||||||
|
// if (stanza.is('presence')) {
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
|
||||||
//register with config
|
//register with config
|
||||||
this.serverConfig.register(this);
|
this.serverConfig.register(this);
|
||||||
// Now actually make the connection
|
// Now actually make the connection
|
||||||
@ -616,13 +651,13 @@ module.exports = function(RED) {
|
|||||||
node.status({fill:"green",shape:"dot",text:"online"});
|
node.status({fill:"green",shape:"dot",text:"online"});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
node.status({fill:"grey",shape:"dot",text:"node-red:common.status.connecting"});
|
node.status({fill:"grey",shape:"dot",text:"connecting"});
|
||||||
if (xmpp.status === "offline") {
|
if (xmpp.status === "offline") {
|
||||||
xmpp.start().catch(error => {
|
xmpp.start().catch(error => {
|
||||||
node.error("Bad xmpp configuration; service: "+xmpp.options.service+" jid: "+node.serverConfig.jid);
|
node.error("Bad xmpp configuration; service: "+xmpp.options.service+" jid: "+node.serverConfig.jid);
|
||||||
node.warn(error);
|
node.warn(error);
|
||||||
node.warn(error.stack);
|
node.warn(error.stack);
|
||||||
node.status({fill:"red",shape:"ring",text:"node-red:common.status.error"});
|
node.status({fill:"red",shape:"ring",text:"error"});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -683,7 +718,6 @@ module.exports = function(RED) {
|
|||||||
{ type: type, to: to },
|
{ type: type, to: to },
|
||||||
xml("body", {}, JSON.stringify(msg))
|
xml("body", {}, JSON.stringify(msg))
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (msg.payload) {
|
else if (msg.payload) {
|
||||||
if (typeof(msg.payload) === "object") {
|
if (typeof(msg.payload) === "object") {
|
||||||
@ -709,7 +743,7 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
node.on("close", function(removed, done) {
|
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.status({fill:"grey",shape:"ring",text:"disconnected"});
|
||||||
node.serverConfig.deregister(node, done);
|
node.serverConfig.deregister(node, done);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red-node-xmpp",
|
"name": "node-red-node-xmpp",
|
||||||
"version": "0.4.0",
|
"version": "0.4.1",
|
||||||
"description": "A Node-RED node to talk to an XMPP server",
|
"description": "A Node-RED node to talk to an XMPP server",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@xmpp/client": "^0.12.0"
|
"@xmpp/client": "^0.12.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user