- New react node for reacting to messages
- made input and output nodes more compatible with each other (for relay purposes). - File/Image input nodes can be combined with a File In node now - Remove console.log debug lines - set version to 0.0.3 - send message node updated to handle message formats and types. - Fixed ignore properties on matrix receive node not saving - created basic readme - WIP on node docs
This commit is contained in:
parent
61aa32e8a6
commit
cd99955115
35
README.md
35
README.md
@ -1,4 +1,33 @@
|
|||||||
# node-red-contrib-matrix-support
|
# node-red-contrib-matrix-chat
|
||||||
Matrix chat server support for Node-RED
|
Matrix chat server client for Node-RED
|
||||||
|
|
||||||
This is currently a work in progress but we are getting close to a first release.
|
### Features
|
||||||
|
|
||||||
|
The following is supported from this package:
|
||||||
|
|
||||||
|
- Receive events from a room (messages, reactions, images, and files)
|
||||||
|
- Send Images/Files
|
||||||
|
- Send HTML/Plain Text Message
|
||||||
|
- Send HTML/Plain Text Notice
|
||||||
|
- React to messages
|
||||||
|
|
||||||
|
Therefor you can easily build a bot or even a relay from another chat service.
|
||||||
|
|
||||||
|
### Installing
|
||||||
|
|
||||||
|
You can either install from within Node-RED by searching for `node-red-contrib-matrix-chat` or run this from within your Node-RED directory:
|
||||||
|
```bash
|
||||||
|
npm install node-red-contrib-matrix-chat
|
||||||
|
```
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
Using this package is very straightforward. Examples coming soon!
|
||||||
|
|
||||||
|
### Other Packages
|
||||||
|
|
||||||
|
- [node-red-contrib-gamedig](https://www.npmjs.com/package/node-red-contrib-gamedig) - Query game servers from Node-RED!
|
||||||
|
|
||||||
|
### Contributing
|
||||||
|
All contributions are welcome! If you do add a feature please do a pull request so that everyone benefits :)
|
||||||
|
Sharing is caring.
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red-contrib-matrix-support",
|
"name": "node-red-contrib-matrix-chat",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
|
14
package.json
14
package.json
@ -1,18 +1,18 @@
|
|||||||
{
|
{
|
||||||
"name": "node-red-contrib-matrix-support",
|
"name": "node-red-contrib-matrix-chat",
|
||||||
"version": "0.0.1",
|
"version": "0.0.3",
|
||||||
"description": "Matrix chat server support for Node-RED",
|
"description": "Matrix chat server client for Node-RED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"matrix-js-sdk": "^12.2.0"
|
"matrix-js-sdk": "^12.2.0"
|
||||||
},
|
},
|
||||||
"node-red": {
|
"node-red": {
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"matrix-server-config": "src/matrix-server-config.js",
|
"matrix-server-config": "src/matrix-server-config.js",
|
||||||
"matrix-send": "src/matrix-send.js",
|
"matrix-receive": "src/matrix-receive.js",
|
||||||
|
"matrix-send-message": "src/matrix-send-message.js",
|
||||||
"matrix-send-file": "src/matrix-send-file.js",
|
"matrix-send-file": "src/matrix-send-file.js",
|
||||||
"matrix-send-image": "src/matrix-send-image.js",
|
"matrix-send-image": "src/matrix-send-image.js",
|
||||||
"matrix-send-message": "src/matrix-send-message.js",
|
"matrix-react": "src/matrix-react.js"
|
||||||
"matrix-receive": "src/matrix-receive.js"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@ -24,7 +24,7 @@
|
|||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/skylar-tech/node-red-contrib-matrix-support"
|
"url": "https://github.com/skylar-tech/node-red-contrib-matrix-chat"
|
||||||
},
|
},
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Skylar Sadlier",
|
"name": "Skylar Sadlier",
|
||||||
|
102
src/matrix-react.html
Normal file
102
src/matrix-react.html
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
<script type="text/javascript">
|
||||||
|
RED.nodes.registerType('matrix-react',{
|
||||||
|
category: 'matrix',
|
||||||
|
color: '#00b7ca',
|
||||||
|
icon: "matrix.png",
|
||||||
|
outputLabels: ["success", "error"],
|
||||||
|
inputs:1,
|
||||||
|
outputs:2,
|
||||||
|
defaults: {
|
||||||
|
name: { value: null },
|
||||||
|
server: { value: "", type: "matrix-server-config" },
|
||||||
|
roomId: { value: null }
|
||||||
|
},
|
||||||
|
label: function() {
|
||||||
|
return this.name || "React";
|
||||||
|
},
|
||||||
|
paletteLabel: 'React'
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-template-name="matrix-react">
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
||||||
|
<input type="text" id="node-input-name" placeholder="Name">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-server"><i class="fa fa-user"></i> Matrix Server Config</label>
|
||||||
|
<input type="text" id="node-input-server">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label>
|
||||||
|
<input type="text" id="node-input-roomId">
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-messageType">
|
||||||
|
Message Type
|
||||||
|
</label>
|
||||||
|
<select id="node-input-messageType">
|
||||||
|
<option value="m.text">m.text</option>
|
||||||
|
<option value="m.notice">m.notice</option>
|
||||||
|
<option value="msg.type">msg.type input</option>
|
||||||
|
</select>
|
||||||
|
<div class="form-tips">
|
||||||
|
It's recommended to use m.notice for bots because the message will render in a lighter text (at least in Element client) for users to distinguish bot and real user messages.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-messageFormat">
|
||||||
|
Message Format
|
||||||
|
</label>
|
||||||
|
<select id="node-input-messageFormat">
|
||||||
|
<option value="">Default (plaintext)</option>
|
||||||
|
<option value="html">HTML</option>
|
||||||
|
<option value="msg.format">msg.format input</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-tips">
|
||||||
|
Must be a valid <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank">MIME Type</a>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script type="text/html" data-help-name="matrix-react">
|
||||||
|
<h3>Details</h3>
|
||||||
|
<p>React to a message in a Matrix room.</p>
|
||||||
|
|
||||||
|
<h3>Inputs</h3>
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.payload
|
||||||
|
<span class="property-type">String</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Usually an emoji but can also be text. </dd>
|
||||||
|
|
||||||
|
<dt>msg.roomId
|
||||||
|
<span class="property-type">String | Null</span>
|
||||||
|
</dt>
|
||||||
|
<dd> Room ID to send image to. Optional if configured on the node. If configured on the node this will be ignored.</dd>
|
||||||
|
|
||||||
|
<dt class="optional">msg.referenceEventId<br />
|
||||||
|
msg.eventId
|
||||||
|
<span class="property-type">String</span>
|
||||||
|
</dt>
|
||||||
|
<dd> The eventId of the message to react to. Uses <code>msg.referenceEventId</code> first and falls back to <code>msg.eventId</code>. One of these MUST be defined.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<h3>Outputs</h3>
|
||||||
|
<ol class="node-ports">
|
||||||
|
<li>Success
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dd>original msg object preserved.</dd>
|
||||||
|
|
||||||
|
<dt>msg.eventId <span class="property-type">string</span></dt>
|
||||||
|
<dd>the eventId from the posted reaction.</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
<li>Error
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.error <span class="property-type">string</span></dt>
|
||||||
|
<dd>the error that occurred.</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</script>
|
78
src/matrix-react.js
Normal file
78
src/matrix-react.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
module.exports = function(RED) {
|
||||||
|
function MatrixReact(n) {
|
||||||
|
RED.nodes.createNode(this, n);
|
||||||
|
|
||||||
|
var node = this;
|
||||||
|
|
||||||
|
this.name = n.name;
|
||||||
|
this.server = RED.nodes.getNode(n.server);
|
||||||
|
this.roomId = n.roomId;
|
||||||
|
|
||||||
|
if (!node.server) {
|
||||||
|
node.warn("No configuration node");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
|
||||||
|
node.server.on("disconnected", function(){
|
||||||
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.server.on("connected", function() {
|
||||||
|
node.status({ fill: "green", shape: "ring", text: "connected" });
|
||||||
|
});
|
||||||
|
|
||||||
|
node.on("input", function (msg) {
|
||||||
|
if (!node.server || !node.server.matrixClient) {
|
||||||
|
node.error("No matrix server selected");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!node.server.isConnected()) {
|
||||||
|
node.error("Matrix server connection is currently closed");
|
||||||
|
node.send([null, msg]);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.roomId = node.roomId || msg.roomId;
|
||||||
|
if(!msg.roomId) {
|
||||||
|
node.error("Room must be specified in msg.roomId or in configuration");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!msg.payload) {
|
||||||
|
node.error('msg.payload is required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let eventId = msg.referenceEventId || msg.eventId;
|
||||||
|
if(!eventId) {
|
||||||
|
node.error('Either msg.referenceEventId or msg.eventId must be defined to react to a message.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
node.server.matrixClient.sendCompleteEvent(
|
||||||
|
msg.roomId,
|
||||||
|
{
|
||||||
|
type: 'm.reaction',
|
||||||
|
content: {
|
||||||
|
"m.relates_to": {
|
||||||
|
event_id: eventId,
|
||||||
|
key: msg.payload,
|
||||||
|
rel_type: "m.annotation"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.then(function(e) {
|
||||||
|
msg.eventId = e.event_id;
|
||||||
|
node.send([msg, null]);
|
||||||
|
})
|
||||||
|
.catch(function(e){
|
||||||
|
msg.error = e;
|
||||||
|
node.send([null, msg]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
RED.nodes.registerType("matrix-react", MatrixReact);
|
||||||
|
}
|
@ -41,58 +41,134 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="node-config-input-ignoreText"
|
id="node-input-ignoreText"
|
||||||
style="width: auto; margin-left: 125px; vertical-align: top"
|
style="width: auto; margin-left: 125px; vertical-align: top"
|
||||||
/>
|
/>
|
||||||
<label for="node-config-input-ignoreText" style="width: auto">
|
<label for="node-input-ignoreText" style="width: auto">
|
||||||
Ignore text
|
Ignore text
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="node-config-input-ignoreReactions"
|
id="node-input-ignoreReactions"
|
||||||
style="width: auto; margin-left: 125px; vertical-align: top"
|
style="width: auto; margin-left: 125px; vertical-align: top"
|
||||||
/>
|
/>
|
||||||
<label for="node-config-input-ignoreReactions" style="width: auto">
|
<label for="node-input-ignoreReactions" style="width: auto">
|
||||||
Ignore reactions
|
Ignore reactions
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="node-config-input-ignoreFiles"
|
id="node-input-ignoreFiles"
|
||||||
style="width: auto; margin-left: 125px; vertical-align: top"
|
style="width: auto; margin-left: 125px; vertical-align: top"
|
||||||
/>
|
/>
|
||||||
<label for="node-config-input-ignoreFiles" style="width: auto">
|
<label for="node-input-ignoreFiles" style="width: auto">
|
||||||
Ignore files
|
Ignore files
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="node-config-input-ignoreImages"
|
id="node-input-ignoreImages"
|
||||||
style="width: auto; margin-left: 125px; vertical-align: top"
|
style="width: auto; margin-left: 125px; vertical-align: top"
|
||||||
/>
|
/>
|
||||||
<label for="node-config-input-ignoreImages" style="width: auto">
|
<label for="node-input-ignoreImages" style="width: auto">
|
||||||
Ignore images
|
Ignore images
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/html" data-help-name="matrix-receive">
|
<script type="text/html" data-help-name="matrix-receive">
|
||||||
<p>Receive messages from a matrix server on all rooms or a specified room.</p>
|
<p>Receive events from matrix.</p>
|
||||||
|
|
||||||
<h3>Outputs</h3>
|
<h3>Outputs</h3>
|
||||||
<ol class="node-ports">
|
<ol class="node-ports">
|
||||||
<li>Message
|
<li>Always Returned
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt>topic <span class="property-type">string</span></dt>
|
<dt>msg.type <span class="property-type">string</span></dt>
|
||||||
<dd>the room the message originated from.</dd>
|
<dd>
|
||||||
|
the message type. This is one of m.text, m.reaction, m.file, or m.image
|
||||||
|
</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt>payload <span class="property-type">string</span></dt>
|
<dt>msg.payload <span class="property-type">string</span></dt>
|
||||||
<dd>the message from the server.</dd>
|
<dd>the body from the message's content.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.sender <span class="property-type">string</span></dt>
|
||||||
|
<dd>the sender of the message. Example: @john:matrix.org</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.roomId <span class="property-type">string</span></dt>
|
||||||
|
<dd>the ID of the room. Example: !OGEhHVWSdvArJzumhm:matrix.org</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.event <span class="property-type">object</span></dt>
|
||||||
|
<dd>the event object returned by the Matrix server</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.content <span class="property-type">object</span></dt>
|
||||||
|
<dd>the message's content object</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><code>msg.type</code> == '<strong>m.text</strong>'
|
||||||
|
<div class="form-tips" style="margin-bottom: 12px;">
|
||||||
|
Doesn't return anything extra
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><code>msg.type</code> == '<strong>m.reaction</strong>'
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.info <span class="property-type">object</span></dt>
|
||||||
|
<dd>the content's info.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.referenceEventId <span class="property-type">string</span></dt>
|
||||||
|
<dd>the message that the reaction relates to</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.payload <span class="property-type">string</span></dt>
|
||||||
|
<dd>the key of the reaction's content</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><code>msg.type</code> == '<strong>m.file</strong>'
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.file.info <span class="property-type">string</span></dt>
|
||||||
|
<dd>the content's info.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.file.url <span class="property-type">string</span></dt>
|
||||||
|
<dd>the file's URL</dd>
|
||||||
|
</dl>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li><code>msg.type</code> == '<strong>m.image</strong>'
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.image.info <span class="property-type">string</span></dt>
|
||||||
|
<dd>the image info.</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.file.url <span class="property-type">string</span></dt>
|
||||||
|
<dd>the image's URL</dd>
|
||||||
|
</dl>
|
||||||
|
|
||||||
|
<dl class="message-properties">
|
||||||
|
<dt>msg.file.thumbnail_url <span class="property-type">string</span></dt>
|
||||||
|
<dd>the image's thumbnail URL</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
@ -10,6 +10,8 @@ module.exports = function(RED) {
|
|||||||
this.ignoreReactions = n.ignoreReactions;
|
this.ignoreReactions = n.ignoreReactions;
|
||||||
this.ignoreFiles = n.ignoreFiles;
|
this.ignoreFiles = n.ignoreFiles;
|
||||||
this.ignoreImages = n.ignoreImages;
|
this.ignoreImages = n.ignoreImages;
|
||||||
|
this.roomId = n.roomId;
|
||||||
|
this.roomIds = this.roomId ? this.roomId.split(',') : [];
|
||||||
|
|
||||||
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
|
|
||||||
@ -18,7 +20,7 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
node.server.on("disconnected", function(){
|
node.server.on("disconnected", function() {
|
||||||
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -26,48 +28,41 @@ module.exports = function(RED) {
|
|||||||
node.status({ fill: "green", shape: "ring", text: "connected" });
|
node.status({ fill: "green", shape: "ring", text: "connected" });
|
||||||
|
|
||||||
node.server.matrixClient.on("Room.timeline", function(event, room, toStartOfTimeline, data) {
|
node.server.matrixClient.on("Room.timeline", function(event, room, toStartOfTimeline, data) {
|
||||||
console.log("Room.timeline", [event, room]);
|
|
||||||
if (toStartOfTimeline) {
|
if (toStartOfTimeline) {
|
||||||
console.log("MESSAGED SKIPPED: toStartOfTimeline");
|
|
||||||
return; // ignore paginated results
|
return; // ignore paginated results
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
event.getType() !== "m.room.message"
|
event.getType() !== "m.room.message"
|
||||||
&& event.getType() !== "m.reaction"
|
&& event.getType() !== "m.reaction"
|
||||||
) {
|
) {
|
||||||
console.log("MESSAGED SKIPPED: TYPE");
|
|
||||||
return; // only keep messages
|
return; // only keep messages
|
||||||
}
|
}
|
||||||
if (!event.getSender() || event.getSender() === node.server.userId) {
|
if (!event.getSender() || event.getSender() === node.server.userId) {
|
||||||
console.log("MESSAGED SKIPPED: SENDER");
|
|
||||||
return; // ignore our own messages
|
return; // ignore our own messages
|
||||||
}
|
}
|
||||||
if (!event.getUnsigned() || event.getUnsigned().age > 1000) {
|
if (!event.getUnsigned() || event.getUnsigned().age > 1000) {
|
||||||
console.log("MESSAGED SKIPPED: UNSIGNED");
|
|
||||||
return; // ignore old messages
|
return; // ignore old messages
|
||||||
}
|
}
|
||||||
|
|
||||||
// if node has a room ID set we only listen on that room
|
// if node has a room ID set we only listen on that room
|
||||||
if(node.roomId) {
|
if(node.roomIds.length && node.roomIds.indexOf(room.roomId) === -1) {
|
||||||
let roomIds = node.roomId.split(',');
|
console.log("SKIASDJIOJSADIJASD", node.roomIds);
|
||||||
|
return;
|
||||||
if(roomIds.indexOf(msg.roomId) === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = event.getContent(),
|
let msg = {
|
||||||
msg = {};
|
content: event.getContent(),
|
||||||
|
type : (event.getContent().msgtype || event.getType()) || null,
|
||||||
|
payload : event.getContent().body || null,
|
||||||
|
sender : event.getSender(),
|
||||||
|
roomId : room.roomId,
|
||||||
|
eventId : event.getId(),
|
||||||
|
event : event,
|
||||||
|
};
|
||||||
|
|
||||||
msg.type = (content.msgtype || event.getType()) || null;
|
node.log("Received chat message [" + msg.type + "]: (" + room.name + ") " + event.getSender() + " :: " + msg.content.body);
|
||||||
msg.payload = event.getContent().body;
|
|
||||||
msg.sender = event.getSender();
|
|
||||||
msg.roomId = room.roomId;
|
|
||||||
msg.eventId = event.getId();
|
|
||||||
msg.event = event;
|
|
||||||
|
|
||||||
node.log("Received chat message [" + msg.type + "]: (" + room.name + ") " + event.getSender() + " :: " + event.getContent().body);
|
|
||||||
|
|
||||||
|
let knownMessageType = true;
|
||||||
switch(msg.type) {
|
switch(msg.type) {
|
||||||
case 'm.text':
|
case 'm.text':
|
||||||
if(node.ignoreText) return;
|
if(node.ignoreText) return;
|
||||||
@ -75,30 +70,34 @@ module.exports = function(RED) {
|
|||||||
|
|
||||||
case 'm.reaction':
|
case 'm.reaction':
|
||||||
if(node.ignoreReactions) return;
|
if(node.ignoreReactions) return;
|
||||||
msg.info = event.getContent()["m.relates_to"].info;
|
msg.info = msg.content["m.relates_to"].info;
|
||||||
msg.eventId = event.getContent()["m.relates_to"].event_id;
|
msg.referenceEventId = msg.content["m.relates_to"].event_id;
|
||||||
msg.payload = event.getContent()["m.relates_to"].key;
|
msg.payload = msg.content["m.relates_to"].key;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm.file':
|
case 'm.file':
|
||||||
if(node.ignoreFiles) return;
|
if(node.ignoreFiles) return;
|
||||||
msg.file = {
|
msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url);
|
||||||
info: event.getContent().info,
|
msg.mxc_url = msg.content.url;
|
||||||
url: node.server.matrixClient.mxcUrlToHttp(event.getContent().url)
|
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'm.image':
|
case 'm.image':
|
||||||
if(node.ignoreImages) return;
|
if(node.ignoreImages) return;
|
||||||
msg.image = {
|
msg.url = node.server.matrixClient.mxcUrlToHttp(msg.content.url);
|
||||||
info: event.getContent().info,
|
msg.mxc_url = msg.content.url;
|
||||||
url: node.server.matrixClient.mxcUrlToHttp(event.getContent().url),
|
msg.thumbnail_url = node.server.matrixClient.mxcUrlToHttp(msg.content.info.thumbnail_url);
|
||||||
thumbnail_url: node.server.matrixClient.mxcUrlToHttp(event.getContent().info.thumbnail_url)
|
msg.thumbnail_mxc_url = msg.content.info.thumbnail_url;
|
||||||
};
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
knownMessageType = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
node.send(msg);
|
if(knownMessageType) {
|
||||||
|
node.send(msg);
|
||||||
|
} else {
|
||||||
|
node.warn("Uknown message type: " + msg.type);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/html" data-help-name="matrix-send-file">
|
<script type="text/html" data-help-name="matrix-send-file">
|
||||||
<p>Send a message to a matrix room.</p>
|
<h3>Details</h3>
|
||||||
|
<p>This node will send a file to a Matrix chat room. Supports direct linking to a File In node.</p>
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
@ -87,9 +88,6 @@
|
|||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<h3>Details</h3>
|
|
||||||
<p>This node will send a file to a Matrix chat room. You can link this directly to a File In node.</p>
|
|
||||||
|
|
||||||
<h3>References</h3>
|
<h3>References</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types">MIME Types</a> - description of <code>msg.contentType</code> format</li>
|
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types">MIME Types</a> - description of <code>msg.contentType</code> format</li>
|
||||||
|
@ -41,6 +41,21 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(msg.content) {
|
||||||
|
node.server.matrixClient.sendMessage(msg.roomId, msg.content)
|
||||||
|
.then(function(e) {
|
||||||
|
node.log("File message sent: " + e);
|
||||||
|
msg.eventId = e.event_id;
|
||||||
|
node.send([msg, null]);
|
||||||
|
})
|
||||||
|
.catch(function(e){
|
||||||
|
node.warn("Error sending file message " + e);
|
||||||
|
msg.error = e;
|
||||||
|
node.send([null, msg]);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(!msg.payload) {
|
if(!msg.payload) {
|
||||||
node.error('msg.payload is required');
|
node.error('msg.payload is required');
|
||||||
return;
|
return;
|
||||||
|
@ -42,7 +42,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/html" data-help-name="matrix-send-image">
|
<script type="text/html" data-help-name="matrix-send-image">
|
||||||
<p>Send an image to a matrix room.</p>
|
<h3>Details</h3>
|
||||||
|
<p>This node will send an image to a Matrix chat room. You can link this directly to a File In node.</p>
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
@ -70,6 +71,11 @@
|
|||||||
<span class="property-type">String | Null</span>
|
<span class="property-type">String | Null</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd> this will be the display name the client will see when rendered in their chat client. If this is left empty the it uses <code>msg.filename</code>. If <code>msg.filename</code> is also undefined it sets it to empty string</dd>
|
<dd> this will be the display name the client will see when rendered in their chat client. If this is left empty the it uses <code>msg.filename</code>. If <code>msg.filename</code> is also undefined it sets it to empty string</dd>
|
||||||
|
|
||||||
|
<dt class="optional">msg.content
|
||||||
|
<span class="property-type">Object | Null</span>
|
||||||
|
</dt>
|
||||||
|
<dd> craft your own msg.content to send to the server. If defined then <code>msg.filename</code>, <code>msg.contentType</code>, <code>msg.body</code>, and <code>msg.payload</code> aren't required since the file already exists.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h3>Outputs</h3>
|
<h3>Outputs</h3>
|
||||||
@ -77,6 +83,9 @@
|
|||||||
<li>Success
|
<li>Success
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dd>original msg object preserved.</dd>
|
<dd>original msg object preserved.</dd>
|
||||||
|
|
||||||
|
<dt>msg.eventId <span class="property-type">string</span></dt>
|
||||||
|
<dd>the eventId from the posted message.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</li>
|
</li>
|
||||||
<li>Error
|
<li>Error
|
||||||
@ -86,12 +95,4 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<h3>Details</h3>
|
|
||||||
<p>This node will send an image to a Matrix chat room. You can link this directly to a File In node.</p>
|
|
||||||
|
|
||||||
<h3>References</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types">MIME Types</a> - description of <code>msg.contentType</code> format</li>
|
|
||||||
</ul>
|
|
||||||
</script>
|
</script>
|
@ -41,6 +41,21 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(msg.content) {
|
||||||
|
node.server.matrixClient.sendMessage(msg.roomId, msg.content)
|
||||||
|
.then(function(e) {
|
||||||
|
node.log("Image message sent: " + e);
|
||||||
|
msg.eventId = e.event_id;
|
||||||
|
node.send([msg, null]);
|
||||||
|
})
|
||||||
|
.catch(function(e){
|
||||||
|
node.warn("Error sending image message " + e);
|
||||||
|
msg.error = e;
|
||||||
|
node.send([null, msg]);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(!msg.payload) {
|
if(!msg.payload) {
|
||||||
node.error('msg.payload is required');
|
node.error('msg.payload is required');
|
||||||
return;
|
return;
|
||||||
@ -59,20 +74,22 @@ module.exports = function(RED) {
|
|||||||
rawResponse: (msg.rawResponse || false), // Return the raw body, rather than parsing the JSON.
|
rawResponse: (msg.rawResponse || false), // Return the raw body, rather than parsing the JSON.
|
||||||
type: msg.contentType, // Content-type for the upload. Defaults to file.type, or applicaton/octet-stream.
|
type: msg.contentType, // Content-type for the upload. Defaults to file.type, or applicaton/octet-stream.
|
||||||
onlyContentUri: false // Just return the content URI, rather than the whole body. Defaults to false. Ignored if opts.rawResponse is true.
|
onlyContentUri: false // Just return the content URI, rather than the whole body. Defaults to false. Ignored if opts.rawResponse is true.
|
||||||
}).then(function(file){
|
})
|
||||||
|
.then(function(file){
|
||||||
node.server.matrixClient
|
node.server.matrixClient
|
||||||
.sendImageMessage(msg.roomId, file.content_uri, {}, (msg.body || msg.filename) || "")
|
.sendImageMessage(msg.roomId, file.content_uri, {}, (msg.body || msg.filename) || "")
|
||||||
.then(function(imgResp) {
|
.then(function(e) {
|
||||||
node.log("Image message sent: " + imgResp);
|
node.log("Image message sent: " + e);
|
||||||
msg.eventId = e.eventId;
|
msg.eventId = e.event_id;
|
||||||
node.send([msg, null]);
|
node.send([msg, null]);
|
||||||
})
|
})
|
||||||
.catch(function(e){
|
.catch(function(e){
|
||||||
node.warn("Error sending image message " + e);
|
node.warn("Error sending image message " + e);
|
||||||
msg.matrixError = e;
|
msg.error = e;
|
||||||
node.send([null, msg]);
|
node.send([null, msg]);
|
||||||
});
|
});
|
||||||
}).catch(function(e){
|
})
|
||||||
|
.catch(function(e){
|
||||||
node.warn("Error uploading image message " + e);
|
node.warn("Error uploading image message " + e);
|
||||||
msg.matrixError = e;
|
msg.matrixError = e;
|
||||||
node.send([null, msg]);
|
node.send([null, msg]);
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
name: { value: null },
|
name: { value: null },
|
||||||
server: { value: "", type: "matrix-server-config" },
|
server: { value: "", type: "matrix-server-config" },
|
||||||
roomId: { value: null },
|
roomId: { value: null },
|
||||||
htmlMessage: { value: false }
|
messageType: { value: 'm.text' },
|
||||||
|
messageFormat: { value: '' },
|
||||||
},
|
},
|
||||||
label: function() {
|
label: function() {
|
||||||
return this.name || "Send Message";
|
return this.name || "Send Message";
|
||||||
@ -33,14 +34,27 @@
|
|||||||
<input type="text" id="node-input-roomId">
|
<input type="text" id="node-input-roomId">
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<input
|
<label for="node-input-messageType">
|
||||||
type="checkbox"
|
Message Type
|
||||||
id="node-input-htmlMessage"
|
|
||||||
style="width: auto; margin-left: 125px; vertical-align: top"
|
|
||||||
/>
|
|
||||||
<label for="node-input-htmlMessage" style="width: auto">
|
|
||||||
HTML/Markdown message
|
|
||||||
</label>
|
</label>
|
||||||
|
<select id="node-input-messageType">
|
||||||
|
<option value="m.text">m.text</option>
|
||||||
|
<option value="m.notice">m.notice</option>
|
||||||
|
<option value="msg.type">msg.type input</option>
|
||||||
|
</select>
|
||||||
|
<div class="form-tips">
|
||||||
|
It's recommended to use m.notice for bots because the message will render in a lighter text (at least in Element client) for users to distinguish bot and real user messages.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-row">
|
||||||
|
<label for="node-input-messageFormat">
|
||||||
|
Message Format
|
||||||
|
</label>
|
||||||
|
<select id="node-input-messageFormat">
|
||||||
|
<option value="">Default (plaintext)</option>
|
||||||
|
<option value="html">HTML</option>
|
||||||
|
<option value="msg.format">msg.format input</option>
|
||||||
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-tips">
|
<div class="form-tips">
|
||||||
Must be a valid <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank">MIME Type</a>
|
Must be a valid <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank">MIME Type</a>
|
||||||
@ -48,34 +62,35 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/html" data-help-name="matrix-send-message">
|
<script type="text/html" data-help-name="matrix-send-message">
|
||||||
<p>Send an image to a matrix room.</p>
|
<h3>Details</h3>
|
||||||
|
<p>Sends a message to a Matrix room.</p>
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
<h3>Inputs</h3>
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dt>msg.payload
|
<dt>msg.payload
|
||||||
<span class="property-type">File | String | Buffer | ReadStream | Blob</span>
|
<span class="property-type">String</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd> the contents of the image to upload. </dd>
|
<dd> the message text. </dd>
|
||||||
|
|
||||||
|
<dt class="optional">msg.formatted_payload
|
||||||
|
<span class="property-type">String</span>
|
||||||
|
</dt>
|
||||||
|
<dd> the formatted HTML message (uses msg.payload if not defined). This only affects HTML messages.</dd>
|
||||||
|
|
||||||
<dt>msg.roomId
|
<dt>msg.roomId
|
||||||
<span class="property-type">String | Null</span>
|
<span class="property-type">String | Null</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd> Room ID to send image to. Optional if configured on the node. Overrides node configuration if set.</dd>
|
<dd> Room ID to send image to. Optional if configured on the node. Overrides node configuration if set.</dd>
|
||||||
|
|
||||||
<dt class="optional">msg.filename
|
<dt class="optional">msg.type
|
||||||
<span class="property-type">String | Null</span>
|
<span class="property-type">String | Null</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd> name of the image file to upload (optional). Overrides node configuration.</dd>
|
<dd> This is only used and required when configured so on the node. Must be set to either 'm.text' or 'm.notice'</dd>
|
||||||
|
|
||||||
<dt class="optional">msg.contentType
|
<dt class="optional">msg.format
|
||||||
<span class="property-type">String | Null</span>
|
<span class="property-type">String | Null</span>
|
||||||
</dt>
|
</dt>
|
||||||
<dd> Content <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types" target="_blank">MIME Type</a>. Optional if configured on the node. Overrides node configuration if set.</dd>
|
<dd> This is only used and required when configured so on the node. Set to null for plain text and 'html' for HTML.</dd>
|
||||||
|
|
||||||
<dt class="optional">msg.body
|
|
||||||
<span class="property-type">String | Null</span>
|
|
||||||
</dt>
|
|
||||||
<dd> this will be the display name the client will see when rendered in their chat client. If this is left empty the it uses <code>msg.filename</code>. If <code>msg.filename</code> is also undefined it sets it to empty string</dd>
|
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
<h3>Outputs</h3>
|
<h3>Outputs</h3>
|
||||||
@ -83,6 +98,9 @@
|
|||||||
<li>Success
|
<li>Success
|
||||||
<dl class="message-properties">
|
<dl class="message-properties">
|
||||||
<dd>original msg object preserved.</dd>
|
<dd>original msg object preserved.</dd>
|
||||||
|
|
||||||
|
<dt>msg.eventId <span class="property-type">string</span></dt>
|
||||||
|
<dd>the eventId from the posted message.</dd>
|
||||||
</dl>
|
</dl>
|
||||||
</li>
|
</li>
|
||||||
<li>Error
|
<li>Error
|
||||||
@ -92,12 +110,4 @@
|
|||||||
</dl>
|
</dl>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<h3>Details</h3>
|
|
||||||
<p>This node will send an image to a Matrix chat room. You can link this directly to a File In node.</p>
|
|
||||||
|
|
||||||
<h3>References</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types">MIME Types</a> - description of <code>msg.contentType</code> format</li>
|
|
||||||
</ul>
|
|
||||||
</script>
|
</script>
|
@ -7,7 +7,44 @@ module.exports = function(RED) {
|
|||||||
this.name = n.name;
|
this.name = n.name;
|
||||||
this.server = RED.nodes.getNode(n.server);
|
this.server = RED.nodes.getNode(n.server);
|
||||||
this.roomId = n.roomId;
|
this.roomId = n.roomId;
|
||||||
this.htmlMessage = n.htmlMessage;
|
this.messageType = n.messageType;
|
||||||
|
this.messageFormat = n.messageFormat;
|
||||||
|
|
||||||
|
// taken from https://github.com/matrix-org/synapse/blob/master/synapse/push/mailer.py
|
||||||
|
this.allowedTags = [
|
||||||
|
"font", // custom to matrix for IRC-style font coloring
|
||||||
|
"del", // for markdown
|
||||||
|
// deliberately no h1/h2 to stop people shouting.
|
||||||
|
"h3",
|
||||||
|
"h4",
|
||||||
|
"h5",
|
||||||
|
"h6",
|
||||||
|
"blockquote",
|
||||||
|
"p",
|
||||||
|
"a",
|
||||||
|
"ul",
|
||||||
|
"ol",
|
||||||
|
"nl",
|
||||||
|
"li",
|
||||||
|
"b",
|
||||||
|
"i",
|
||||||
|
"u",
|
||||||
|
"strong",
|
||||||
|
"em",
|
||||||
|
"strike",
|
||||||
|
"code",
|
||||||
|
"hr",
|
||||||
|
"br",
|
||||||
|
"div",
|
||||||
|
"table",
|
||||||
|
"thead",
|
||||||
|
"caption",
|
||||||
|
"tbody",
|
||||||
|
"tr",
|
||||||
|
"th",
|
||||||
|
"td",
|
||||||
|
"pre",
|
||||||
|
];
|
||||||
|
|
||||||
if (!node.server) {
|
if (!node.server) {
|
||||||
node.warn("No configuration node");
|
node.warn("No configuration node");
|
||||||
@ -25,7 +62,26 @@ module.exports = function(RED) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
node.on("input", function (msg) {
|
node.on("input", function (msg) {
|
||||||
if (! node.server || ! node.server.matrixClient) {
|
let msgType = node.messageType,
|
||||||
|
msgFormat = node.messageFormat;
|
||||||
|
|
||||||
|
if(msgType === 'msg.type') {
|
||||||
|
if(!msg.type) {
|
||||||
|
node.error("Message type is set to be passed in via msg.type but was not defined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msgType = msg.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(msgFormat === 'msg.format') {
|
||||||
|
if(!msg.format) {
|
||||||
|
node.error("Message format is set to be passed in via msg.format but was not defined");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
msgFormat = msg.format;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!node.server || !node.server.matrixClient) {
|
||||||
node.warn("No matrix server selected");
|
node.warn("No matrix server selected");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -46,31 +102,27 @@ module.exports = function(RED) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.htmlMessage) {
|
let content = {
|
||||||
node.server.matrixClient.sendHtmlMessage(msg.roomId, msg.payload.toString(), msg.payload.toString())
|
msgtype: msgType,
|
||||||
.then(function(e) {
|
body: msg.payload.toString()
|
||||||
node.log("Message sent: " + msg.payload);
|
};
|
||||||
msg.eventId = e.eventId;
|
|
||||||
node.send([msg, null]);
|
if(msgFormat === 'html') {
|
||||||
})
|
content.format = "org.matrix.custom.html";
|
||||||
.catch(function(e){
|
content.formatted_body = msg.formatted_payload || msg.payload;
|
||||||
node.warn("Error sending message " + e);
|
|
||||||
msg.matrixError = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
node.server.matrixClient.sendTextMessage(msg.roomId, msg.payload.toString())
|
|
||||||
.then(function(e) {
|
|
||||||
node.log("Message sent: " + msg.payload);
|
|
||||||
msg.eventId = e.eventId;
|
|
||||||
node.send([msg, null]);
|
|
||||||
})
|
|
||||||
.catch(function(e){
|
|
||||||
node.warn("Error sending message " + e);
|
|
||||||
msg.matrixError = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
node.server.matrixClient.sendMessage(msg.roomId, content)
|
||||||
|
.then(function(e) {
|
||||||
|
node.log("Message sent: " + msg.payload);
|
||||||
|
msg.eventId = e.eventId;
|
||||||
|
node.send([msg, null]);
|
||||||
|
})
|
||||||
|
.catch(function(e){
|
||||||
|
node.warn("Error sending message " + e);
|
||||||
|
msg.error = e;
|
||||||
|
node.send([null, msg]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
RED.nodes.registerType("matrix-send-message", MatrixSendImage);
|
RED.nodes.registerType("matrix-send-message", MatrixSendImage);
|
||||||
|
@ -1,78 +0,0 @@
|
|||||||
<script type="text/javascript">
|
|
||||||
RED.nodes.registerType('matrix-send',{
|
|
||||||
category: 'matrix',
|
|
||||||
color: '#00b7ca',
|
|
||||||
icon: "matrix.png",
|
|
||||||
outputLabels: ["success", "error"],
|
|
||||||
inputs:1,
|
|
||||||
outputs:2,
|
|
||||||
defaults: {
|
|
||||||
name: { value: null },
|
|
||||||
matrixServer: { value: "", type: "matrix-server-config" },
|
|
||||||
room: { value: null }
|
|
||||||
},
|
|
||||||
label: function() {
|
|
||||||
return this.name || "matrix-send";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/html" data-template-name="matrix-send">
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-name"><i class="icon-tag"></i> Name</label>
|
|
||||||
<input type="text" id="node-input-name" placeholder="Name">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-matrixServer"><i class="fa fa-user"></i> Matrix Server Config</label>
|
|
||||||
<input type="text" id="node-input-matrixServer">
|
|
||||||
</div>
|
|
||||||
<div class="form-row">
|
|
||||||
<label for="node-input-roomId"><i class="fa fa-user"></i> Room ID</label>
|
|
||||||
<input type="text" id="node-input-roomId">
|
|
||||||
</div>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/html" data-help-name="matrix-send">
|
|
||||||
<p>Send a message to a matrix room.</p>
|
|
||||||
|
|
||||||
<h3>Inputs</h3>
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>payload
|
|
||||||
<span class="property-type">string</span>
|
|
||||||
</dt>
|
|
||||||
<dd> the payload of the message to publish. </dd>
|
|
||||||
<dt class="optional">topic <span class="property-type">string</span></dt>
|
|
||||||
<dd> the Matrix room ID to send the message to. Setting it will override the room ID configured on the node.</dd>
|
|
||||||
</dl>
|
|
||||||
|
|
||||||
<h3>Outputs</h3>
|
|
||||||
<ol class="node-ports">
|
|
||||||
<li>Standard output
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>payload <span class="property-type">string</span></dt>
|
|
||||||
<dd>the standard output of the command.</dd>
|
|
||||||
</dl>
|
|
||||||
</li>
|
|
||||||
<li>Standard error
|
|
||||||
<dl class="message-properties">
|
|
||||||
<dt>payload <span class="property-type">string</span></dt>
|
|
||||||
<dd>the standard error of the command.</dd>
|
|
||||||
</dl>
|
|
||||||
</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<h3>Details</h3>
|
|
||||||
<p><code>msg.payload</code> is used as the payload of the published message.
|
|
||||||
If it contains an Object it will be converted to a JSON string before being sent.
|
|
||||||
If it contains a binary Buffer the message will be published as-is.</p>
|
|
||||||
<p>The topic used can be configured in the node or, if left blank, can be set
|
|
||||||
by <code>msg.topic</code>.</p>
|
|
||||||
<p>Likewise the QoS and retain values can be configured in the node or, if left
|
|
||||||
blank, set by <code>msg.qos</code> and <code>msg.retain</code> respectively.</p>
|
|
||||||
|
|
||||||
<h3>References</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a>Twitter API docs</a> - full description of <code>msg.tweet</code> property</li>
|
|
||||||
<li><a>GitHub</a> - the nodes github repository</li>
|
|
||||||
</ul>
|
|
||||||
</script>
|
|
@ -1,175 +0,0 @@
|
|||||||
module.exports = function(RED) {
|
|
||||||
function MatrixSendMessage(n) {
|
|
||||||
RED.nodes.createNode(this, n);
|
|
||||||
|
|
||||||
var node = this;
|
|
||||||
|
|
||||||
this.name = n.name;
|
|
||||||
this.server = RED.nodes.getNode(n.matrixServer);
|
|
||||||
this.room = n.room;
|
|
||||||
|
|
||||||
if (!node.server) {
|
|
||||||
node.warn("No configuration node");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
||||||
|
|
||||||
node.server.on("disconnected", function(){
|
|
||||||
node.status({ fill: "red", shape: "ring", text: "disconnected" });
|
|
||||||
});
|
|
||||||
|
|
||||||
node.server.on("connected", function() {
|
|
||||||
node.status({ fill: "green", shape: "ring", text: "connected" });
|
|
||||||
|
|
||||||
// node.matrixClient.joinRoom(node.room, {syncRoom:false}) // should we really skip syncing the room?
|
|
||||||
// .then(function(joinedRoom) {
|
|
||||||
// node.log("Joined " + node.room);
|
|
||||||
// node.room = joinedRoom.roomId;
|
|
||||||
// node.updateConnectionState(true);
|
|
||||||
// }).catch(function(e) {
|
|
||||||
// node.warn("Error joining " + node.room + ": " + e);
|
|
||||||
// });
|
|
||||||
});
|
|
||||||
|
|
||||||
node.on("input", function (msg) {
|
|
||||||
if (! node.server || ! node.server.matrixClient) {
|
|
||||||
node.warn("No matrix server configuration");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!node.server.isConnected()) {
|
|
||||||
node.warn("Matrix server connection is currently closed");
|
|
||||||
node.send([null, msg]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg.payload) {
|
|
||||||
node.log("Sending message " + msg.payload);
|
|
||||||
|
|
||||||
if(!msg.roomId) {
|
|
||||||
msg.roomId = node.room;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!msg.roomId) {
|
|
||||||
node.warn("Room must be specified in msg.roomId or in configuration");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @todo add checks to make sure required properties are filled out instead of throwing an exception
|
|
||||||
switch(msg.type || null) {
|
|
||||||
case 'react':
|
|
||||||
/**
|
|
||||||
* React to another event (message)
|
|
||||||
* msg.roomId - required
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
node.server.matrixClient.sendCompleteEvent(
|
|
||||||
msg.roomId,
|
|
||||||
{
|
|
||||||
type: 'm.reaction',
|
|
||||||
content: {
|
|
||||||
"m.relates_to": {
|
|
||||||
event_id: msg.eventId,
|
|
||||||
"key": msg.payload,
|
|
||||||
"rel_type": "m.annotation"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(function(e) {
|
|
||||||
msg.eventId = e.event_id;
|
|
||||||
node.send([msg, null]);
|
|
||||||
})
|
|
||||||
.catch(function(e){
|
|
||||||
msg.matrixError = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'image':
|
|
||||||
node.server.matrixClient.uploadContent(
|
|
||||||
msg.image.content, {
|
|
||||||
name: msg.image.filename || null, // Name to give the file on the server.
|
|
||||||
rawResponse: (msg.rawResponse || false), // Return the raw body, rather than parsing the JSON.
|
|
||||||
type: msg.image.type, // Content-type for the upload. Defaults to file.type, or applicaton/octet-stream.
|
|
||||||
onlyContentUri: false // Just return the content URI, rather than the whole body. Defaults to false. Ignored if opts.rawResponse is true.
|
|
||||||
}).then(function(file){
|
|
||||||
node.server.matrixClient
|
|
||||||
.sendImageMessage(msg.roomId, file.content_uri, {}, msg.payload)
|
|
||||||
.then(function(imgResp) {
|
|
||||||
node.log("Image message sent: " + imgResp);
|
|
||||||
msg.eventId = e.eventId;
|
|
||||||
node.send([msg, null]);
|
|
||||||
})
|
|
||||||
.catch(function(e){
|
|
||||||
node.warn("Error sending image message " + e);
|
|
||||||
msg.matrixError = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
}).catch(function(e){
|
|
||||||
node.warn("Error uploading image message " + e);
|
|
||||||
msg.matrixError = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'file':
|
|
||||||
if(!msg.file) {
|
|
||||||
node.error('msg.file must be defined to send a file');
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!msg.file.type) {
|
|
||||||
node.error('msg.file.type must be set to a valid content-type header (i.e. application/pdf)');
|
|
||||||
}
|
|
||||||
|
|
||||||
node.server.matrixClient.uploadContent(
|
|
||||||
msg.file.content, {
|
|
||||||
name: msg.file.filename || null, // Name to give the file on the server.
|
|
||||||
rawResponse: (msg.rawResponse || false), // Return the raw body, rather than parsing the JSON.
|
|
||||||
type: msg.file.type, // Content-type for the upload. Defaults to file.type, or applicaton/octet-stream.
|
|
||||||
onlyContentUri: false // Just return the content URI, rather than the whole body. Defaults to false. Ignored if opts.rawResponse is true.
|
|
||||||
}).then(function(file){
|
|
||||||
const content = {
|
|
||||||
msgtype: 'm.file',
|
|
||||||
url: file.content_uri,
|
|
||||||
body: msg.payload,
|
|
||||||
};
|
|
||||||
node.server.matrixClient
|
|
||||||
.sendMessage(msg.roomId, content)
|
|
||||||
.then(function(imgResp) {
|
|
||||||
node.log("File message sent: " + imgResp);
|
|
||||||
msg.eventId = e.eventId;
|
|
||||||
node.send([msg, null]);
|
|
||||||
})
|
|
||||||
.catch(function(e){
|
|
||||||
node.warn("Error sending file message " + e);
|
|
||||||
msg.matrixError = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
}).catch(function(e){
|
|
||||||
node.warn("Error uploading file message " + e);
|
|
||||||
msg.matrixError = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: // default text message
|
|
||||||
node.server.matrixClient.sendTextMessage(msg.roomId, msg.payload.toString())
|
|
||||||
.then(function(e) {
|
|
||||||
node.log("Message sent: " + msg.payload);
|
|
||||||
msg.eventId = e.eventId;
|
|
||||||
node.send([msg, null]);
|
|
||||||
}).catch(function(e){
|
|
||||||
node.warn("Error sending message " + e);
|
|
||||||
msg.matrixError = e;
|
|
||||||
node.send([null, msg]);
|
|
||||||
});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
node.warn("msg.payload is empty");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
RED.nodes.registerType("matrix-send", MatrixSendMessage);
|
|
||||||
}
|
|
@ -79,7 +79,6 @@ module.exports = function(RED) {
|
|||||||
switch (state) {
|
switch (state) {
|
||||||
case "ERROR":
|
case "ERROR":
|
||||||
node.error("Connection to Matrix server lost");
|
node.error("Connection to Matrix server lost");
|
||||||
console.log(state, prevState, data);
|
|
||||||
node.setConnected(false);
|
node.setConnected(false);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user