Socket.io client-to-client logic, with lot of users - javascript

I am trying to implement client to client messaging in my app, using socket.io, and node.js and Android.
I searched a little, and found a lot of tutorials, explaining how to deal with targetting specific client when sending messages through socket.io socket.
Send message to specific client with socket.io and node.js
The solution is almost always the same : Creating a hashmap object, linking user info such as its username, email address (or anything unique allowing to identify it), with its socketid.
Then calling io.clients[sessionID].send()
Now I have two questions :
This would work if only one instance of the app is running, but imagine if my app is divided in multiple instances (for large app).
What if a client A, connected to instance X, wants to send message to user B, connected to instance Z. If, as seen in the example, socketids are stored directly in a simple object existing in the script, some sockets wont know about others users existing in an other instance.
If I am totally wrong (and I might), is this a good practice to store all user's socketids in a single variable ? If yes, would it still be okay with a 50000+ users enviromnment ? If no, should I find another solution like storing user's socketids in database ?

You could use a redis instance, shared between all your app instances. And you get 2 birds with one stone.
The redis would store all your socket ids in a centralized place.

Related

Javascript creating hubs?

I have an express server setup that is handling all of my routing and session stuff. I want the system to work so that when a user is logged in they are able to connect to a "hub" like entity that is uniquely based on the location of the "hub". I thought about working it like each of the "hubs" is a collection in a database, but the way it works is that a user connects to the "hub" and then disconnects from it when they are done but can connect to different "hubs" based on a location. How should I go about creating a unique group of "hub" like things that all act as objects with storable data?
Instead of connecting to a "hub", why not just present them with different information from a database based on their location. The user will never really connect to anything other than your single backend. Unless, ofcourse, you set up different servers all over the world (known as a CDN, and probably a bit too much effort).
If you're using express, you could use something like mongodb for data storage.
With mongodb you get the mongoose npm package. With that, you can create Schemas. You could have different Schemas as "hubs" and load the correct ones based on location data. That would let the user see different information for different locations.

How do I handle communication between multiple Node.js servers for each user?

I'm trying to make a user log in just once, and have his information on all the servers. Any changes made to the user's information will instantly be available for all servers. Is this possible to do without having each user "log in" separately for each server?
Sort of like the $_SESSION for php, but for Node.js
Design 1 -
What I think would be best to do, but don't know how to share socket data between servers, perhaps using something like PHP's $_SESSION?
Design 2 -
What I'm currently doing:
User uses socket.emit to main.js
main.js adds user information onto the emit
main.js emits to the appropriate server
Appropriate server emits back to main.js
main.js finally emits back to user
This seems awfully inefficient and feels wrong
If your information is primarily static, you can try something similar to JWT. These are cryptographically signed tokens that your authenticating server can provide and the user can carry around. This token may contain information about the user that you want each server to have available without having the user accessing it.
If it's not, you may be looking into sharing a database across all servers, and have that be the point of synchronization between them.
Updates based on our comments (so they can be removed later):
If you decide to use auto-contained JWT tokens, you don't need to be making trips to the database at all. These tokens will contain all the information required, but it will be transparent to the end user that won't have insight into their contents.
Also, once you understand the JWT standard, you don't necessarily have to work with JSON objects, since it is just the serialization approach that you can switch by another one.
You'd provide one of these tokens to your user on authentication (or whenever required), and then you'd require that user to provide that token to the other servers when requesting information or behavior from them. The token will become your synchronization approach.

How to configure Autobahn(crossbar.io) for dynamic chat rooms?

I love crossbar.io and how it works(personally). But I would like to know how we could setup the architecture for a typical dynamic chat application using Autobahn(Crossbar.io).
Dynamic chat here means, individual chat room created for each url.
For example: http://www.myapplication.com/chat?roomId=123 , creates a chat room subscribing to topic "com.myapp.chat123".
http://www.myapplication.com/chat?roomId=456 , creates a chat room subscribing to topic "com.myapp.chat456".
We need to store the chat messages in the Database for future reference, since Autobahn doesn't have message persistence.
Now my questions are:
If each chat room use separate topic, then how we could subscribe for the messages in the server(since we can't subscribe using Patterns as of now) ?
Since we will use separate topic for each room, how we do authentication and authorization in Crossbar.io ?
I couldn't able to find the Javascript documentation for setting the features as mentioned here. Where to find it ?
In this SO answer, it was mentioned that crossbar.io provides meta-events for session join or leave on Router. Is there any way to know when user subscribes or unsubscribes to specific topic instead of Router join or leave ?
Could you explain how to configure available advanced profile features with Current version of Crossbar.io (in Javascript, browser or Node.js) ?
Could you explain about Event History feature in detail ? And how to configure it ?
I'll answer your question one by one:
At least, it's your client which wants to subscribe to his topic (correct me if I misunderstand), then, you need to store a list of topic ID related to user in your database, and when your client connects to the server, you send him the list of topic ID and let him subscribe all of them.
Authentication / Authorization process has nothing to do with a separate topic. You can do something like that:
There is two way to authenticate, anonymously and WAMP-CRA. Then, you assign a role for anonymously connected clients, and another role for authenticated client (this role can be different following the database e.g: user, admin, moderator, ...)
When authenticated, subscribing to a topic needs authorization (implemented by a dynamic authorizer, you can see how to do it there: https://github.com/tavendo/AutobahnPython/blob/master/examples/twisted/wamp/authorization/router.py -- basically, it is the same, except you forget the router thing and you focus on the authorize method)
Then, you authorize based on something like Access Control.
Unfortunately, the doc is quite outdated, you should ask for it on the Mailing List which features you want to use and how can you use them.
As I recall, there is a meta-event on_subscribe/on_unsubscribe.
Advanced features can be configured in the config file of Crossbar, they can be also an argument passed to publish/subscribe/call/register calls.
I'm not a core developer of Autobahn, but as much as I understood, it is a feature that give you a way to get all previous published data from a topic (X last ones, since a TIMESTAMP, after a ID).
I know that Autobahn is hard to follow sometimes due to the documentation, but examples can help a lot, and here there are a lot of interesting things: https://github.com/crossbario/crossbarexamples (including Authentication, MetaAPI, Patterns).
I hope that I've answered most of your questions, but yet, if there are things you don't understand, I recommend you to go to the mailing list, this is your best try, in my opinion.

SignalR - invoking a message from server code

Been researching heaps and making no progress :(
Trying to set up a small web app using VB in VS 2013.
I have added all the SignalR resources to my project.
Each logged in client has a UserID in my database.
I want to invoke a SignalR message to certain UserID's from server-side code, not client-side. Firstly, is this possible? (it was possible using ReverseAJAX, but I have chosen not to use that)
If it is possible, how do I go about setting up the SignalR Hub to allow me to send a message using a UserID? I don't need help with the SQL, I can do that my self.
Also, what javascript do I need to persist the request? I'm guessing I will need the UserID somewhere in this piece of code.
Thanks heaps.
This is very possible. If you look here
http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-server#callfromoutsidehub
you will find a section on "Single User Groups". This is the mechanism available in version 2 to send a message to a single User Id. Essentially when a Connection is established you add the User Id to a "group" which can be accessed by Group Name (syn. User Id) without having to worry about persisting the relationship of a connection id to a user id yourself. The only limitation would be if more than 1 connection is established by the same user, all devices with that user would be in the same group and would therefore receive any messages sent to it...
There is also another section on how to retain the instance of your SignalR context on the web server to make calls out to clients (How to call client methods and manage groups from outside the Hub class)
I did read something about the SignalR team creating User Id methods but I have used the above approach with fair success and haven't looked much further into that.
Hope this helps
As #Pepto mentioned, here it is described how you can get a reference to your hub, and then use it in your server code.
An easy way to invoke a client-side function for a specific user, would be to use Clients.User("Username") in your hub.
Intellisense will tell you that User() wants an ID as a parameter, but you should pass the username of the user, whose function you want to invoke, not his ID.

What is the best way to show online followers, node.js/socket.io and Redis

My app is built in PHP (served on nginx/php-fpm) and I use node/js with socket.io for users push notifications. These are pushed using Redis pub/sub to interlink between PHP and node.js
The node.js app maintains an array of online userid's. They get added when a user connects to socket.io and removed from the array when they disconnect.
MySQL is used as the main database and I have a standard relationship table which denotes who is following who. A list of followers userid's is retrieved when a user logs and displayed to them.
I now wish to intersect these two sets of data to provide live online status's of these relationships in a similar manner to facebook (a green light for online and grey for offline)
What would be the most performant and most scale-able way of managing this. My current thought process is along these lines:
On the client side we have a javascript array of followers user id's. Set up a timer client side which pushes this array to the node.js app every 60 seconds or so. Node.js handles inersecting the followers id's with its current array of online users and returns an object depicting which users are online.
Now this would work but it feels like it might be a heavy load on node.js to be consistently looping through users followers lists for every online user. Or perhaps I am wrong and this would be relatively trivial considering the main application itself is served by PHP and not via node which only currently handles notification pushing?
Regardless, is there a better way? It's worth noting that I also use redis to build users activity streams (The data is stored in MySQL and redis maintains lists of activity id's)
So seeing as I already have a Redis server active, would there be a better method leveraging Redis itself instead?
Thanks for any advice
If i remember right, when socket.io connected to client side, that makes a request to the client every time for checking active connection and return result, in callback succeffull you can put code that will be update time active users in DB. And when get last notes beyond 5 minutes from DB.

Categories