Probably I haven't understood nodeJS at all, but I build a running client and server app, which sends data trough socket.io.
It works perfectly, but when I open the site on another machine, the content is identically.
When using PHP, every machine running the script has a unique instance of it, so I can make database calls that are only visible to the particular user.
Hopefully this is understandable.
EDIT:
Let's say I've got a normal socket.io setup.
When clicking a button, the following is fired.
socket.emit('getImages', 'someData');
this will make the server send 2 images back, which I will then display on the site.
This works fine for one user. But if there are multiple users at the same time, the images will get changed on every user's site, not just on the one, which fired the function.
On your server:
socketServer.on('connection', function(socket){
console.log("A Client has connected.");
socket.on('disconnect', function(){
console.log("A Client has disconnected.");
});
socket.on('getImages', function(data){
//Do something with the image/data here
//send something to the socket that emitted getimages command
this.emit.('commandhere', datahere);
/* you can also do this.broadcast.emit('commandhere', datahere) to broadcast
all connected sockets except the one who emitted the command
or socketServer.emit('commandhere', datahere) to broadcast all connected
sockets. */
});
});
Related
So, I am still in the experimental phase of Socket.io, but I just can't figure out why my code is doing this. So, I have the code below and when I console.log the code, it repeats the the connection even when there is only one connection. Do you know a solution?
io.on('connnection', (socket) => {
console.log("A new user is connected.")
})
Client side:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io()
</script>
Node.js Console:
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
A new user is connected.
...
(Note: there is only one connection, and I have already cleared the browser cashe)
Here are some of the possible reasons for socket.io connecting over and over:
Your socket.io client and server versions do not match and this causes a connection failure and an immediate retry.
You are running with some infrastructure (like a proxy or load balancer) that is not configured properly to allow lasting webSocket connections.
You are running a clustered server without sticky webSocket connections.
You have put the server-side io.on('connnection', ...) code inside some other function that is called more than once causing you to register multiple event handlers for the same event so you think you're getting multiple events, but actually you just have multiple listeners for the one occurrence of the event.
Your client code is calling its var socket = io() more than once.
Your client page is reloading (and thus restarting the connection on each reload) either because of a form post or for some other reason.
FYI, you can sometimes learn something useful by installing listeners for all the possible error-related events on both client and server connections and then logging which ones occur and any parameters that they offer. You can see all the client-related error events you can listen to and log here.
To solve repetion problem write your code like that for socket:
io.off("connnection").on('connnection', (socket) => {
console.log("A new user is connected.")
})
So I'm creating a basic jackpot betting site for fun and it allows users to put money into a pot and then based on the percentage of money each user puts in it randomly picks a winner. It's working fine at the moment but I feel like the way I'm updating the jackpot page with ajax is really bad. At the moment I have javascript that makes an ajax request each second to get the pot info (size of the pot, players, etc..). I feel like there is a much better way to do this. Is it possible to only make an ajax call when the database is updated? Thanks!
My javascript at the moment:
setInterval(update, 1000);
function update() {
getPotID();
$.ajax({
type: "POST",
url: "/jackpot/update/" + potID,
complete: function(response) {
$('.live-jackpot').html(response.responseText);
getPotInfo();
},
error: function(xhr, status,error) {
console.log("Error");
}
});
}
as said from 7urkm3n, ActionCable has great advantage for this functionality.
Right now you are writing Javascript code that is executed on the client side. Every user that will start a GET http request to your site, will load that javascript files. They will start performing POST request every second to your backend server.
ActionCable is a websocket preinstalled in Rails 5. This means that to configure the notifications with ActionCable and Rails 5, you already have installed everything in your app (if you are using rails 5), you just need to install Redis on your local machine for testing the app in development.
I am not an expert, my understanding is that you use a specific database called redis to store the information about the subscription. I quote a useful article
So PubSub is this concept that Redis and Postgres and a few other things supports, and basically you have this ability to have Channels and the ability to subscribe (and receive those messages) and publish to those channels and anyone listening will then receive those messages.
An example of this is a ChatroomChannel, you could have people publishing messages to the ChatroomChannel and anyone who was subscribed to the ChatroomChannel would receive the broadcast from the channel with the websocket.
This is something you are missing, this way you could only find which users are actually on the playing page and which users are just browsing around, based on this ActionCable creates a channel to communicate between server and client and then creates a subscription to distinguish users that are actually on the playing page and those that left and should not be anymore notified
I quote another useful article
Before we dive into some code, let's take a closer look at how Action Cable opens and maintains the WebSocket connection inside our Rails 5 application.
Action Cable uses the Rack socket hijacking API to take over control of connections from the application server.
For every instance of your application that spins up, an instance of Action Cable is created, using Rack to open and maintain a persistent connection, and using a channel mounted on a sub-URI of your main application to stream from certain areas of your application and broadcast to other areas.
so every user that connects, ActionCable creates a channel that uses a specific url localhost:3000/cable to communicate between server and client (browser)
Action Cable offers server-side code to broadcast certain content (think new messages or notifications) over the channel, to a subscriber. The subscriber is instantiated on the client-side with a handy JavaScript function that uses jQuery to append new content to the DOM.
This means that the server can call the client with parameters and change the page with jquery functions. For ex. appending a div, with a new message.
In my app https://sprachspiel.xyz I do the following in the MessagesController#create
ActionCable.server.broadcast 'messages',
message: message.content,
user: message.user.name,
chatroom_id: message.chatroom_id,
lastuser: chatroom.messages.last(2)[0].user.name
head :ok
so basically, I have my message in my controller and I can update the client by using the ActionCable.server.broadcast function
then in my asset pipeline file /app/assets/javascripts/channels/messages.js I have the following code that trigger the change in the browser adding the message
App.messages = App.cable.subscriptions.create('MessagesChannel', {
received: function(data) {
$('#messages').append(this.renderMessage(data));
},
renderMessage: function(data) {
return "<br><p> <strong>" + data.user + ": </strong>" + data.message + "</p>";
}
});
I build an app called https://sprachspiel.xyz that is an actioncable app, this is the github page for the project, on my portfolio you can read more info about my app, so please ask me anything, I'll be happy to look into it!
Good luck
Fabrizio
When user visit my webpage his is connected to socket on port 3000
var socket = io('http://localhost:3000');
Now I included this code so every page have it. How is there a way to pass second parameter here so even if user refresh page or go to a different page he still have some unique identifier ? My problem is that I got node.js app that respond to event.
socket.on('myevent', function (data) {
Some code is executed here.....
Well now I want to emit response back to the single user who sent it, but what if in meantime user decide to refresh or switch page ? That will give him new connection.
I am running Node.js and Socket.io on Linux Server.
I've created an online chat room/lobby, I am wondering how can I create like a daemon who has a role of user, he is connected to lobby always and is monitoring lobby, and messages that users post. When specific criteria is matched - report back to server.
For example, some user posts too many messages per minute, the bot would send message to user saying to slow down, if user continues bot would send request to server saying to kick that user.
I am new to node.js and socket.io, so I am not sure how to implement it.
I don't want to hard code every rule or criteria into server itself.
I don't think your way will be working. The way on top of my head is doing it on server. Socket.io can fire any event on client side and send to server, so you can ask server to listen to certain event and handle your logics accordingly on server. Below is some sample code for your reference.
client side:
this event will fire whenever client sends a message.
$("#msgbutton").click(function(){
socket.emit("message","some message client send");
});
server side:
socket.on('message', function(msg){
var now = new Date();
var lastsent = socket.lastsent; //socket is an object and you can store lastsent datetime to it
var diff = now.getTime() - socket.lastsent.getTime();
if (diff/1000 > 2) // if message interval is larger than 2 seconds
{socket.to(room).emit('message',msg); // send message to whole room}
else if
{ // maybe send a warning event to user }
});
The code is not tested, and only consider the time difference between current msg and last message. If you want to monitor the message sent event over certain time course, you will have to write your logics on server to do that. Hope this can give you some pointers.
I'm building a chat application in which I want to load on start the last messages between 2 users.
Here's what I do on the frontend so load the old messageList from the database:
socket.emit('get messageList', data);
on the backend side I load the messages into messages and try to emit them back. I dont want to broadcast.emit since I want to load the data in my session, not in the chat partners.
socket.in(roomId).emit('send messageList', messages);
When I execute this code the messageList of the chat partner gets refreshed. Basically it has the same effect as
socket.in(roomId).broadcast.emit('send messageList', messages);
Before I implemented the rooms a normal
socket.emit('send messageList', messages);
would update my list just as I'd expected. But since I use the code with rooms it doesn't work anymore.
My questions:
Why is that?
Is it possible to send back data from the backend to the client with socket.io?
Or am I doing something completely wrong?
socket.nsp.to(room).emit('room_message','hello world')
I'll make my comment into an answer since that seems to be what will work for you.
If you're just trying to respond to the client that send you a request, you just socket.emit() back to the requesting socket. You're just trying to respond to the sender so you don't do anything differently just because there are chat rooms being used. The response goes to the socket that asked for it, regardless of chat room usage.
To send to a single client, you just send to that client's socket. You only use chat rooms to help with the sending if you want to send to all clients in that room or all clients in the room except one.