Closed janvda closed 5 years ago
I'm having the same problem..
Same problem here. Also bots online status changes to "offline" in Slack. This seems to indicate some kind of connection problem.
I've coded up what I think will work around this for now. If it works, I'll put in a background task to do it automatically. For now it's a new node that you use like so :-
Inject timer (every 2 mins say) -> Slack Bot Keep Alive node
It outputs either true or false depending on if the connection was still alive, and if it's not, it reconnects it.
Thanks for the workaround. I'll take a look this week and might redesign the whole thing to use webhooks VS the current web sockets
@shanness I have tried the work around with the Slack Bot Keep Alive
node but it is not working. Have you checked that this is working ?
E.g. this is what I see in my node-RED log file:
[Sat Dec 15 2018 17:43:18 GMT+0100 (CET)] ERROR Last pong is too old: 14.7
[Sat Dec 15 2018 17:43:18 GMT+0100 (CET)] INFO Reconnecting in 1000ms
[Sat Dec 15 2018 17:43:19 GMT+0100 (CET)] INFO Attempting reconnect
[Sat Dec 15 2018 17:43:19 GMT+0100 (CET)] INFO Connecting...
15 Dec 17:43:20 - [info] [Slack Bot In:stemija slackbot] in: Logged in:
15 Dec 17:44:00 - [info] [Slack Bot Keep Alive:stemija keep alive] KEEP ALIVE : Reconencting to Slack.
15 Dec 17:44:00 - [info] [Slack Bot Keep Alive:stemija keep alive] Slack disconnecting...
15 Dec 17:44:00 - [info] [Slack Bot Keep Alive:stemija keep alive] Slack already connected
15 Dec 17:45:00 - [info] [Slack Bot Keep Alive:stemija keep alive] Keep alive called before other bot nodes initialised
15 Dec 17:46:00 - [info] [Slack Bot Keep Alive:stemija keep alive] Keep alive called before other bot nodes initialised
15 Dec 17:47:00 - [info] [Slack Bot Keep Alive:stemija keep alive] Keep alive called before other bot nodes initialised
15 Dec 17:48:00 - [info] [Slack Bot Keep Alive:stemija keep alive] Keep alive called before other bot nodes initialised
15 Dec 17:49:00 - [info] [Slack Bot Keep Alive:stemija keep alive] Keep alive called before other bot nodes initialised
15 Dec 17:50:00 - [info] [Slack Bot Keep Alive:stemija keep alive] Keep alive called before other bot nodes initialised
One problem is that the slackReconnect()
function always says that Slack already connected
while this is most likely because the slackLogOut() function is deleting the ojbect slackBotGlobal[token]
which is checked in line 29 of the slackLogin()
function.
Moreover I am also doubting that fixing the slackReconnect()
would make that after successful reconnect that the slack on message handler (line 82) is still registered.
Hey @janvda. I just got my first "Reconnecting" today actually (been doing lots of node-red dev, so hasn't triggered till today). I didn't write the slackReconnect, just call it as it was called in the out node. But agreed, it looks busted, seems to dump all the listeners and not reconnect them. I suspect it would just require making slackLogOut() return a copy of the listeners it removed, and re-setting them after slackLogIn() in the slackReconnect().
function slackReconnect(token, node) {
var handlers = slackLogOut(token, node);
slackLogin(token, node);
for ( int i = 0 ; i < handlers.length; i++ ) {
slackBotGlobal[token].on(handler.event,handler.funtionRef)
}
}
Or actually, on second thoughts, perhaps just call slackLogin() instead of reconnect (like the error handler does), that would hopefully just re-login.. I'll do that now. I've removed the slackReconnect function (only had two calls, and one was mine, both now just call slackLogin()). Just leaving above in case it's needed.
Fingers crossed this will fix it. Hard to know until it triggers again.. e7e922e4d657ff86970e9a7a86c9cf2798474e33
Got it fixed @janvda. See https://github.com/shanness/node-red-slack/commit/e8557203a2cd9987c2f2c72c3c4696f48141737d
Tested and working (after resetting slackBotState[token].connecting = false
before the slackLogin call
[Slack Bot Keep Alive:b516ad8b.50dc8] KEEP ALIVE : Reconencting to Slack. (false,true)
[Slack Bot Keep Alive:b516ad8b.50dc8] Slack not connected
INFO Connecting...
...1 second gap..
[Slack Bot In:cmd bot in] in: Logged in:
Figured out how to force disconnects (details in commit message).
sudo netstat -pn | grep node
find the "tcp 0 0 10.0.0.7:48670 13.54.39.212:443 ESTABLISHED 29167/node-red "
line (key is the :443), and run "sudo tcpkill port 48670" hitting Ctrl-C after a couple of
seconds. This will force a reconnect, which is now working :)
So now sends me one connection lost message to slack (using the webhook node), and the $help
shows it reconnected
cmd APP [4:35 AM] cmdbot lost connection, reconnecting : false !
craig [4:39 AM] $help
cmd APP [4:39 AM] Valid commands :-
$bounce [live|beta]
This implied it's could by run by a setInterval() function (with perhaps 30 second loops) without the need for the KeepAlive node :) I'll get onto that next, then this should be solid.
OK, this is all fixed. No longer needs the separate KeepAlive node, just does a 30 second interval timer per token. I'll leave it running for a while before squashing my commits into one and doing a PR.
For anyone that wants to assist with testing, pull this and replace the html and js files in ~/.node-red/node_modules/node-red-contrib-slack
with the ones from here.
https://github.com/shanness/node-red-slack
@shanness I have integrated your changes. No connection drops so far. Thanks a lot.
@shanness : There is an issue with the changes (https://github.com/shanness/node-red-slack/commit/2ec2ba41aec7e0258968dee2dd88d0ffe3cd7512). It seems to reconnect but now every slack message is received multiple times by the Slack Bot In
node. So today I am receiving every slack message 5 times !
FYI here some logs showing the reconnections:
20 Dec 00:05:56 - [info] [Slack Bot In:stemija slackbot] KEEP ALIVE : Reconencting to Slack. (false,true)
20 Dec 00:05:56 - [info] [Slack Bot In:stemija slackbot] Slack logging in ...
[Thu Dec 20 2018 00:05:56 GMT+0100 (CET)] INFO Connecting...
20 Dec 00:05:57 - [info] [Slack Bot In:stemija slackbot] in: Logged in:
20 Dec 00:41:57 - [info] [Slack Bot In:stemija slackbot] KEEP ALIVE : Reconencting to Slack. (false,true)
20 Dec 00:41:57 - [info] [Slack Bot In:stemija slackbot] Slack logging in ...
[Thu Dec 20 2018 00:41:57 GMT+0100 (CET)] INFO Connecting...
20 Dec 00:41:57 - [info] [Slack Bot In:stemija slackbot] in: Logged in:
20 Dec 00:43:27 - [info] [Slack Bot In:stemija slackbot] KEEP ALIVE : Reconencting to Slack. (false,true)
20 Dec 00:43:27 - [info] [Slack Bot In:stemija slackbot] Slack logging in ...
[Thu Dec 20 2018 00:43:27 GMT+0100 (CET)] INFO Connecting...
20 Dec 00:43:27 - [info] [Slack Bot In:stemija slackbot] in: Logged in:
20 Dec 00:49:57 - [info] [Slack Bot In:stemija slackbot] KEEP ALIVE : Reconencting to Slack. (false,true)
20 Dec 00:49:57 - [info] [Slack Bot In:stemija slackbot] Slack logging in ...
[Thu Dec 20 2018 00:49:57 GMT+0100 (CET)] INFO Connecting...
20 Dec 00:49:57 - [info] [Slack Bot In:stemija slackbot] in: Logged in:
20 Dec 00:57:27 - [info] [Slack Bot In:stemija slackbot] KEEP ALIVE : Reconencting to Slack. (false,true)
20 Dec 00:57:27 - [info] [Slack Bot In:stemija slackbot] Slack logging in ...
[Thu Dec 20 2018 00:57:27 GMT+0100 (CET)] INFO Connecting...
20 Dec 00:57:27 - [info] [Slack Bot In:stemija slackbot] in: Logged in:
@janvda sorry this is still an issue for you. Can you give me a rough idea of your use case?
@shanness
Maybe it is fixed now. I think I had another reconnect this morning (see below) without messages being received twice by the "Slack Bot In" node.
FYI I did 2 things:
var autoReconnect = false;
) as the reconnection will be done by the slackKeepAlive()
function.22 Dec 06:31:14 - [info] [Slack Bot In:stemija slackbot] KEEP ALIVE : Reconencting to Slack. (false,true) 22 Dec 06:31:14 - [info] [Slack Bot In:stemija slackbot] Slack logging in ... [Sat Dec 22 2018 06:31:14 GMT+0100 (CET)] INFO Connecting... 22 Dec 06:31:15 - [info] [Slack Bot In:stemija slackbot] in: Logged in:
@yayadrian the use case is pretty simple.
I have a node red flow that is handling any message that is posted on a channel of my slack work space that has been joined by my slack bot app. The Slack Bot In
node is used to receive those messages. This flow is also posting a response on the same channel using the Slack Bot Out
node.
@shanness
The 2 changes proposed 2 comments ago didn't fix the issue regarding the slack bot in
receiving every slack message multiple times. So today it received the slack bot in message 6 times (most likely due to several re-connections in the last days).
Hi @janvda, sorry for the delay, just back from holidays. Will have a look tomorrow to see if I can repeat your problem, unfortunately I restarted NR a few minutes before reading this, so will hopefully have a couple of reconnects by the morning.
Hey @janvda , I haven't been able to repeat this. Despite multiple reconnects, I'm only getting the messages once.
It happened again for me the 11th of January (I received the message 2 times) but on the 14th of January it is working again properly (message is only received once). I need to check log files (as I can't remember if I restarted node-red in that period).
Update: I only have the logs of the 16th Jan. So the relevant part is not available.
In the log of the 16th - I see following error but this seems not related to my problem regarding duplicate messages:
Trace
at Client.<anonymous> (/home/pi/.node-red/node_modules/node-red-contrib-slack/slackpost.js:125:21)
at emitOne (events.js:121:20)
at Client.emit (events.js:211:7)
at Client.onMessage (/home/pi/.node-red/node_modules/slack-client/src/client.js:481:21)
at WebSocket.<anonymous> (/home/pi/.node-red/node_modules/slack-client/src/client.js:149:24)
at emitTwo (events.js:126:13)
at WebSocket.emit (events.js:214:7)
at Receiver.ontext (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/WebSocket.js:816:10)
at /home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:477:18
at Receiver.applyExtensions (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:364:5)
at /home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:466:14
at Receiver.flush (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:340:3)
at Receiver.finish (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:482:12)
at Receiver.expectHandler (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:457:31)
at Receiver.add (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:95:24)
at TLSSocket.realHandler (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/WebSocket.js:800:20)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
at readableAddChunk (_stream_readable.js:250:11)
at TLSSocket.Readable.push (_stream_readable.js:208:10)
at TLSWrap.onread (net.js:597:20)
16 Jan 21:26:40 - [error] [Slack Bot In:stemija slackbot] Error: [object Object]
Trace
at Client.<anonymous> (/home/pi/.node-red/node_modules/node-red-contrib-slack/slackpost.js:245:21)
at emitOne (events.js:121:20)
at Client.emit (events.js:211:7)
at Client.onMessage (/home/pi/.node-red/node_modules/slack-client/src/client.js:481:21)
at WebSocket.<anonymous> (/home/pi/.node-red/node_modules/slack-client/src/client.js:149:24)
at emitTwo (events.js:126:13)
at WebSocket.emit (events.js:214:7)
at Receiver.ontext (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/WebSocket.js:816:10)
at /home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:477:18
at Receiver.applyExtensions (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:364:5)
at /home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:466:14
at Receiver.flush (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:340:3)
at Receiver.finish (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:482:12)
at Receiver.expectHandler (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:457:31)
at Receiver.add (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/Receiver.js:95:24)
at TLSSocket.realHandler (/home/pi/.node-red/node_modules/slack-client/node_modules/ws/lib/WebSocket.js:800:20)
at emitOne (events.js:116:13)
at TLSSocket.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
at readableAddChunk (_stream_readable.js:250:11)
at TLSSocket.Readable.push (_stream_readable.js:208:10)
at TLSWrap.onread (net.js:597:20)
16 Jan 21:26:40 - [error] [Slack Bot Out:stemija slackbot response] Error sending to Slack: {"msg":"slow down, too many messages...","code":-1,"source":"gs-fra-ak8g"}
Hmm, strange. Not sure what to suggest, except to figure out if you somehow have multiple open connections to slack. I only have one
craig@home:~$ sudo netstat -pn | grep ':443.*node-red'
tcp 0 0 10.0.0.7:49304 13.54.39.212:443 ESTABLISHED 6066/node-red
Despite quite a few reconnects (oops, I spelt that wrong in the log message).
Jan 16 16:16:46 home Node-RED[783]: 16 Jan 16:16:46 - [info] [Slack Bot In:cmd bot in] KEEP ALIVE : Reconencting to Slack. (false,true)
Jan 19 05:22:52 home Node-RED[6066]: 19 Jan 05:22:52 - [info] [Slack Bot In:cmd bot in] KEEP ALIVE : Reconencting to Slack. (false,true)
Jan 20 16:49:35 home Node-RED[6066]: 20 Jan 16:49:35 - [info] [Slack Bot In:cmd bot in] KEEP ALIVE : Reconencting to Slack. (false,true)
Jan 21 16:15:22 home Node-RED[6066]: 21 Jan 16:15:22 - [info] [Slack Bot In:cmd bot in] KEEP ALIVE : Reconencting to Slack. (false,true)
Jan 22 16:17:29 home Node-RED[6066]: 22 Jan 16:17:29 - [info] [Slack Bot In:cmd bot in] KEEP ALIVE : Reconencting to Slack. (false,true)
I have little traffic on my inbound, due to it being a command channel, but checked the NR logs, and there are no dupes received. Next time you get one, try running the above netstat command and see if you somehow have multiple sockets connected.
@yayadrian I've squashed my stuff into one commit, would be good to have someone else test it to see if they have the issue janvda does. It's been working perfectly for me since this change.
@yayadrian I'd be happy to modernize some of the code base and clean up this along with several other issues (update to latest client, using credentials instead of normal settings, use proper configuration nodes, etc) if you'd be willing to accept an MR. It would break current setups though (particularly moving configuration to credentials and using proper config nodes)...any interest?
@travisghansen Yep I would be happy to take a look. I started on a new version but time was short and I haven't got far.
@yayadrian yeah, I took the liberty to rewrite everything and I have a really solid foundation now. inputs/outputs are quite different but I've implemented full usage of the 'Web' API (ie: you can invoke any method you want generically) and the 'RTM' listens to all events, not just incoming messages (ie: you can see reaction events, channel updates, etc, etc, etc).
I've added node statues so you can see when it's connected and loses connection and when activity is in place. Observing such, I've bee able to cut connectivity and watch the nodes go to 'disconnected' state and subsequently automatically return when connectivity was restored and go to a 'connected' state. I really like where it's headed.
Given the massive overhaul of config/inputs/outputs I'm still not sure whether you'd like to keep it in this repo. I'd love to keep it here as I feel this is pretty much the de-facto package but I'm happy to publish as something else altogether if you're not comfortable with it. If you want to proceed it's definitely a 'major' version bump for semver.
If we do move forward it will close nearly all the 'issues' in this repo (although I'm sure it'll add new ones). The code is however quite concise and has pretty small surface for error.
MR #22
@janvda or @shanness would either of you be willing to install the rewrite referenced above and let me know if you're still seeing connection issues? I've pretty much completed the functionality and have had it running for several days now so it should be stable. I've tested several reconnect scenarios and it's always reconnected perfectly.
Hey @travisghansen, sure, happy to test. I'm having a problem though.
[node-red-contrib-slack/slack] Error: Cannot find module '@slack/client'
Because of this
"dependencies": {
"@slack/client": "^4.9.0"
}
(which used to be
"slack-client": "^1.4.0"
Pardon my ignorance about how to fix it, basically I've just changed the files in the installed package to symlinks to yours, which is breaking me restarting node-red.
craig@home:~/.node-red/node_modules/node-red-contrib-slack$ ltr
total 20
-rw-rw-r-- 1 craig craig 1105 Jan 24 2017 LICENSE
lrwxrwxrwx 1 craig craig 73 Mar 1 17:55 package.json -> /home/craig/apps/node-red-stuff/node-red-slack_travisghansen/package.json
lrwxrwxrwx 1 craig craig 70 Mar 1 17:56 README.md -> /home/craig/apps/node-red-stuff/node-red-slack_travisghansen/README.md
lrwxrwxrwx 1 craig craig 73 Mar 1 17:56 slackpost.js -> /home/craig/apps/node-red-stuff/node-red-slack_travisghansen/slackpost.js
lrwxrwxrwx 1 craig craig 75 Mar 1 17:56 slackpost.html -> /home/craig/apps/node-red-stuff/node-red-slack_travisghansen/slackpost.html
@shanness not sure if this will work with what you've done but we'll try it first. Just go into the new folder and run npm install
which should install all the deps.
Hmm, when I did it from that directory, it created another node_modules dir in it (which is itself already in a node_modules dir). And that didn't fix it. Moving @slack
from ~/.node-red/node_modules/node-red-contrib-slack/node_modules
to ~/.node-red/node_modules/
didn't help either.
I then did the npm install
from ~/.node-red
, and it reset node-red-contrib-slack
to the package version :(
Any idea how to install a non npm version of something to node red (i.e. from github like yours?)
i.e. this is what I got after the last npm install
craig@home:~/.node-red/node_modules/node-red-contrib-slack$ ls -ltr
total 32
-rw-rw-r-- 1 craig craig 8650 Jan 24 2017 slackpost.js
-rw-rw-r-- 1 craig craig 6189 Jan 24 2017 slackpost.html
-rw-rw-r-- 1 craig craig 2461 Jan 24 2017 README.md
-rw-rw-r-- 1 craig craig 1105 Jan 24 2017 LICENSE
Sorry, I'm a coder, but not a JS coder, and don't know npm really.
Doh, should have read the man page for npm install
it was just a matter of doing
npm install https://github.com/travisghansen/node-red-slack
from the ~/.node-red
directory.
That seems to have gotten it working. It's not very backwards compatible though, channel isn't in the dialog (yet?), and the inbound messages aren't strings in msg.payload (instead it's an object) But that's probably a good thing, just gotta fix my nodes (it's a pretty breaking change though, requiring a lot of re-writing of my functions).
Also, seems I need to set msg.topic = "message"
and keep the msg.payload.channel
(id) and set output text in msg.payload.text
. It crashes with slack-rtm-out:b3de6698.41d428] TypeError: Cannot read property '0' of undefined
if msg.topic
isn't set, because of this line
if (method[0] == "@" || method[0] == "#") {
And crashes with the same error if msg.payload.channel
isn't set but msg.topic
is set to message
Looking good though so far. Will update when I have it working properly, just wanted to let you know I've got it running.
OK, finally got it all working. Apart from the problems above, the I can't seem to send attachments like I used to. Used to do this :- Now it just posts this
I was using the outbound webhook for sending the former.
@shanness the interface has changed quite a bit (it would be easy to mimic previous behavior with a simple function node in front of the output node). In order to do complex messages you need to send the following to the slack-web-out
(not the slack-rtm-out
) node:
set msg.topic
to chat.postMessage
set msg.payload
to the same structure as found here: https://api.slack.com/methods/chat.postMessage
ignore the token
property and channel
will intelligently handle @
or #
channel names so you don't need to use the acutal channel id.
Let me know if that helps. Thanks for trying it out!
Cool, all working, thanks. For the record, the problem was that the old API used msg.attachments
, and the new one uses msg.payload.attachments
. I like it! Much nicer using the slack JS payload :)
I'll let you know how well it stays connected :) Thanks for your hard work! I think it's worth checking the topic (and channel) is set rather than giving the TypeError: Cannot read property '0' of undefined
with no stack trace for users to try to debug. Then you can throw a specific error.
Yeah thanks for the feedback. I ran into that myself and mostly my thought has been pass through errors from slack directly...but that's clearly not even making it to slack so I'll rethink that a little.
@shanness just noticed you're earlier comment about backward compatibility etc. That's essentially what I was stating earlier in the thread is I don't really have any intention of making it backwards compatible. As it is it supports the fullness of slack's API which the other simply didn't do so it's much more generic (and powerful) now (which is why channel isn't an option at the node level as some API calls don't require it). It would be pretty easy for someone to front the output nodes with a simple function to replicate whatever the previous behavior was or do generally whatever custom stuff is wanted/needed. I have for example already made some nodes to handle sending /me
messages from the bot (https://api.slack.com/methods/chat.meMessage). To do so I created a simple function node in front of the slack-web-out
node to simplify the 'API' to send a /me
message (ie: setting topic to chat.meMessage
and building the appropriate msg.payload
using the old topic as the channel
property and the old payload as the text
property).
I haven't updated the documentation yet but the general idea is:
@
or #
then it's assumed you're trying to send a message and the payload should be a string. The output node (web or rtm) automatically handles sending a simple message.msg.slackState
object which has several properties containing the lists of users/channels/bot/team info/etc so downstream nodes can do 'lookups' without re-hitting the API (this data is currently refreshed in the background every 10 minutes)msg.payload
of the output side is the direct passthrough/response from the rtm/web invocation. However, to make things easier, before passing it through we traverse the response and set fooObject
properties for channel/user/bot/etc (basically doing lookups from slackState
for you) to make it easier to assert/switch/whatever based off of username/real name/etc instead of internal slack IDs.As an example of that last point, the user_typing
event (https://api.slack.com/events/user_typing) of the slack-rtm-in
node produces:
{
"type": "user_typing",
"channel": "...",
"user": "...",
"channelObject": {
"id": "...",
"name": "...",
"is_channel": true,
"is_group": false,
"is_im": false,
"created": 1434735155,
...
},
"userObject": {
"id": "...",
"name": "...",
"real_name": "...",
...
}
}
instead of just:
{
"type": "user_typing",
"channel": "...",
"user": "..."
}
All of the lookups are done dynamically/generically so regardless of what API response you get if the node finds a property that appears to be a user
in some shape or form, it creates <property>Object
attribute with the user lookup value. For example, in some of my messages I've seen bot_idObject
getting created, but if it found a property called bot
it would add botObject
etc. Ultimately it's doing all the lookups from slackState
so it could be done on your own but it's added to simplify.
Hopefully that helps clear things up a little bit and provides some insight into the design. I'll document all of it once everyone gives the metaphorical nod to the interface/decisions.
Hey @travisghansen , Yep, worked most of that out by looking at the code and output :) Nice work. Do you know if there is info about who is online? Would be useful, but the members in the slackState doesn't seem to have it. And yep, I agree not making it backwards compatible, would be messy and not the way forward.
@shanness yeah slack calls it presence
. Depending on your needs there are 2 approaches.
The former would be a '1 shot' approach on an as-needed basis looking for a particular/known user.
The latter would subscribe you to the stream of events which would show up on all slack-rtm-in
nodes. You won't receive the presence details on the output side of the request directly.
If you want to watch the whole team for example I would put a trigger node on some time interval of 10+ minutes in front of the slack-state
node to emit the current state. Put a function node on the other side to iterate the users and build up the list of ids
. Set msg.topic
to presence_sub
and set msg.payload
to { ids: list_from_iteration }
and push the result to the/a slack-rtm-out
node. From then on your slack-rtm-in
nodes will start receiving events with type: "presence_change"
.
I personally have a switch node right after the slack-rtm-in
node to divide appropriately based on the type
.
It may be a good idea for us to watch that event ourself and add the data to slack state. I wouldn't automatically subscribe but if the user/flow has subscribed then go ahead and start tracking it in the internal state so it's more accessible.
Edit: technically there is also https://api.slack.com/events/presence_query but it seems a waste of time in this context but it would be available.
@shanness ok, I've pushed another fairly large update. All state
data has been updated to use hash maps so lookups can be done via key instead of traversing a list (array). The state
node also added a second output that pushes events (currently only the ready
event) which you can key on to trigger presence subscriptions after the state
has been initialized on startup. The state
also now tracks presence
and dnd
data. presence
data is only tracked if the user/flow subscribes to presence events. I've also worked out all the events (I think) which will update state based on server-side events instead of needing to poll state every 10 minutes (which is still enabled).
Lastly, I've updated the general appearance of the nodes (updated color, icons, alignment, etc) to match guidelines and modernize.
Enjoy! Let me know how things look for you.
@travisghansen , Thanks for taking up this challenge. I am currently struggling with the new API that is not backwards compatible. I fully understand that you are breaking backwards compatibility, but it would be good to describe how the people can migrate there existing flows to the new API : I haven't got a clue if I need to use "slack web out" or "slack rtm out" instead of the former "slack out" node. At the moment my node-red application is not working and I am figuring out what I need to do.
It would be good to give some examples what the incoming payload could be for the different nodes. I have also no clue how I can receive messages posted on a certain slack channel and how I can best generate a response in the same channel.
.... after some struggling, I am gradually figuring out how to use the new API. One of the things I still need to figure out is how I can change the user (currently it is "bot") when posting a message with slack rtm out in a channel.
@janvda yeah thanks for your patience and taking the time to test it out! All of the documentation is the slack API documentation for requests/responses. For the slack-web-out
node here: https://api.slack.com/methods and for the slack-rtm-in/out
nodes here: https://api.slack.com/rtm
msg.topic
is the function/method name, msg.payload
is the params/args (for -out
nodes). The slack-rtm-in
node listens to all events and passes the event
payload on directly as msg.payload
(with some niceties added from msg.slackState
added as <foo>Object
properties. Click on any of the events from the rtm link above and you'll see the expected responses.
Using slack-rtm-out
for sending messages should only be used for very basic stuff, just assume using the slack-web-out
for anything beyond the simplest messaging use-case.
In order to mimic the previous outbound API try putting a function node like this in front of a slack-web-out
node...it should effectively mimic previous behavior 100%, just point your old-style outputs to the function node:
// https://api.slack.com/methods/chat.postMessage
msg.topic = "chat.postMessage"
var payload = {
text: msg.payload
};
if (msg.emojiIcon) {
payload.icon_emoji = msg.emojiIcon;
}
if (msg.channel) {
payload.channel = msg.channel
} else {
payload.channel = "#your_default_channel_set_on_node_previously"
}
if (msg.username) {
payload.username = msg.username;
payload.as_user = false;
}
if (msg.attachments) {
payload.attachments = msg.attachments;
}
msg.payload = payload;
return msg;
For inbound node try putting a function node like this after a slack-rtm-in
node. From what I can tell it will mimic the old inbound node 100% as well:
// https://api.slack.com/events/message
if (msg.payload.type != "message") {
return null;
}
// if you only want to watch a specific channel put name here
var channel = "";
if (channel && msg.payload.channelObject.name != channel.replace(/^@/, "").replace(/^#/, "")) {
return null;
}
var payload = "";
if (msg.payload.text) {
payload += msg.payload.text;
}
if (msg.payload.attachments) {
if (payload) {
payload += "\n";
}
msg.payload.attachments.forEach((attachment, index) => {
if (index > 0) {
payload += "\n";
}
payload += attachment.fallback;
})
}
var slackObj = {
id: msg.payload.client_msg_id,
type: msg.payload.type,
text: msg.payload.text,
channelName: msg.payload.channelObject.name,
channel: msg.payload.channelObject,
fromUser: (msg.payload.userObject) ? msg.payload.userObject.name : "",
attachments: msg.payload.attachments
};
msg = {
payload: payload,
slackObj: slackObj
}
return msg;
I don't have the old nodes installed anymore so I may have something off a little. If you still have them installed and want to send some examples over I can compare a little better.
Let me know how they work and I'll keep them updated and add them to the eventual documentation as transition examples.
@janvda I just noticed your comment about responding to messages in channels. Here's an example function node to put between a slack-rtm-in
node and a slack-web-out
node:
// ignore anything but messages
if (msg.payload.type != "message") {
return null;
}
// ignore deleted messages
if (msg.payload.subtype == "message_deleted") {
return null;
}
// ignore messages from bots
if (msg.payload.bot_id || msg.payload.userObject.is_bot) {
return null;
}
// if you only want to watch a specific channel put name here
var channel = "";
if (channel && msg.payload.channelObject.name != channel.replace(/^@/, "").replace(/^#/, "")) {
return null;
}
// only specific users
var username = "";
if (username && msq.payload.userObject.name.replace(/^@/, "") != username) {
return null;
}
// check for keyword
// could use regex etc
if (!msg.payload.text.includes("keyword")) {
return null;
}
// prepare outbound response
var topic = "chat.postMessage";
var payload = {
channel: msg.payload.channel, // respond to same channel
//text: '<@' + msg.payload.userObject.name + '>, thanks for chatting',
text: '<@' + msg.payload.user + '>, thanks for chatting',
//as_user: false,
//username: "",
//attachments: [],
//icon_emoji: "",
}
msg = {
topic: topic,
payload: payload
}
return msg;
@travisghansen thanks a lot for sharing this. It will definitely help me. I will have a look at it later. I also think it would be good to enable "issues" on your node-red-slack repository (that is also the fork that I have cloned) so we can raise any issues there before they are integrated in this repository. One of the things I think you still need to do is changing the version from 1.2.0 to 2.0.0.
@janvda yeah no problem. Although the version is currently 0.1.2
I think it's probably best to bump to 2.0.0
when it's ready to publish like you mentioned. I've gone ahead and enabled issues there but I prefer to keep this work as 'upstream' as possible.
Regarding documentation, I think I can start working on that now, I feel like things have settled enough in the interfaces that it's probably about what it will be. I'll work on the README and the integrated documentation (as seen in the Node-RED interface) and start pushing those up.
All of my testings so far has been successful. There is clearly a big change required so we should differently bump to 2.0 when ready.
Given that the slackState
object is now indexed do we think we should still be adding the <foo>Object
properties to the msg.payload
for convenience or should we strip them to be more concise?
@travisghansen From a users point of view, I think I would go with stripping them out to keep it concise. I'm not sure if there are performance benefits around doing this.
@yayadrian probably very little in the way of performance. It is handy but entirely possible to operate without them. For example, I haven't tested if a switch
node let's you put something like slackState.members[msg.payload.user].name
. I'll give it a whirl and see what happens.
UPDATE: yeah Node-RED
switch
nodes don't like that. Being able to switch
on those properties is quite handy..
Of interest to the original issue: https://github.com/slackapi/node-slack-sdk/issues/710
I've pushed another commit with updated README.md
. It includes details about how to use the nodes and how to migrate from the current version. I'm not really a technical writer so any feedback is welcome. I'm interested to know if it's understandable and flows well.
In addition, I've updated the reconnect settings per the results discussed in the issue linked above. Hopefully that fully addresses any ongoing connection issues.
Thanks @travisghansen for the great work - I have migrated my flows. Will keep you posted.
Has anyone here been using a slack user
token (starts with xoxp-
) vs a bot
token (starts with xoxb-
)? I've been using a bot
token and want to make sure the new code at least semi works with a user
token. Subsequently I want to document the required scopes for user
tokens to work fully.
No, my token also starts with xoxb-
Thanks for the README update @travisghansen ! Nice work, explains it well. And yeah, I'm using a bot token for my stuff too.
Hi,
First and foremost my appreciation for these excellent slack nodes.
I am using these nodes for quite some time and the thing I noticed is that after some time (even some days) my [Slack Bot In] node no longer receives any slack messages (in the slack - I also see under "Apps" that it is no longer connected to the "Slack Bot").
I think that the connection between the [Slack Bot In] node and slack is broken and that this connection is not automatically restored. So I need to restart or redeploy my node red application to get it working again.
Note also that no error message is logged in the node red log files when this connection drops and there is also no status indication when consulting the [Slack Bot In] node in the node red editor.
kr Jan