Most of the time the messages are passed normally, but a couple messages in particular arent recieved until the recieving client sends a message. This happens everytime for specific methods/messages, but not at all for others.
Example: user1 sends a message, user2 then sends a message to receive message from user1.
Related Material
Deleted question: websocket receives previous message only when new message is sent
Github issue: webSocket client does not receive messages before sending...
We ran into this issue and the solution had to do with how we wrote our promises. We initially used the sample code provided by Amazon
https://github.com/aws-samples/simple-websockets-chat-app/blob/master/sendmessage/app.js#L26
const postCalls = connectionData.Items.map(async ({ connectionId }) => {
try {
await apigwManagementApi.postToConnection({ ConnectionId: connectionId, Data: postData }).promise();
} catch (e) {
if (e.statusCode === 410) {
console.log(`Found stale connection, deleting ${connectionId}`);
await ddb.delete({ TableName: TABLE_NAME, Key: { connectionId } }).promise();
} else {
throw e;
}
}
});
And I'm pretty sure having an async function as a map function doesn't work properly or reliably (for whatever reason. maybe this is documented somewhere), so we changed it to a simple for loop and it fixed the issue.
for(const connection of connectionData.Items) {
const connectionId = connection.connectionId;
...same logic goes here
}
Related
I am using a Slack webhook to process incoming SMS messages from Twilio. However, the way I have it set up, It seems that Twilio is expecting the web server (slack) to respond to it. This causes errors to be generated in Twilio, and I obviously don't want errors because I'll be getting emails.
I am using the twilio-ruby gem in Ruby to send out the SMS messages, and using the slack-ruby-client to monitor incoming messages from Slack.
How do I stop Twilio from trying to expect a response from the web server when it POSTS to the Slack webhook? Is that even possible or do I have this all configured incorrectly?
EDIT
Here's the function that I have which sends the forwarded SMS to Slack:
const https = require("https");
// Make sure to declare SLACK_WEBHOOK_PATH in your Environment
// variables at
// https://www.twilio.com/console/runtime/functions/configure
exports.handler = (context, event, callback) => {
// Extract the bits of the message we want
const { To, From, Body } = event;
// Construct a payload for slack's incoming webhooks
const slackBody = JSON.stringify({
text: `!asi SMS\nFrom: ${From}\nMessage: ${Body}`
});
// Form our request specification
const options = {
host: "hooks.slack.com",
port: 443,
path: context.SLACK_WEBHOOK_PATH,
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": slackBody.length
}
};
// send the request
const post = https.request(options, res => {
// only respond once we're done, or Twilio's functions
// may kill our execution before we finish.
res.on("end", () => {
// respond with an empty message
callback(null, new Twilio.twiml.MessagingResponse());
});
});
post.write(slackBody);
post.end();
};
Twilio developer evangelist here.
Twilio is always going to expect at least a 200 response or will timeout at 15 seconds for incoming message webhooks.
You could avoid the error messages by using something in between Twilio and Slack, like Zapier (example in this blog post) or using a Twilio Function (as described here) or with Twilio Studio (from the documentation here).
Hope one of those ideas helps!
Update
Further to my earlier answer, and given the code you used to make the call, I have an update.
When making a request using Node's built in https module you will not get the end event until you have read the data. This is what is causing the timeout between Twilio and the Twilio Function, you are never responding to it because you don't consume the data from the request.
In a quick test I found that just listening for the data event meant that the end event did fire. So update your function to:
const post = https.request(options, res => {
// only respond once we're done, or Twilio's functions
// may kill our execution before we finish.
res.on("data", () => {});
res.on("end", () => {
// respond with an empty message
callback(null, new Twilio.twiml.MessagingResponse());
});
});
And it should work.
Is it possible for a SignalR client send a message to the server and then to await for a seperate message (not a return value) from the server?
The theory;
Client1 send message1 to Server and "waits" for the response.
Server processes some logic
Server sends message2 to Client1 and Client1 executes the waiting code.
Call to the server:
$.connection.myhub.server.myRequest(id).done(()==>{
// myRequest is done;
// the server has received the request but hasn't processed it yet.
// I want put some *async* code here to do something when the server has triggered $.connection.myhub.client.myResponse(id, someParam);
});
Callback to the client:
$.connection.myhub.client.myResponse(originalId, somePassedBackValue);
Can I use Async/Await, or wrap this in a Promise somehow?
If this isn't acheivable in SignalR are there anyother socket libraries that might be used instead?
You can do something, like the following:
Imagine you have a client that joins a group, updates a table and then notifies the client that it has joined.
Client
msgHub.server.joinGroup(id).done(function () {
console.log("Joined Group");
serverCallFinished = true;
})
msgHub.client.displayTable = function (table) {
display(table);
}
Hub
public async Task JoinGroup(string practiceId)
{
try
{
await Groups.Add(Context.ConnectionId, practiceId);
//Add new table
var table = new Table(practiceId)
await UpdateTable("SomeGroup", table);
}
catch (Exception e)
{
throw;
}
}
public async Task UpdateInfo(string groupName, string table)
{
//await some logic
Clients.Group(groupName).updateTable(table);
}
Update info will call the client with message2 in this case a table that it wants to display to the client. When it finishes the it will return from its awaited state by JoinGroup which will return and alert that a new user has joined a group.
How can you detect that you received a message on a socket.io connection that you do not have a handler for?
example:
// client
socket.emit('test', 'message');
// server
io.on('connection', function (socket) {
console.log('connection received...');
// logs all messages
socket.conn.on('message', function(data) {
console.log('this gets every message.');
console.log('how do I get just the ones without explicit handlers?');
});
socket.on('other' function(data) {
console.log('expected message');
});
}
By accessing the internals of the socket object you can determine what events it is currently listening for. You can use this server-side code to see if the current message is being handled.
io.on('connection', (socket) => {
console.log('A user connected.');
socket.on('disconnect', () => {
console.log('A user disconnected.');
});
socket.on('chat', (msg) => {
console.log('message: ' + msg);
io.emit('chat', msg);
});
socket.conn.on('message', (msg) => {
if(!Object.keys(socket._events).includes(msg.split('"')[1])) {
console.log(`WARNING: Unhandled Event: ${msg}`);
}
});
}
Once connected I am handling two events, 'disconnect' and 'chat'. After that I define a handler that catches all messages with socket.conn.on(...).
The message it receives is going to be a string that looks something like this: '2["myEventName","param1","param2"]'. By splitting it along the double quotes we can get the event name.
We then peek into the internals of socket to find all the keys of socket._events, which happen to be the event name strings. If this collection of strings includes our event name, then another handler will take care of it, and we don't have to.
You can test it from the console in the browser. Run socket.emit('some other event') there and you should see your warning come up in the server console.
IMPORTANT NOTE: Normally you should not attempt to externally modify any object member starting with an underscore. Also, expect that any data in it is unstable. The underscore indicates it is for internal use in that object, class or function. Though this object is not stable, it should be up to date enough for us to use it, and we aren't modifying it directly.
Tested with SocketIO version 2.2.0 on Chrome.
I didn't find a way to do it like socket.io, but using a simple js function to transform message into json it's doing the same job. Here you can try this:
function formatMessage(packetType, data) {
var message = {'packetType': packetType, 'data': data}
return JSON.stringify(message)
}
With:
socket.on('message', function(packet){
packet = JSON.parse(packet)
switch (packet.packetType) {
case 'init':
...
and
socket.send(formatMessage('init', {message}));
I would do so, of course it is the abstract code ... you would have to implement all the listeners and the logic to get the ids of the users to work
Client
var currentUser = {
id: ? // The id of current user
};
var socketMessage = {
idFrom: currentUser.id,
idTo: ?, // Some user id value
message: 'Hello there'
};
socket.emit('message', socketMessage);
socket.on('emitedMessage' + currentUser.id, function(message) {
// TODO: handle message
});
Server
io.on('connection', function (socket) {
// Handle emit messages
socket.on('message', function(socketMessage) {
// With this line you send the message to a specific user
socket.emit('emitedMessage-' + socketMessage.idTo, {
from: socketMessage.idFrom,
message: socketMessage.message
});
});
});
More info: http://socket.io/docs/
The following code will close the connection, event further observers exists on the myWebSocketSubject:
myWebSocketSubject.Observable.webSocket('ws://mysocket');
myWebSocketSubject.subscribe();
myWebSocketSubject.multiplex(..).subscribe().unsubscribe()
// the connection closed now
My expectation was, that the connection gets closed with the last unsubscribe() call (and not with the first one).
Use Case
If I get it right, with the multiplex(..) operator, on create and complete a message is send to the socket, which e.g. allows to un-/subscribe on server side to specific event.
My preferred Web Socket service could therefore look like as below. There exists only one connection, and this single connection provides several streams. On first subscription to the web socket the connection gets created; and with the last unsubscribe call the connection gets closed. For each data-stream a un-/subscribe message is sent once.
I haven't found a solution to use the WebSocketSubject.multiplex(..) method...
Preferred Example Web Socket Service
export class WebSocketService {
connection: WebSocketSubject<any>;
constructor() {
this.connection = Observable.webSocket<any>(_createConfig())
}
dataStream(eventType: string): Observable<WebSocketMessage> {
return connection.multiplex(
() => new WebSocketMessage("WebSocket.Subscribe." + eventType),
() => new WebSocketMessage("WebSocket.Unsubscribe." + eventType),
message => (message.type == eventType)
)
.retry() // reconnect on error and send subscription messages again
.share(); // send messages on last/fist un-/subscribe on this stream
}
// ...
}
export class WebSocketMessage {
type: string;
data: any;
constructor(command: string, data?:any) {
this.type = command;
this.data = data || undefined;
}
}
I have written the following test case which fails...
it('should able to handle multiple subscriptions', () => {
const subject = Observable.webSocket(<any>{url: 'ws://mysocket'});
const sub1 = subject.subscribe();
const sub2 = subject.subscribe();
const socket = MockWebSocket.lastSocket;
socket.open();
sinon.spy(socket, 'close');
sub1.unsubscribe();
// Fails, because the socket gets closed on first unsubscribe
expect(socket.close).have.not.been.called;
sub2.unsubscribe();
expect(socket.close).have.been.called;
});
If I get it right the share operator would do the trick. But after using the operator, the multiplex method is not available.
Thanks for any feedback, input, ...!
I'm using a node package: slack-client to interact with the api at slack. Now with or without using slack-client how do I send a direct message from my bot to a user I want to specify? Here's what have so far with a plain socket connection:
var WebSocket = require('ws')
,ws2 = new WebSocket(myURL); //from rtm start
ws2.on('open', function() {
ws2.send({
"id": 333,
"type": "message",
"channel": "#user1", //User I want to send to
"text": "HEY!!!!"
});
});
ws2.on('message', function(message) {
console.log('received: %s', message);
});
I was hoping that message would go directly to me from the bot but nothing. I get a reply of type hello though? The send details above I got on another post about this but it doesn't work for me. The message Id was one I created.
Ok so when calling the rtm.start via the web api, you would get a list of DM's that would be open for various users otherwise you can easily just open an im with im.open. I'm using the node package slack-client as mentioned in my question so you can do this:
//name of user your bot wants to send a msg to.
var userTest = slack.getUserByName('user1');
slack.openDM(userTest.id, function(res)
{
TestMsg(res.channel.id, 'some other msg');//test function I'm using
});
Next is the TestMsg function:
function TestMsg(userChannelId, msg)
{
request.post({url: 'https://slack.com/api/chat.postMessage',
form: { token: "xxxx-yourbot-token",channel: userChannelId,text: msg ,username: "yourBotNamehere", as_user: false}
}, function(error, response, body){
console.log(response.body);
});
}
I couldn't get it to work yet using the websockets send method but I suppose the api of postMessage will do for now as you can post richly formatted messages with postMessage. Hope this helps someone