SignalR multi user live chat desynchronisation - javascript

I have a live chat in which multiple people would be connected simultaneously. All public messaging works fine, but sometimes private messaging to a specific id doesn't work. I believe i narrowed it down to when people disconnected and reconnected that they connected to a different instance (perhaps IIS had recycled and started a new hub).
I thought I had fixed it, but I haven't and now I'm here because I'm stuck. What I thought would fix it was changing the connection variable within the startChat() function to refresh it with the correct information.
This is a cut down version of the code, as I didnt thing the rest would be necesary.
Issue is that when connected to signalR recipients of a message directly to them doean't come through, even though the chat Id it's being sent to it correct. Possible hub/socket mismatch?
var chat = $.connection.chatHub;
$(document).ready(function () {
// Start the chat connection.
startChat();
//restart chat if disconnected
$.connection.hub.disconnected(function () {
setTimeout(startChat(), 5000);
});
$.connection.hub.error(function (error) {
$('#messagebar').html('Chat ' + error + '. If this message doesn\'t go away, refresh your page.');
});
chat.client.addToChat = function (response) {
$('#chat-' + response.Type).prepend(response.Message);
};
});
function startChat() {
chat = $.connection.chatHub;
$.connection.hub.start().done(function () {
//get recent chat from db and insert to page.
//also saves user's chat id to their user for lookup when private messaging
$.ajax({
method: 'POST',
url: '/api/Chat/SetupChat/'
});
$('#messagebar').html('Connected to chat.');
});
}
Any help appreciated, Thanks.

Not sure exactly how your message is going missing, but you should send messages to a User instead of by connection id. This way you be able to identify on the server that a User has at least one connection, and send messages to all connections for that User. if a given connection id is no longer valid, but another one is (because the client has refreshed the page for example) the message wont be lost.
From the docs https://learn.microsoft.com/en-us/aspnet/core/signalr/groups:
The user identifier for a connection can be accessed by the
Context.UserIdentifier property in the hub.
public Task SendPrivateMessage(string user, string message)
{
return Clients.User(user).SendAsync("ReceiveMessage", message);
}
Not sure how this relates exactly to your server code, but you could add it if you're unclear how to progress.

Related

How to allow JavaScript to receive a message sent to a specific user (or self) using Signal R?

I previously asked this question but it was closed for duplication owing to this thread (SignalR - Sending a message to a specific user using (IUserIdProvider) *NEW 2.0.0*) - but this doesn't show the JavaScript as made clear in my title.
I have a WebForm application in ASP.Net that uses SignalR to push live data to the user logged in. The setup works perfectly, but realised I am broadcasting messages to all clients, which whilst it doesn't cause the wrong data to displayed to the logged in user, does cause the JavaScript function to get called for all users when just one has a data push.
I have amended the Hub code to broadcast to a specific user (User) and provided the User ID, and I have also tried Client with a Connection ID. Both fire off fine in the codebehind, but the javascript will not update the front end.
I believe it's because the JavaScript has not been modified to listen for a message sent to the user, but I'm not sure how I need to adapt the code to allow the message to be received.
The 2 tried lines in Hub here:
context.Clients.User(Me.Context.User.Identity.GetUserId()).ReceiveNotification(notifCount)
context.Clients.Client(Me.Context.ConnectionId).ReceiveNotification(notifCount)
JavaScript/jQuery function for the SignalR message here:
$(function () {
var nf = $.connection.notificationHub;
nf.client.receiveNotification = function (notifCount) {
// Update data
}
$.connection.hub.start().done(function () {
nf.server.sendNotifications();
}).fail(function (e) {
alert(e);
});
//$.connection.hub.start();
});
For calling back to the client (or self) you should use:
Clients.Caller.addContosoChatMessageToPage(name, message);
And for calling users you should use:
Clients.Client(Context.ConnectionId).addContosoChatMessageToPage(name, message);
Reference - docs

How to get Socket to send to the requesting client only?

I am having an issue practicing with socket.io. I have a function set up, where on connection, the users data is refreshed, only it seems to only be happening AFTER the initial connection.
When one user connects, nothing on new user refreshes. Aditional new user connects, Old connection refreshes, but new connection remains untouched.
Am I not able to send data during connection?
This is just some simple practice for me, trying to get better with websockets, and can't seem to get past the general broadcast.emit.
I have tried socket.to(socket.id).broadcast.emit, of course, however no luck there either. You will see in my code.
// Setup socket.io
socketIo.on('connection', socket => {
getDataByUser(user, socket)
socket.on('disconnect', function() {
delete CLIENTS[socket.id];
console.log(`${username} disconnected`)
});
function getDataByUser(user, socket) {
var items = [1,2,3];
items.forEach(element => {
socket.broadcast.emit('server:data', element)
socket.broadcast.to(socket.id).emit('data', 'for your eyes only');
});
}
As you can see in the getData function, I use both a general emit, and an emit to, in order to test it. I have proper listeners set up, however the socket itself is only refreshed apon a new connection. Perhaps this is only called when socket a makes a new connection?
I would like to have this function called imediately apon socket connection. for only the user who has connected. Any help would be greatly appreciated.
I think the way you can deal with this is to not broadcast it.
Try to emit only to the socket who got connected at that time.
I did not get what you are trying to achieve so if the code below does not resolve you problem please say what output do you expect.
socketIo.on('connection', socket => {
var items = [1,2,3];
items.forEach(element => {
socket.emit('server:data', element)
socket.emit('data', 'for your eyes only');
});
socket.on('disconnect', function() {
socket.disconnect();
console.log(`${username} disconnected`)
});
when you use the socket object you adress to that client only...the one who establised the connection.

unable to broadcast a user disconnection in socket.io

i am new to socket.io & nodejs. i have been writing a tictactoe game and i have a problem in it, my purpose is if someone refresh the page or close the browser let his/her opponent know . i know i should do this with disconnect event and here is what i try, but it is not working .
server side
socket.on('disconnect', function() {
socket.emit('user:disconnect');
});
client side
socket.on('user:disconnect', function() {
var message = player.getPlayerName() + ' leaves';
socket.emit('gameEnded', {room: this.getRoomId(), message: message,id:player.getPlayerId(),gameid: this.getGameId(),winType:"leave"});
});
also, i need to know how to get the room of disconnected user .
i already saw this but i just want to send the users in a room not all users in the whole application.
server.js
socket.on('disconnect', function() {
socket.emit('user:disconnect');
});
In the above code if a user named 'xxx' is disconnected, server is emitting 'user:disconnect' to the same user. You have to find the socket connection of other player and emit the event to that client.
You can achieve your goal by joining both the clients in a room and send message to other user in the room.
socket.join('room1');
io.sockets.in('room1').emit('user:disconnect');
Otherwise you have to store all clients as mentioned below and send message to the specific client using the following code.
var users = {
'client1': [socket object],
'client2': [socket object],
'client3': [socket object]
}
users['client3'].emit('user:disconnect')

Chromecast not receiving messages over CastMessageBus

I'm trying to initialise the cast message bus on my
receiver application. I am using the
CastReferencePlayer Sample I'm able to initialise the channel at launch, and
receive one message.
But after media is playing, I'm not able to receive
any additional messages over the channel using the same send methods on
the sender. My sender is an iOS Device
Where is the best place to init the message bus to ensure that the channel
is open to receive messages throughout the life of the app?
I am currently starting the channel
in sampleplayer.CastPlayer.prototype.start = function(). But I'm not sure if this is the correct place to start the message bus as I'm only receiving the message once at startup (i.e. before the media starts to play).
sampleplayer.CastPlayer.prototype.start = function() {
var messageBus = this.receiverManager_.getCastMessageBus(
"urn:x-cast:com.myTestChannel.app",
cast.receiver.CastMessageBus.MessageType.JSON);
messageBus.onMessage = function(event) {
var message = event.data;
if (message.testID) {
console.log("Message received");
} else if (message.someKey) {
console.log("pause message received");
}
};
this.receiverManager_.start();
};
I have tried to place the channel creation code in a window.onload function inside my player.js but this reacts the same as before (i.e. initial message only).
Does anyone have any idea where I should be placing the code to init the channel?
Any help would be appreciated.
EDIT: I have done some more investigating and discovered that it is just my iOS sender that will not send multiple messages to the receiver. I have tried both android and chrome and multiple messages work.
Is anyone aware of problems with sending messages from an iOS sender.
The problem with my code was in my sender.
The sendTextMessage method was not firing the after the first instance due to the my reference to the cast channel being destroyed.

Meteor client disconnected event on server

Simple question, maybe simple answer: how do I know on the server that a certain client has disconnected? Basic use case: the serve would need to know if a player has dropped the connection.
In the publish function, you can watch socket close event as follows.
this.session.socket.on "close", -> # do your thing
Meteor.publish("yourPublishFunction", function()
{
var id = this._session.userId;
this._session.socket.on("close", Meteor.bindEnvironment(function()
{
console.log(id); // called once the user disconnects
}, function(e){console.log(e)}));
return YourCollection.find({});
});
I've created a pretty comprehensive package to keep track of all logged-in sessions from every user, as well as their IP addresses and activity:
https://github.com/mizzao/meteor-user-status
To watch for disconnects, you can just do the following, which catches both logouts and browser closes:
UserStatus.on "sessionLogout", (userId, sessionId) ->
console.log(userId + " with session " + sessionId + " logged out")
You can also check out the code and do something similar for yourself.
Maybe (in the server code)
Meteor.default_server.sessions.length
or
Meteor.default_server.stream_server.open_sockets.length
you can do one thing make a event on server and call it from browser with ajax which call after some small time interval settimeinterval using with session values into header and if server din`t get request from user it means he dropped connection

Categories