How to reconnect after you called .disconnect() - javascript

Question: How do you reconnect a client to the server after you have issued a manual .disconnect()?
In my current project, I need to disconnect a client from the server when the user log out from the session. I did a socket.disconnect() to do the disconnection successfully. Server removed the user from the session.
After awhile, the user decided to login again, but socket.io refuses to connect.
I am clear that Socket.IO has implemented reconnection algorithm but clearly this is a different case.
Below is the piece of code where I do the connection. On second trigger of this block of code, object socket was created, but no connect was fired from this object.
//Start the socket
var socket = io.connect(SOCKET_IO_URL);
socket.on('connect', function() {
me.fireEvent('connect');
socket.emit('register', {
hashed_identifier: hashed_identifier,
account_id: account_id
});
});
socket.on('ready', function() {
me.ready = true;
me.log('Handshake done. Listening for new data');
});
socket.on('data', function(data) {
me.fireEvent('data', data);
//Tells server we received it
socket.emit('data', {ack: 1});
});
socket.on('disconnect', function() {
me.fireEvent('disconnect');
});
UPDATE: As requested by #Tony
In fact the whole thing is wrapped under Sencha Touch 2.0, but I believe there is nothing to do with ST2.0
This is my Data Class. Usage of this class is when the user logged in, this class will get initialized. And upon the user logout, the system will call the disconnect() method in this class.
When the user login again, this class is initialized again, but funny is the socket somehow retained all the previous events and sessions it has previously.
/**
* Serve as interface to wait for data communication in between server and client
*/
Ext.define('go.module.connect.Data', {
mixins: {
observable: 'Ext.mixin.Observable'
},
config: {
account: null
},
ready: false,
socket: null,
constructor: function(cfg) {
var me = this,
hashed_identifier = Sha1.hash(go.__identifier);
me.initConfig(cfg);
var account_id = me.getAccount().get('id');
//Start the socket
var socket = io.connect(SOCKET_IO_URL);
socket.on('connect', function() {
console.log('connect');
me.fireEvent('connect');
socket.emit('register', {
hashed_identifier:hashed_identifier,
account_id: account_id
});
});
socket.on('ready', function() {
me.ready = true;
me.log('Handshake done. Listening for new data');
});
socket.on('data', function(data) {
me.fireEvent('data', data);
//Tells server we received it
socket.emit('data', {ack: 1});
});
socket.on('disconnect', function() {
me.fireEvent('disconnect');
});
console.log(socket);
if (!socket.socket.connected){
socket.socket.reconnect();
}
me.socket = socket;
me.callParent([cfg]);
},
disconnect: function() {
this.socket.disconnect();
this.socket.removeAllListeners();
this.socket.socket.removeAllListeners();
},
log: function(msg) {
console.log('## Connect: '+msg);
}
});
And below is my console.log results:
And below is my node.js debug window
I believe the root cause of this funny scenario is that the previously attached connect event listener is not removed thoroughly. How should I remove it? Should I use once? or I should specify the listener function as well. I thought removeAllListeners() is sufficient for this task.

The standard approach in latest socket.io is:
socket.on('disconnect', function() {
socket.socket.reconnect();
})
This is what I've been using in my app and works great. It also ensures that the socket keeps trying to reconnect if the server goes way, and eventually reconnects when the server is back online.
In your case, you need to ensure two things:
You create your socket only once. Don't call socket = io.connect(...) more than once.
You setup your event handling only once - otherwise they will be fired multiple times!
So when you want to reconnect the client, call socket.socket.reconnect(). You can also test this from the browser console in FireFox and Chrome.

You can reconnect by following client side config.
// for socket.io version 1.0
io.connect(SERVER_IP,{'forceNew':true };

I'm doing this way with socket.io 1.4.5 and it seems to work, for now:
var app = {
socket: null,
connect: function() {
// typical storing of reference to 'app' in this case
var self = this;
// reset the socket
// if it's not the first connect() call this will be triggered
// I hope this is enough to reset a socket
if( self.socket ) {
self.socket.disconnect();
delete self.socket;
self.socket = null;
}
// standard connectiong procedure
self.socket = io.connect( 'http://127.0.0.1:3000', { // adapt to your server
reconnection: true, // default setting at present
reconnectionDelay: 1000, // default setting at present
reconnectionDelayMax : 5000, // default setting at present
reconnectionAttempts: Infinity // default setting at present
} );
// just some debug output
self.socket.on( 'connect', function () {
console.log( 'connected to server' );
} );
// important, upon detection of disconnection,
// setup a reasonable timeout to reconnect
self.socket.on( 'disconnect', function () {
console.log( 'disconnected from server. trying to reconnect...' );
window.setTimeout( 'app.connect()', 5000 );
} );
}
} // var app
app.connect();

socket.socket.connect();
gets you reconnected.

It seems to me it is how you handle the disconnect...
Worked for me using socket.io - v1.1.0
wrong way...
var sock = io( '/' );
sock.on( 'connect', function(x) { console.log( 'Connected', x ); } );
// now we disconnect at some point:
sock.disconnect();
// now we try to reconnect...
sock.connect()
// or
sock.reconnect();
// - both seem to create the new connection in the debugger, all events are missing though
correct way...
// As above with 3 extra characters, everything functions as expected...
//events fire properly...
sock.io.disconnect();
// consequently i'm also using (for consitency)
sock.io.reconnect();
// sock.connect() still seems to work however.

socket.io v2.0 (current)
For the peoples that was looking as me for the last version please find the doc extract as below:
To manually reconnect:
socket.on('disconnect', () => {
socket.open();
});

socket.io-client v2.2.0
import io from "socket.io-client"
var socket = io(url) // initial connection
const reconnect = () => {
if(!socket.connected) {
socket = io(url) // reconnects to a new socket
}
}

Related

VueJS access to a variable from another method [duplicate]

This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 1 year ago.
I'm using Vuejs and i would i have two methods one is to make a call and another one is to hangup
i would like to access to device variable that i have in makeCall methods from hangup
error : Cannot set property 'device' of undefined at eval
this is my code :
export default {
components: {Modal},
data: () => ({
device: '',
showModal: false,
form:{
output: ''
},
collection: {
}
}),
created(){
},
methods: {
init(){
this.showModal = true
},
dialer(digit){
this.form.output += `${digit}`
this.count++
},
clearScreen(){
let screen = document.getElementById('output').value
this.form.output = screen.slice(0, -1)
},
hangUp(){
this.device.disconnectAll();
},
makeCall(){
console.log("Requesting Access Token...");
// Using a relative link to access the Voice Token function
getAPI.get("api/contacts/token/")
.then(function (response) {
console.log("Got a token.");
console.log("Token: " + response.data.token);
// Setup Twilio.Device
this.device = new Twilio.Device(response.data.token, {
// Set Opus as our preferred codec. Opus generally performs better, requiring less bandwidth and
// providing better audio quality in restrained network conditions. Opus will be default in 2.0.
codecPreferences: ["opus", "pcmu"],
// Use fake DTMF tones client-side. Real tones are still sent to the other end of the call,
// but the client-side DTMF tones are fake. This prevents the local mic capturing the DTMF tone
// a second time and sending the tone twice. This will be default in 2.0.
fakeLocalDTMF: true,
// Use `enableRingingState` to enable the device to emit the `ringing`
// state. The TwiML backend also needs to have the attribute
// `answerOnBridge` also set to true in the `Dial` verb. This option
// changes the behavior of the SDK to consider a call `ringing` starting
// from the connection to the TwiML backend to when the recipient of
// the `Dial` verb answers.
enableRingingState: true,
debug: true,
});
this.device.on("ready", function (device) {
console.log("Twilio.Device Ready!");
});
this.device.on("error", function (error) {
console.log("Twilio.Device Error: " + error.message);
});
this.device.on("connect", function (conn) {
console.log('Successfully established call ! ');
// $('#modal-call-in-progress').modal('show')
});
this.device.on("disconnect", function (conn) {
console.log("Call ended.");
// $('.modal').modal('hide')
});
var params = {
To: document.getElementById('output').value
};
console.log("Calling me " + document.getElementById('output').value + "...");
if (this.device) {
var outgoingConnection = this.device.connect(params);
outgoingConnection.on("ringing", function () {
console.log("Ringing...");
});
}
})
.catch(function (err) {
console.log(err);
console.log("Could not get a token from server!");
});
}
}
}
</script>
The error was due to how this works in JS. The function declaration in the promise was creating a different this context than the main function. The function keyword sets this based on where it is called, whereas arrow functions set this based on where it is defined in the code.
All you need to do is replace the function(response){} declaration in the getAPI promise .then with an arrow function, and it will work fine.
makeCall(){
console.log("Requesting Access Token...");
// Using a relative link to access the Voice Token function
getAPI.get("api/contacts/token/")
.then((response) => {
Try replacing these lines - to use an arrow function in the .then

Handle Push notification in Nativescript

I am working on application in Nativescript which implements push notification. Lets say server sends push notification and based on action mentioned in payload of notification i will have to redirect in application. This redirection should be performed if user taps on notification from drawer and application is in background. Other case when application should not redirect if its in foreground. I have managed a flag for that as follow
app.js
application.on(application.launchEvent, function (args) {
appSettings.setBoolean('AppForground', true);
});
application.on(application.suspendEvent, function (args) {
appSettings.setBoolean('AppForground', false);
});
application.on(application.resumeEvent, function (args) {
appSettings.setBoolean('AppForground', true);
});
application.on(application.exitEvent, function (args) {
appSettings.setBoolean('AppForground', false);
});
application.on(application.lowMemoryEvent, function (args) {
appSettings.setBoolean('AppForground', false);
});
application.on(application.uncaughtErrorEvent, function (args) {
appSettings.setBoolean('AppForground', false);
});
And on Push notification listener
var settings = {
// Android settings
senderID: '1234567890', // Android: Required setting with the sender/project number
notificationCallbackAndroid: function(data, pushNotificationObject) { // Android: Callback to invoke when a new push is received.
var payload = JSON.parse(JSON.parse(pushNotificationObject).data);
if (appSettings.getBoolean('AppForground') == false){
switch (payload.action) {
case "APPOINTMENT_DETAIL":
frame.topmost().navigate({
moduleName: views.appointmentDetails,
context: {
id: payload.id
}
});
break;
case "MESSAGE":
frame.topmost().navigate({
moduleName: views.appointmentDetails,
context: {
id: payload.id,
from: "messages"
}
});
break;
case "REFERENCES":
frame.topmost().navigate({
moduleName: views.clientDetails,
context: {
id: payload.id,
name: ""
}
});
break;
default:
}
}
},
// iOS settings
badge: true, // Enable setting badge through Push Notification
sound: true, // Enable playing a sound
alert: true, // Enable creating a alert
// Callback to invoke, when a push is received on iOS
notificationCallbackIOS: function(message) {
alert(JSON.stringify(message));
}
};
pushPlugin.register(settings,
// Success callback
function(token) {
// if we're on android device we have the onMessageReceived function to subscribe
// for push notifications
if(pushPlugin.onMessageReceived) {
pushPlugin.onMessageReceived(settings.notificationCallbackAndroid);
}
},
// Error Callback
function(error) {
alert(error);
}
);
Now the problem, is that if application is in killed state and notification arrives. Then it sets flag to true as application is launched which it should not. So due to that redirection is not performed and in other cases when application is in foreground state then also its navigating through pages (which should not be) on receiving notification.
I doubt about flag management is causing the problem but not sure. Would you please guide me if anything is wrong with what i did ?
UPDATE
I am using push-plugin.
Thanks.
I use this for notifications
https://github.com/EddyVerbruggen/nativescript-plugin-firebase
This plugin use FCM, it adds to datas received from notifications foreground parameter so from payload you can determine if app was background(foreground==false, app is not active or was started after notification arrived) or foreground(foreground==true, app is open and active), but you need to some changes to code as they are different plugins
You can use pusher-nativescript npm module.
import { Pusher } from 'pusher-nativescript';
/*Observation using the above.
- Project gets build successfully.
- on run -> ERROR TypeError: pusher_nativescript__WEBPACK_IMPORTED_MODULE_6__.Pusher is not a constructor
- Use: import * as Pusher from 'pusher-nativescript';
- Make sure to install nativescript-websocket with this package.
*/
var pusher = new Pusher('Your_app_key', { cluster: 'your_cluster_name' });
var channel = pusher.subscribe('my-channel');
channel.bind('my-event', function(data) {
alert(JSON.stringify(data));
});

Rumor Socket Disconnected: Connectivity loss was detected as it was too long since the socket received the last PONG message

While using Opentok plugin for video chat (client version - 2.2.5.1 , server Node sdk - 2.2.3) , i get this error after publishing to the session :
Rumor.Socket: Rumor Socket Disconnected: Connectivity loss was detected as it was too long since the socket received the last PONG message
Along with that i also get this error :
OT.SessionDisconnectEvent{
type: "sessionDisconnected",
cancelable: true,
preventDefault: function,
isDefaultPrevented: function,
reason: "networkDisconnected"
}
It does say "reason" : "network disconnected" , but i have double checked and nothing seems to wrong with the network connection .
This is the code i have been using :
session = TB.initSession(TOK_API_KEY,session_id);
session.on("sessionDisconnected", function(event) {
console.log("SESSION DISCONNECTED: "+new Date());
console.log(event);
});
session.on('sessionConnected', function(e){
console.log("SESSION CONNECTED");
var prop = {width: 400, height:300, name:"My Video"};
publisher = TB.initPublisher("broadcast_display", prop, function(error) {
if (error) {
console.log('error initializing publisher', error);
} else {
console.log('publisher initialized successfully');
}
});
});
session.connect(token, function(error) {
if (error) {
console.log(error);
} else {
console.log("Published: "+new Date());
session.publish(publisher);
}
});
The session terminates after this and the publishing also stops . The time it takes to disconnect after publishing starts and the disconnection is consistent (53 secs . Not sure if this is relevant) .
I have also been using GruntJS and EmberJS along with Opentok .
Any help ?
This is a known bug in OpenTok when used with EmberJS. This bug has been found and fixed and should be released in the JS update late this week or next week.

How to use socketio for showing Online/Offline User in Real Time Using Sails?

My Real Time Chat App is based on Sails and SocketIO.It shows all users along with available online users .When a User logged in,a UserConnected socket is emitted and When a User is disconnected,a UserDisconnected socket is emitted ,
My Server side socketio code in config/sockets.js is
onConnect: function(session, socket) {
if (session.passport) {
if (session.passport.user && socket.id) {
sails.io.sockets.emit('UserConnected', {userID : session.passport.user}); }
}
}
//// By default: do nothing
//// This is a good place to broadcast a disconnect message, or any other custom socket.io logic
},
onDisconnect: function(session, socket) {
if (session.passport) {
if (session.passport.user && socket.id) {
sails.io.sockets.emit('UserDisconnected', {userID : session.passport.user});
}
}
//// By default: do nothing
//// This is a good place to broadcast a disconnect message, or any other custom socket.io logic
}
The Problem is that when a User refreshes the page ,it shows connected and disconnected to another User and one major problem is that if one User logged in two different browsers and if any one browser is closed is shows User disconnected to other Users but the User is actually available in another browser. How would I modify/code So that these problems will be fixed?Thanks in Advance
#InternalFX posted a good method; an alternative that you can use on Sails v0.10.x would be:
onConnect: function(session, socket) {
// If this is a logged in user, subscribe the socket to a
// custom "loggedInCount" room
if (session.user) {
var roomName = 'loggedIn'+session.user.id;
sails.sockets.join(socket, roomName);
// If this is the first subscriber, the user is just coming online,
// so notify any subscribers about the state change.
if (sails.sockets.subscribers(roomName).length == 1) {
User.message(session.user.id, {state: 'online'}, socket);
}
}
},
onDisconnect: function(session, socket) {
if (session.user) {
var roomName = 'loggedIn'+session.user.id;
sails.sockets.leave(socket, roomName);
// If this was the last subscriber, the user is going offline,
// so notify any subscribers about the state change.
if (sails.sockets.subscribers(roomName).length == 0) {
User.message(session.user.id, {state: 'offline'}, socket);
}
}
},
This uses Sails' built-in pubsub architecture to notify connected sockets whenever a particular user comes online or goes offline. It requires sockets to subscribe to the user instances they want to know about (using something like socket.get('/user') on the client), which is a good practice to get into. This way you can be notified only about the users you care about (e.g. if you had a "friends list").
Here is the method I am using for a similar purpose.
var online_users = {};
module.exports.sockets = {
onConnect: function(session, socket) {
if (_.isString(session.user_id)) {
if (_.has(online_users, session.user_id)) {
online_users[session.user_id] += 1;
} else {
online_users[session.user_id] = 1;
}
}
sails.io.sockets.emit('crm/online_users', online_users);
},
onDisconnect: function(session, socket) {
if (_.isString(session.user_id)) {
if (_.has(online_users, session.user_id)) {
online_users[session.user_id] -= 1;
} else {
online_users[session.user_id] = 0;
}
}
sails.io.sockets.emit('crm/online_users', online_users);
},
}
It keeps track of how many browsers are logged in as a specific user. So you could use the following.
if (online_users[session.user_id] > 0) { console.log('USER IS LOGGED IN'); }`

ETIMEDOUT problems with node.js & amqp

I have 2 producers and two consumers in my project that uses rabbitmq via amqp module in node.js.
The code for establishing connection for consumers looks like this:
function init_consumers( ) {
console.log( 'mq: consumers connection established. Starting to init stuff..' );
global.queue.consumers.connection = con_c;
var fq_name = global.queue.fq_name;
var aq_name = global.queue.aq_name;
var q_opts = { durable:true };
var subscr_opt = { ack: true, prefetchCount: 1 };
var fq = con_c.queue( fq_name, q_opts, function() {
console.log( 'mq: consumer f queue prepared. ');
global.queue.consumers.fq = fq;
fq.subscribe( subscr_opt, function(msg) {
global.controllers.fc.ParseF( msg, function() { global.queue.consumers.fq.shift(); } );
});
});
var aq = con_c.queue( aq_name, q_opts, function() {
console.log( 'mq: consumer a queue prepared. ');
global.queue.consumers.aq = aq;
aq.subscribe( subscr_opt, function(msg) {
global.controllers.fc.ParseAndSaveToDB( msg, function() { global.queue.consumers.aq.shift(); } );
});
});
}
// connect and init
var con_c = amqp.createConnection( { url: global.queue.consumers.host }, global.queue.con_extra_options );
con_c.on( 'ready', init_consumers );
con_c.on( 'error', function(e) {
console.log( 'consumer error', e );
con_c.end();
if( typeof global.queue.consumers.connection !== 'undefined' ) { global.queue.consumers.connection.end(); }
});
Connection extra options are:
con_extra_options: { reconnect: true, // Enable reconnection
reconnectBackoffStrategy: 'linear',
reconnectBackoffTime: 5000, // Try reconnect 5 seconds
},
After project has launched in rabbitmq management console I clearly see that there is 1 connection established with 2 channels. Very good.
Then, it works just fine until an error (possible related to some disconnections) happens, giving me this output in console:
consumer error { [Error: read ETIMEDOUT] code: 'ETIMEDOUT', errno: 'ETIMEDOUT', syscall: 'read' }
The problem is that when this error happens, amqp tries to reconnect to queue server, but it seems that even with my code above the connection remains opened. In result after several hours of work I have 10 connections with like 50 channels opened, and the only thing remains for me is just to restart the project.
So, I have two questions:
Why this kind of error appears?
What modifications should I implement to stop the growth of connections and channels with time?
Add this to your url parameter
heartbeat=5
This will send heartbeat to AMQP server to let it know that your code is still alive
(You can set to something else except zero)

Categories

Resources