I'm writing a Chrome background extension with firebase. What I've noticed is that when I hibernate my computer (Win7) while Chrome is open, the connection with firebase disconnects (as would be expected). However, when I return from hibernate it does not automatically reconnect and my .on() events are no longer firing.
I've already looked through the API documentation and this StackOverflow question about detecting disconnects: Detect if Firebase connection is lost/regained
Here's some pseudocode that I'm using to test the connection:
var myFirebase = new Firebase('https://my.firebaseio.com/'); //replace
setInterval(function() {
myFirebase.child('.info/connected').on('value', function (snap) {
if (snap.val() === true) {
console.log('Connected: ' + (new Date()).toString());
}
else {
console.log('Disconnected: ' + (new Date()).toString());
}
});
}, 5000);
This works as expected when running the javascript through a webpage - it connects, then disconnects when I hibernate, then reconnects soon after coming back from hibernation.
However, when it runs as a background page as part of a google extension, it disconnects and never reconnects.
Is there a way to force a reconnect and/or a reason why this isn't working as expected?
Do your permissions look something like this?
"content_security_policy": "script-src 'self' https://static.firebase.com https://myfirebase.firebaseio.com https://s-ord-nss-1.firebaseio.com https://s-ord-nss-2.firebaseio.com; object-src 'self'"
And are you getting any permission errors in the log?
(Just a hunch--no idea if this could be related to connection logic, but I've had problems with permissions in the past.)
Related
I need the socket connection to establish before I can send data from the route to the user (otherwise it is not possible).
In app.js file I have socket connection logic:
app.use(function(req, res, next)
{
req.sio = sio;
next();
});
sio.on('connection',
function(soc)
{
console.log('socket connected');
soc.on('disconnect', function(reason)
{
console.log('socket disconnected');
});
// and more about socket connection here...
});
In index.js file I have route.post logic:
router.post('/route1', function(req, res, next) // user is moved from index.js to route1.js if he fills the form
{
var fromInput = req.body.form_name;
console.log('DATA passed from INDEX.JS: ' + formInput);
if ((formInput !== '') && (formInput !== null) && (formInput !== undefined))
{
function render()
{
//// first we render the page, so the javascript (with socket.io notes) can be read it and then the browser know that socket connection should be established
return new Promise(function(resolve, reject)
{
resolve(res.render('route1'));
});
}
// I need to pass some data AFTER the socked connection is established - cause I move to a different page path - using a **router.post** and cause of that socket connection is disconnected - so I need to wait till its usable again. For simplicity let suppose socket connection is established after 2 seconds (it is a simple check for req.soc.connected):
var soc = false;
setTimeout(function()
{
soc = true; // after 2 sec soc is true (connection is established)
}, 2000);
// Now I want to create an interval that will monitor IF socket connection is established every 100ms (so checking won't happen to often - it is not "resource hungry"). If socket connection is not ready the function should call it self (recursion) if the socket connection is established it (function) should fire a promise.
var arr = [];
arr.push(exe(100, data));
function exe(delay, d)
{
d = data;
return new Promise(function(resolve)
{
if (d === false)
{
setTimeout(function()
{
console.log('wait another ' + delay + ' [ms] - ' + d);
return resolve(exe(delay, d));
}, delay);
}
else
{
console.log('socket connected!');
return resolve(d);
}
});
}
render().then(function()
{
return Promise.all(arr).then(function(arr)
{
console.log(arr);
});
}).then(function()
{
console.log('ALL DONE!');
});
}
});
Comment are in code. If something isn't clear let me know.
#jfriend00
1 - true,
2 - true,
3 - I call render() immediately - so page is loaded and client make a socket connection, then the rest of the code should execute and send the data.
yes I did use POST with a form. There could be socket connection between the server and index page - not a problem I can create one, but I dunno what for.
"or there could be a socket.io connection created in the response to the POST when the browser renders and processes that." I'm trying that one :) I have data in this router.post I want to sent with help of sockets - but first I need to make a connection.
as I understand it... user did use form, so path is changed (socket connection is broken), then I'm in router.post I render the page FIRST - so the browser can read it's JS and make a socket connection, BUT you want to say that my response is not finished? So the browser say - ok you want me to render a page, but what now - cause we are NOT finish yet?!
So I will never establish a socket connection, cause I did not properly response? And cause of this I will not be able to send the data (later code in router.post) cause socket connection is never established cause I did not response properly? Cause my tests show me otherwise - it is working just fine.
you are right - code should works now.
till socket connection is established.
yea, good catch. I will make some kind of database - redis with express session I guess.
So again step by step.
User did fill the form so he is redirect from index.js to route1.js (so it does not make a difference if there is a socket connection BEFORE filling the form or not cause the connection is lost). We are in process of redirecting him (router.post) so I thought I will render the route1 page immediately, so the JS from it can be read by browser, and socket connection can be established (which take time - and IF its possible). So I wait with the data I want to sent to the user (in router.post for example... the form input or whatever) TILL the connection is established, and the send it to the user, with help of socket.io.
The thing is that socket io connection is lost when you change page (path). So I thought (and it could be wrong cause I'm newb) then I wait till it is established, and then send the data. I hope it does make sense.
This structure can never work. Here's what it looks like you're trying to do:
Express server receives a POST request.
Then, you try to wait for a socket.io connection to appear before you process the POST and send a response.
Finally, when you think you've found a socket.io connection, you then call your render() function to "presumably" send a response.
Without really understanding what you're' trying to accompilsh, there are a number of things wrong with the current code:
A POST request comes from either an Ajax call or a form POST. There is no socket.io connection associated directly with either one of those. There could have been a socket.io connection when the page loaded BEFORE the POST request was sent or there could be a socket.io connection created in the response to the POST when the browser renders and processes that.
Even if there was a socket.io connection created when the browser processes the POST response, you're trying to wait for the socket.io connection BEFORE you send the response so you're waiting for something that won't happen until you're done waiting (essentially a deadlock - A won't finish until B finishes, but B can't start until A finishes).
This structure render().then(waitUntil(100, d)) isn't correct. You MUST pass .then() a function reference. You are passing it a promise (the return value form calling waitUntil(...)). This is the least of your problems though because the overall structure of what you're trying to do is wrong.
The whole implementation of waitUntil() is confused and I can't even tell what it's trying to actually wait for.
This is a server that can field lots of connections from lots of clients. You can't just wait for the "next" socket.io connection and assume that connection is from the client you just got a request for. The only way to associate a socket.io connection with an http request is to use some identifying characteristic in both (usually a cookie) and then in the http request, you get the cookie and look up the cookie to see if you currently have a socket.io connection that matches that cookie. This is something that express-socket.io-session helps with.
Unfortunately, you don't describe what you're really trying to accomplish here so I can't point you to a good solution. All, I can really say here is that this scheme will not work. If you want further help with the actual problem, please edit your question to include the problem description in words (not your coding issues). Show the exact sequence of events you want to happen and explain what you're trying to accomplish and why.
I have an angular 5 application which uses a socket.io-client to connect to a websocket server which is hosted on google cloud platform. However instead of opening 1 connection, I see in the browser multiple connection being created, with a new connection opening every second. I added a debug breakpoint in the code where the connection is open and it is triggered only once when the page load. Not sure why it keeps on requesting for a new connection even though the initial connection was successful with 101 code.
private BASE_URL = 'wss://X.XXX.XX.XXX/';
private socket: any;
connectSocket(userId: string) {
this.socket = io(this.BASE_URL, { query: `userId=${userId}`, transports: ['websocket'] });
}
I'd need more information to answer this with certainty, but I could make an educated guess as to what's happening here.
I think the connection code might be placed in a bit of code that gets executed over and over again, causing it to show this behavior.
Additionally, if this is indeed a server problem, you can easily see what the server actually sent back, that caused the socket to close. In Chrome, click on the "name" of the request in the "Network" tab, and then click on "Frames" tab - that should show you exactly what kind of information travelled between the client and the server.
I made a nodeJS script to automate a few actions on a website - which is not mine!
To have a bit more control over what is going on, I would like to listen to the events on the website's socket.io stream.
Works in NODE so far:
Logging into the website and receiving their cookies as a string for further requests
Sending requests with the cookies from the login (do the actual actions)
Open a websocket connection and listen to the public (!) events
Doesn't work in NODE yet:
Read "private" events that are only being sent to a specific user (me)
I inspected a XHR request that is happening in chrome when clicking a specific button on this website. After this request has been sent, the websocket connection on chrome emits events about the status of my action. Of course, these events are only being sent to the user who performed this action.
Doing the exact same request in node (with the cookies from the website login) gives the right response (success), but the socket stream i opened before, only shows some public events - nothing about my actions.
As seen here, it logs in, displays the website's cookies, opens a socket stream. Then it sends a XHR POST request with the displayed cookies in the headers. The response says "success", but the socket.io events popping up once a second are only the public ones (userCount).
http://i.imgur.com/ZUrA2el.jpg
After sending the request, there should be events like "step_calc" popping up, displaying the status of my action.
My script
After receiving the website's login cookies as a string, I am running this:
const io = require('socket.io-client');
const request = require('request');
main()
function main() {
var socket = io(socketURL, {});
socket.on('connect', function () {
setTimeout(function(){
performAction(); // Send XHR to server
console.log(" > Sending XHR request...")
}, 1500)
});
socket.on('step_calc', function (data) { // Personal event about my action
console.log(" >>> Event = step_calc: " + data)
});
socket.on('login_time', function (data) { // Personal event being displayed every few seconds IF LOGGED IN (chrome) console.log(" >>> Event = step_calc: " + data)
});
socket.on('userCount', function (data) { // Public event
console.log(" >>> Event = userCount: " + data)
});
socket.on('disconnect', function () {
console.log(" > [Disconnected]");
});
}
1500ms after being connected to the socket, it would send the XHR request that should make the server emit information to the socket - performAction().
When I check the chrome console:
step_calc follows to a successfull XHR request (account specific)
login_time is being displayed every 2 seconds, but only if i am logged in (account specific)
userCount is being displayed all the time - to everybody
I checked the socket.io-client's API guide and found out about socketIDs. But it only says, how to get this id after connecting to the server...
https://github.com/socketio/socket.io-client/blob/master/docs/API.md#socket
... and yes ... when opening the website, the first thing chrome does, is send a GET request to the website, with data like this:
EIO=3&transport=polling&t=1493058868222-0
The response contains some kind of "sid".
{"sid":"g_mqoOS__________bHb","upgrades":["websocket"],"pingInterval":25000,"pingTimeout":60000}
Well...
Now that I have gathered all of this information, how can I use it?
How can I make the socket connection be "connected" to the cookies that I got from the login (which I am using to send requests to the website)?
I really hope that my question is kind of understandable. Any help is appreciated, I have already put a lot of time into trying to make it work by myself.
Thanks a lot!
Edit:
I tried to add the same cookies from the handshake in chrome. One weird thing is, that the first XHR it does when i open the website (which seems to be the handshake), already contains a cookie named "io", which is then replaced by a new one. If I check the chrome console>application>cookies, I can't see this cookie at all. Where does it come from?
Left side: The request under the XHR tab on chrome
Right side: This is being displayed under the Websocket tab
http://i.imgur.com/VkRouQf.jpg
Are those two different requests or is it the same one in some way?
Does this information help somehow help to solve my problem?
From what I can see, you're not passing the session cookies to the socket.io-client constructor, which would probably mean that the socket connection isn't being authenticated.
Try this:
var socket = io(socketURL, {
extraHeaders: {
Cookie : '...'
}
});
Documented here.
I have a socket.io connection using xhr as its only transport. When I load up the app in the browser (tested in chrome and ff), the socket connects and everything works well until I navigate away from the page. If I reload the browser, I can see the 'disconnect' event get sent out by the client, but the server disconnect event doesn't fire for a very long time (presumably when the client heartbeat times out). This is a problem because I do some cleanup work in the server when the client disconnects. If the client reloads, I get multiple connection events before disconnect is fired. I've tried manually emitting a disconnect message from the client in the window's 'beforeunload' event as well, but to no avail. Any ideas?
I debugged the socket.io server, and I can confirm that Manager.prototype.onClientDisconnect is only getting hit for "close timeout" reasons.
After some more debugging, I noticed the following configuration in the socket.io Manager object:
blacklist : ['disconnect']
That causes this branch from namespace.js to not process the event:
case 'event':
// check if the emitted event is not blacklisted
if (-~manager.get('blacklist').indexOf(packet.name)) {
this.log.debug('ignoring blacklisted event `' + packet.name + '`');
} else {
var params = [packet.name].concat(packet.args);
if (dataAck) {
params.push(ack);
}
socket.$emit.apply(socket, params);
}
The change is detailed in this pull request https://github.com/LearnBoost/socket.io/pull/569. I understand why this is in place for XHR, since anyone could send an HTTP request with random session IDs trying to disconnect other users from the server.
What I plan to do instead is to check each new connection for an existing session id in the server, and make sure to run my disconnect logic before continuing with the connection logic.
I'm doing a realtime app with geddy framework (the basic chat example). But I get and error when the client tries to establish the connection.
here's the server-side code (on the init.js file):
var io = require('socket.io').listen(geddy.server);
io.sockets.on('connection', function (socket) {
console.log("Good!");
socket.emit('new', { message: 'world' });
socket.on('newMessage', function (data) {
console.log(data);
});
});
and the client-side code:
$(document).ready(function(){
startSockets();
});
function startSockets(){
var socket = io.connect('http://localhost:4004');
socket.on('new', function (data) {
alert(data);
//socket.emit('newMessage', { my: 'data' });
});
}
When I try to connect to localhost:4004/ I get the next warn:
debug - setting request GET /socket.io/1/websocket/G_GapksVv1J4iBZIUVe3
debug - set heartbeat interval for client G_GapksVv1J4iBZIUVe3
debug - websocket writing 7:::1+0
warn - client not handshaken client should reconnect
info - transport end (error)
debug - set close timeout for client G_GapksVv1J4iBZIUVe3
debug - cleared close timeout for client G_GapksVv1J4iBZIUVe3
debug - cleared heartbeat interval for client G_GapksVv1J4iBZIUVe3
debug - discarding transport
besides Chrome console gives this error:
WebSocket is closed before the connection is established.
I don't know what can cause these. Any ideas?
The problem is that Socket.io needs to connect to the server after it's started, and the server doesn't start until after the code in init.js has run. The current (hacky) solution in the existing built-in RT code (as of Geddy v0.11) is to put this sort of code in an after_start.js file in the config directory, which Geddy runs after the server starts up. This should work as a workaround in this case too, where you're wiring up Socket.io to the server yourself.
This is obviously not ideal, and a major goal for v0.12 is fixing up the RT integration so it's much more usable and useful. If you have input into how you think this should look, definitely hit us up in IRC (#geddy on Freenode.net), or on the mailing list (https://groups.google.com/group/geddyjs).