Is there a way to make Using server-sent events persistent? - javascript

I need to run a script that updates the user's browser once every second. My need is a one way communication from the server to the client.
To do that, I implemented server-sent events polling from my server to the user's client.
The problem is that the user is allow to open multiple connection to the server "by opening multiple browser tabs" witch is a problem as it adds an overhead on the server.
I would like to limit the connection that is coming from a single user to 1. Meaning a single connection to the server across all their tabs. One connection between a client and the server even if the user have 10 browser tabs open.
This is my server-sent event implementation
var evtSource = new EventSource('getMyMessages.php');
evtSource.addEventListener("getMessagingQueue", function(e) {
console.log(e);
var data = JSON.parse(e.data);
processServerData(data);
}, false);
evtSource.onerror = function(e) {
evtSource.close();
};
Is there a way to make this method of communication persistent?

(This is an indirect answer: how to prevent the overhead of multiple tabs being open. You'll need some communication method between tabs if all of them getting fed the data is desirable, and the shared worker idea looks good for that.)
At the application level: Use a PHP session.
When you use a PHP session the PHP script locks it. This means no other scripts can access the session. In your case that is what you want. (In another recent question, Server-Sent Events Polling causing long delays, that was the cause of a problem.)
This is even better if you require they login to the session to be able to use it. (Otherwise someone who disables cookies can still access multiple tabs.)
The problem is that their other tabs just sit there, and (I believe) the PHP process is using up resources on the server, while it waits for the session to unlock.
You can get around that resource-usage problem by using a session variable to record that they have a current connection, and making sure you release the session lock (as described in the other question). You can then give the user a friendly error message when they try to connect more than once.
At the proxy/firewall level: Set a rule to not allow the same something to have more than one connection at a time to the same URL (your SSE script in this case). Redirect to them an error page explaining why they are not allowed to.
The obvious, but bad, choice for the something is their IP address. That sucks, because multiple users can be coming from the same IP address. You could use their user agent, but just as unreliable. Giving them a cookie, and looking for that is better. (You could even look for the PHP session cookie.)

Related

Socket.io - remove jitter?

I have not been able to get an answer to this anywhere online. I want to remove possible jitter from my nodejs server. I am using socket.io to create connections to node.
If a user goes to a specific part of my website, a connection is started. However, if the user refreshes the site too quickly and often, the connection is created very frequently, and issues arise with my server.
While I realized it's possible this could be solved a couple different ways, I am hoping a server solution is out there. Meaning, whenever a user connects, make sure the user is connected for at least 5 seconds. Then move on. Otherwise, disconnect the user. Thanks for any insight!
First off a little background. With a default configuration, when a socket.io connection starts, it first does 2-5 http connections and then once it has established the "logical" connection, it tries to establish a connection using the webSocket transport. If that is successful, then it keeps that webSocket connection as a long lasting connection and sends socket.io packets over it.
If the client refreshes in the middle of the transition to a webSocket connection, it creates a period of unknown state on the server where the server isn't sure if the user is just still in the middle of the transition to a lasting webSocket connection, if the user is gone entirely already, if the user is having some sort of connection issues or if the user is doing some refresh thing. You can easily end up with a situation where the server thinks there are multiple connections all from the same user in the process of being confirmed. It can be a bit messy if your server is sensitive to that kind of thing.
The quickest thing you can do is to force the connection process to go immediately to the webSocket transport. You can do that in the client by adding an options to your connection code:
let socket = io(yourURL, {transports: ["websocket"]});
You can also configure the server to only accept webSocket connections if you're try to protect against any other types of connections besides just from your own web pages.
This will then go through the usual webSocket connection which starts with a single http request that is then "upgraded" to the webSocket protocol. Once connection, one socket. The server will know right away, either the user is or isn't connected. And, once they've switched over to the webSocket protocol, the server will known immediately if the user hits refresh because the browser will close the webSocket immediately.
The "start with http first" feature in socket.io is largely present because in the early days of webSockets, there were some browsers that didn't yet support them and some network infrastructure (like corporate proxies) that didn't always support webSocket connections. The browser issue is completely gone now. All browsers in use support webSocket connections. I don't personally have any data on the corporate proxies issues, but I don't ever hear about any issues with people using webSockets these days so I don't think that's much of an issue any more either.
So, the above change will get you a quick, confirmed connection and get rid of the confusion around whether a user is or isn't connected early in the connection process.
Now, if you still have users who are messing things up by rapid refresh, you probably need to just implement some protection on your server for that. If you cookie each user that arrives on your server, you could create some middleware that would keep track of how many page requests in some recent time interval have come from the browser with this cookie and just return them an error page that explains they can't make requests that quickly. I would probably implement this at the web page level, not the webSocket level as that will give users better feedback to stop hitting refresh. If it's really a refresh you're trying to protect against and not general navigation on your site, then you can keep a record of a combination cookie and URL and if you see even two of those within a few seconds, then return the error page instead of the expected content. If you redirect to an error page, it forces a more conscious action to go back to the right page again before they can get to the content.

How to refresh the view using websocket getting the data from database

I need to refresh a part of my view without refreshing the whole page.
At my index.html page I have three panels, wich one shows the number of Tickets by it's status, I need to refresh this number every time a new ticket is created or updated. I used Java with Spring Boot and Thymelaf to build my application.
This is my view:
This is the way I'm doing it now:
model.addAttribute("resolvedTickets", atendimentoService.findAllTicketsByStatus(STATUS_RESOLVED).size());
I have tried to use web sockets but i can't figure out how to get this and refresh the panels.
In a standard web interaction, the client (i.e. your web browser) sends a request to your server. Your server receives the request, and sends back the information to show in your browser and then terminates the connection.
WebSockets are a way to create a persistent, two-way connection between the client and the server, but it requires cooperation from both. A lot of shared servers don't allow WebSockets, so you first have to make sure your server is capable of providing WebSockets. (I see from your screenshot that you're running on Heroku, which should have no problem running WebSockets.)
On the server side, you need to set up handling for incoming WebSocket requests. I don't know what language you've coded your server in, so I can't provide any guidance, but there are plenty of libraries that do the server-side part of WebSockets in most languages.
On the client side, you need to set up your WebSocket client. MDN has a great guide on WebSockets that explains what you'll need to do. Basically, all you'll have to do is listen for incoming messages and increment your counter.
var count = 0;
var exampleSocket = new WebSocket("ws://example.com/socket");
exampleSocket.onmessage = function(event) {
count++;
document.getElementById('myTicketCounter').innerHTML = count;
}
For some things, WebSockets are overkill. If you find that this is too much work for too little reward, you can also just set up an AJAX call to fire every few minutes that pings another page on your server and returns the number of tickets and updates accordingly. It won't be instantaneous, but if you don't need down-to-the-second resolution, it'll probably suffice. You can adjust the interval to be as long or as short as you want (to an extent; bombarding your server with constant requests will slow you down a bit).

How does websockets deal with for two tabs of the same browser

I have
1 PHP server (serving http request) and
1 node.js publishing updated data messages (with websockets to each connection).
The php server setup its cookie. In one browser, this cookie is available across all tabs.
When a browser has 2 tabs opened to the domain, there is only one cookie identifying the browser, but 1 message of updated data must be sent to each tabs.
What is the traditional way to distinguish between tabs ?
Should I use another cookie (managed by node.js) to distinguish between each browser tabs ?
Turning my comment into an answer...
There's a separate websocket for each tab. That's how you distinguish different tabs from each other. If you're keeping separate state per tab in your server and you want to allow multiple connections by the same user, then you have to keep the state per websocket connection (you can use the websocket id), not per user.
You don't need to create a separate cookie per tab because the websocket itself already serves as the unique id for each tab.
You haven't said if your app wants identical state in all tabs or if each tab has different state and you would handle things a bit differently on the server side based on the desire. If you want all tabs to receive the same data, then whenever you want to send data to a client, you have to find all websockets that are associated with a given user and send the same data to them.
If you want each tab to behave independently, then you just keep server-side state per websocket and send a response only to the websocket that the response belongs to, not all websockets associated with that user.
As with nearly all questions here on SO, it's a lot easier to answer more specifically if you tell us more about what you're actually doing rather than having a theoretical conversation. For example, if we knew how your app was supposed to work with different tabs, then we'd know which behavior path to follow.

Does server sent events is "Busy Wait"?

I'm building a web site using flask and I wish to do a Push to the client. I've followed real-time-events-python and I was able to create the website.
One thing that I've noticed is that when accessing the Javascript console, there is a GET every 500ms, so I'm wondering if the EventSource of javascript actually sends a GET to the server periodically to see if there are any updates, causing it to be a Busy Wait.
For information, I'm using Flask (python framework) for developing the website and chrome to access it.
Server Sent Events specification
According to the link you provided, yes, the browser sends GETs as an implementation for server-sent events:
The actual protocol for Server-Sent Events is very simple. The client
will open a standard connection to the server and make a GET request.
It expects the server to hold open the socket and send new events by
prefixing them with data: and terminating with two newline characters.
So, on the server side, the connection is supposed to remain open, while data is still being streamed through it. Keep in mind that Server-Sent Events allows for automatic reconnection, so if you are experiencing a lot of reconnects (which I imagine is what all those gets are, unless your client-side code is not written correctly), you should check to make sure that your server side is not closing the connection, which causes the browser to reopen the connection.
As for the "busy wait", if I'm understanding you correctly, you don't need to worry about this. This is handled by the browser, so your code doesn't block while waiting for something.

Is there a reliable way to log a user out when the browser is closed?

I am looking for a reliable way to log out a user or abandon their session when the browser is closed. Is there a way to do this with tabbed browsers?? Any suggestions are appreciated. Thanks!
There is no reliable way to do this immediately when the client closes the browser. There's the beforeunload event, but even then, when you fire an ajax request during this event, it's not guaranteed to ever reach the server. Still then, you've a problem with multiple browser tabs.
Most reliable way is to have a relatively short session timeout in the server side (e.g. 1 minute) and introduce an ajaxbased heartbeat on the client side (e.g. every 30 seconds) to keep the session alive.
There may be better ways depending on the sole functional requirement for which you thought that this is the solution. For example, if your actual intent is to restrict all logins to 1 per registered user, then you'd better collect all logins and the associated sessions and then compare this on each login and invalidate the earlier session if any present. This way it'll work as well on clients with JS disabled.
If you aren't using cookies to preserve your users' login information, it should log them out when they close the browser, because any session cookies should be killed when the browser closes.
Obviously this isn't always the case (see here for an example of Firefox preserving login information after logging out) because "session restore" features we now blur the line between what is considered a "single browser session". (Personally, I think this should be classified as a bug, but that is only my opinion).
There are two possible techniques. The first would be (as yojimbo87 mentions before me) to use web sockets to keep a connection between client and server, and when the socket closes, kill the session. The issue here is that web sockets support is limited, and certainly not possible on anything other than bleeding edge browsers (FF4, Chrome, IE9, etc).
An alternative could be to use AJAX to constantly poll the server to tell it that the page is still being viewed, so if, for example, you send a keep-alive request via AJAX every 30 seconds, you'd store the timestamp of the request in the session. If the user then comes back to the page and the time difference between the current request and the last request is more than say... 45 seconds (accounting for latency), you'd know that the user closed their browser and need to log in again.
In both of these situations, there is however a fatal flaw, and that is that they rely on JavaScript. If the user doesn't have JavaScript enabled, you'd end up ruining the user experience with constant login prompts, which is obviously a bad idea.
In my opinion, I think its reasonable to simply rely on session cookies being deleted by the browser when the user closes the browser window, because that is what they are supposed to do. You as a developer can't be blamed when the client browser performs undesirable behaviour, since its entirely out of your hands, and there's no functional workaround.
A feasible technique would be to use AJAX to send keep-alive requests to your servers quite often — e.g. every one minute. Then you could abandon a session as soon as a keep-alive (or a few in sequence) is not received as expected.
Otherwise, there's no reliable way to achieve that. Since there's not a persistent connection between the browser and the server you can't detect situations that are out-of-control of any JavaScript code you might have running in the browser. For example, when there's a network failure you might want to close the session as well even though the browser's window is still opened. Hence, to make the system robust enough, you should detect network outages as a “side-effect” of the keep-alive mechanism from the browser (e.g. like Gmail does it).
Unless you are using WebSockets or some kind of long polling for each tab which tracks the connection with client in "real time", you will probably have to wait until the session is timed out on the server side.
You can do this via a combination of Jquery,Ajax and PHP
The Jquery
function updatestatusOFF(){
// Assuming we have #shoutbox
$('#connection').load('connection.php?user=<?php echo $_SESSION['username']; ?>&offline=true');
}
The before unload script
<script>window.onbeforeunload = function() { return updatestatusOFF(); }</script>
and the php you would have to write yourself which i'm more then certain you can do.
it isn't the most reliable but it's the easiest way to implement that. if you want real time reporting .. look into comet

Categories

Resources