I haven't work with socket io before so I feel a little bit lost right now.
I try to make a chat. I have a system when users send a private message to another it makes a connection between them (Creat chat id).
Now I try to find a solution for how front-end listen for an event from many chat id.
Now the system looks like this I am not sure if this one is a correct solution.
Front-end
io(`/privateMessage/${user._id}`).on('message')
Back-end
io.of(`privateMessage/${toRecipientId}`)
.emit('message')
My question is it is possible that the client can listen from array namespaces like chat Id or I should stick to first solution?
I would suggest you use "rooms" approach:
https://socket.io/docs/rooms-and-namespaces/#Rooms
Syntax, how to connect to a few rooms, is the following:
socket.join(['room1', 'room2']);
Related
Hello I hope you are very well, I would like to ask you a question that I have not been able to deduce the answer to.
In a course I was seeing that to send a message to a specific user with socketIO.js the to () method is used and the id as a parameter, but I have a doubt, that id is auto generated by socketIO as far as I understand, so I would like to know How can the frontend know that id? The example that I saw in the course does it from the console and sends it directly to the method with the id that it already knows, then that example is not so real, what I would like to know in itself How is it that it performs a one-to-one chat if the id is autogenerated by the socket? I don't know if I understand.
For example, to start a conversation with another user, you can click on a button, trigger an event that makes emit, send the id of the user who writes, the event that should trigger the backend with socket, but my question is how does it taste like who send the message? How do you know the id of who is being sent to when establishing communication between 2 users for the first time? Obviously this must be sent by frontent as a parameter but also how does the frontend give this id of who will it be sent to? I don't know if you can store a fixed socket id for a user in a DB or Can you use your DB id to use with sockets? more than everything is what I can not deduce how it would be done?
I do not know if I understood with the question, more than everything is that, I do not know how it obtains or assigns the id for the target from where the message is sent and if this can be fixed and stored in db or is there any method to this.
I thank you in advance for your response, and any resources that you share with me about it or if you recommend a course with, I would greatly appreciate it.
as an example I have this method
io.on('connection', (client) => {
client.on('privateMessage', (data)=>{
const person = user.getPersona(client.id) //get this
client.broadcast.to(data.para).emit('privateMessage', createMsj( person.name, data.messages));
});
}
But where does the front-end of the person to receive the message to pass it to the method?
The front-end will not know the socket.io id of any other clients. This is where your server needs to be involved.
Each of your users presumably has some username that is displayed in the client UI and this is the name that other clients would know them by.
So, your server needs to keep a mapping between username and socket.io clientID. So, a user can send a request to your server to connect to BobS. Your server then needs to be able to look up BobS, find out if that user is currently connected and, if they are, then what is their socket.id value. That way, your server can facilitate connecting the two users.
This mapping would not typically be kept in a permanent store (such as a database) because the socket.id is a transient value and is only good for the duration of that client's socket.io connection. As such, it is more typically just kept in some sort of Javascript data structure (such as a Map object).
I found it's easier to just setup own custom path for multiple endpoints like this
server side:
io.on('connection', function(client) {
var username = client.handshake.headers.users[0].username;
client.on(username+'_con1', function(data) {
io.emit(username+'_con1',data);
});
client.on(username+'_con2', function(data) {
io.emit(username+'_con2',data);
});
}
Is above approach correct? at least I'm able to make it work.
Depending on what you mean by correct. This will create multiple events for the client.
Its hard to say if this is the best/correct way without any context. But you should look into namespaces and rooms and decide for yourself! http://socket.io/docs/rooms-and-namespaces/
Creating unique message names for each client makes it seem like you plan on sending a message to all clients and only some clients will be listening for the message directed at them. This is not a very efficient way to do things.
Rooms in socket.io are designed such that you can have a common message name (no need for a unique message name for each client) and then send that message only to the clients that it is intended for. That's a lot more efficient scheme.
Now, of course, you could create the unique message name for each client and then only send it to the desired client, but why bother with the extra complication of the unique message name. You don't need it if you're only sending the message to the intended client.
So, you could certainly make your scheme work, but it does not seem like it's the simplest way to do things and, depending upon other details of your implementation, it may not be the most efficient way to do things either.
A namespace is more like connecting to a particular channel. The client decides what channel they want to connect to. The server then decides which namespace to send a given message to.
A room is a something a server subscribes a client to in order to make it easy to send a specific set of clients the same messages or in some cases to share incoming messages from one client with all the other clients in a room (like in chat).
I am developing a webapp in which I'd need one client, associated with the admin, to trigger an event (e.g., a new value selected in a dropdown list) which in turns will tell all the other connected clients to change the subscription, possibly using a parameter, i.e., the new selected value.
Something along the lines of
Template.bid.events
"change .roles": (e, tpl) ->
e.preventDefault()
role = tpl.$("select[name='role']").val()
Meteor.subscribe role
Of course this works for the current client only.
One way I thought would be keeping a separate collection that points a the current collection to be used, so the clients can programmatically act on that. It feels cumbersome, thou.
Is there a Meteor-way to achieve this?
Thanks
In meteor, whenever you have a problem that sounds like: "I need to synchronize data across clients", you should use a collection. I realize it seems like overkill just to send one piece of data, but I assure you it's currently the path of least resistance.
There are ways you can expose pseudo-collections which don't actually write to mongo, but for your use case that really sounds like overkill - new Mongo.Collection is the way to go.
You can use streams to setup a simple line of communication between connected clients and the server. It doesn't store data in MongoDB. Just let all connected clients listen to a stream and switch subscriptions when a new message comes in with the subscription name. Make sure only your client associated to your admin can push messages to the stream.
Available package: https://atmospherejs.com/lepozepo/streams
Examples: http://arunoda.github.io/meteor-streams/
I am trying to set up a simple presentation using three computers synchronized by a central server, and I figured node would be the ideal tool.
I was wondering if there's any way to have all three computers connect to the server via the browser, and if I could control the server to push changes to each?
For example:
Computer-1 visits 10.0.0.1?comp=1?slide=1
Computer-2 visits 10.0.0.1?comp=2?slide=1
Computer-3 visits 10.0.0.1?comp=3?slide=1
Then from the server commandline, I would like to be able to trigger a change so the clients will each be redirected accordingly like so:
Computer-1 visits 10.0.0.1?comp=1?slide=2
Computer-2 visits 10.0.0.1?comp=2?slide=2
Computer-3 visits 10.0.0.1?comp=3?slide=2
I'm new to node, so I'm not even sure if this is the ideal platform, but was wondering what terminology I should be researching to be able to build something like this?
Thank you for your responses, I ended up looking into socket.io and managed to write this system in one evening! Node + socket.io and express is a pretty amazing tool with the socket emit events.
Thank you for pointing me in the right direction, this is exactly the tool I was looking for.
Just in case it may help anyone, in my client/jade template, I have something like:
socket.on('slideUpdate', function (data) {
// Do things with the data
}
and on the server app.js:
io.on('connection', function (socket) {
socket.on('slideChange', function (data) {
// logic for setting slide data
io.sockets.emit('slideUpdate', { example: exampleData ... });
});
});
where a slideChange event is triggered via a button on the client-side template.
For such a presentation I would use the most simple solution, i.e. not websockets, not server-sent events and not long-polling.
Just do a short poll, i.e. every client calls the server every 100ms for updates. The server then responds with a status update (if there is one).
I'm making a multiplayer (2 player) browser game in JavaScript. Every move a player makes will be sent to a server and validated before being transmitted to the opponent. Since WebSockets isn't ready for prime time yet, I'm looking at long polling as a method of transmitting the data and node.js looks quite interesting! I've gone through some example code (chat examples, standard long polling examples and suchlike) but all the examples I've seen seem to broadcast everything to every client, something I'm hoping to avoid. For general server messages this is fine but I want two players to be able to square off in a lobby or so and go into "private messaging" mode.
So I'm wondering if there's a way to implement private messaging between two clients using nodejs as a validating bridge? Something like this:
ClientA->nodejs: REQUEST
nodejs: VALIDATE REQUEST
nodejs->ClientA: VALID
nodejs->ClientB: VALID REQUEST FROM ClientA
You need some way to keep track of which clients are in a lobby together. You can do this with a simple global array like so process.lobby[1] = Array(ClientASocket, ClientBSocket) or something similar (possibly with some additional data, like nicknames and such), where the ClientXSocket is the socket object of each client that connects.
Now you can hook the lobby id (1 in this case) onto each client's socket object. A sort of session variable (without the hassle of session ids) if you will.
// i just made a hashtable to put all the data in,
// so that we don't clutter up the socket object too much.
socket.sessionData['lobby'] = 1;
What this allows you to do also, is add an event hook in the socket object, so that when the client disconnects, the socket can remove itself from the lobby array immediately, and message the remaining clients that this client has disconnected.
// see link in paragraph above for removeByValue
socket.on('close', function(err) {
process.lobby[socket.sessionData['lobby']].removeByValue(socket);
// then notify lobby that this client has disconnected.
});
I've used socket in place of the net.Stream or request.connection or whatever the thing is.
Remember in HTTP if you don't have keep-alive connections, this will make the TCP connection close, and so of course make the client unable to remain within a lobby. If you're using a plain TCP connection without HTTP on top (say within a Flash application or WebSockets), then you should be able to keep it open without having to worry about keep-alive. There are other ways to solve this problem than what I've shown here, but I hope I got you started at least. The key is keeping a persistent object for each client.
Disclaimer: I'm not a Node.js expert (I haven't even gotten around to installing it yet) but I have been reading up on it and I'm very familiar with browser js, so I'm hoping this is helpful somehow.