I am currently using Ratchet with laravel 4 for my application's chat feature. I am using the following JS in the front-end to handle the web sockets.
function startChatSession(){
var person = prompt("Please enter your ID", "");
if(chatBoxes.length <= 0)
chatBoxes.push("onlineList");
if (person != null && person != "") {
myself = person;
if(conn == null){
conn = new WebSocket('ws://192.168.1.5:8080?'+person); // 'user facebook id' instead of name
conn.onmessage = msgReceive;
conn.onopen = function(e) {
console.log(e);
};
conn.onerror = function(e){setTimeout(startChatSession,5000);};
}
}
}
Now my problem is that the web socket connection disconnects on page refresh and page transition. After searching the web I decided this couldn't be fixed in the front-end. So I want to preserve the chat session at the Laravel's end. I am already storing the online users in the DB, when a connection is opened and deleting them on close.
I am trying to come up with a work around check for online users, since the sockets opens and closes often it creates too many inserts and deletes to table. How can I attach the socket with Laravel session or create a work-around that could solve my problem?
Related
The websockets server example works as expected. On browser refresh (e.g. S-F5 with chrome), the websocket disconnects, still working as expected. After refresh, the user has to give name again to connect to the server.
How would you capture the refresh-event and keep the user connected? E.g.
Is this doable only on server side or does the client require modifications as well? Haskell examples or links to such would be nice as well as hints on how to do this!
How would you capture the refresh-event...
There isn't really such a thing as a refresh event to detect (I would love to be proved wrong in this!)
... and keep the user connected...
The refresh, or rather, the leaving of the page before loading it again, causes the websocket to disconnect, and (especially if this is the only page on the site that is open), there isn't really much you can do about it.
So the only thing that can be done, is have some sort of auto-reconnect the next time the page loads. A solution that allows this is one where..
when the name is initially entered, the name is saved somewhere in the browser;
when the page reloads, it checks for a previously saved name;
and if it's found, it connects again using that name.
Local storage is one such place to save this, as in the below example, modified from https://github.com/jaspervdj/websockets/tree/master/example to save/retrieve the name from local storage.
$(document).ready(function () {
var savedUser = sessionStorage.getItem("rejoin-user");
if (savedUser) {
joinChat(savedUser);
}
$('#join-form').submit(function () {
joinChat($('#user').val())
});
function joinChat(user) {
sessionStorage.setItem("rejoin-user", user);
$('#warnings').html('');
var ws = createChatSocket();
ws.onopen = function() {
ws.send('Hi! I am ' + user);
};
ws.onmessage = function(event) {
if(event.data.match('^Welcome! Users: ')) {
/* Calculate the list of initial users */
var str = event.data.replace(/^Welcome! Users: /, '');
if(str != "") {
users = str.split(", ");
refreshUsers();
}
$('#join-section').hide();
$('#chat-section').show();
$('#users-section').show();
ws.onmessage = onMessage;
$('#message-form').submit(function () {
var text = $('#text').val();
ws.send(text);
$('#text').val('');
return false;
});
} else {
$('#warnings').append(event.data);
ws.close();
}
};
$('#join').append('Connecting...');
return false;
};
});
... Is this doable only on server side or does the client require modifications as well?
It definitely needs something done in the client to auto-reconnect. The bare bones version above needs no changes to the server, but if you wanted something fancier, like having the cases of initial connect and auto reconnect handled/shown differently somehow, then the server might need to be modified.
I've been able to add chat functionality to my website but I'm wondering if there is a more efficient way to do it. This is the current structure of the chat:
HTML page with javascript functions:
sendChat(elmnt) {
var result = XHR("http_sendChat.aspx","POST",0,elmnt); //xmlhttprequest to send chat message by posting elmnt string to page. 0 used for not polling
}
getChat() {
var result = XHR("http_getChat.aspx","GET",50,""); //polls page every 50ms to get new chat messages
addMessageElmnt(result); //update chat window with new messages
}
On the server side in vb.net http_sendChat.aspx:
Application.Lock
Application("chat") = Application("chat") & Request.Form("message") //Global application object stores chat log
Application.Unlock
On the server side in vb.net http_getChat.aspx:
Dim chatTemp
chatTemp = Mid(Application("chat"),Session("chatIndex")) //fetches whatever chat data hasn't been fetched yet
Session("chatIndex") = Session("chatIndex") + Len(chatTemp) //set index to last read position
Response.Write(chatTemp)
There is some more code that mostly checks to make sure the users account is activated and such but as far as the chat goes, is there a better way to do this? I ask because its fairly slow when there are like 100 people logged in and using the chat.
I'm trying to create a desktop app with node-webkit. A part of this app require the use of facebook to get/post some content to any profile (facebook user) that use my desktop app on my personal computer.
Regarding facebook api documentation (https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.0) , I have to manually implement the login flow and use the following URI as the redirect URI: https://www.facebook.com/connect/login_success.html
Currently, in my node-webkit app, via a child window (a popup), a user can login to facebook and authorize my desktop app to interact with it's profile.
Here is a part of the code:
var url = "https://www.facebook.com/dialog/oauth?client_id=myclientID&redirect_uri=https://www.facebook.com/connect/login_success.html&response_type=token&scope=publish_actions";
loginWindow = window.open(url, 'Login facebook', 'location=yes,toolbar=yes,menubar=yes,directories=yes,status=yes,resizable=yes,scrollbars=yes,height=480,width=640', false);
After that, the user is redirected to the following URI and as mentioned in the doc, the access token appear correctly:
https://www.facebook.com/connect/login_success.html#access_token=theBigTokenString&expires_in=3864.
But it appears only for few seconds and after that the url is replaced by https://www.facebook.com/connect/blank.html#_=_ (with a security warning message).
I've read some post that propose to add eventListener like hashchange to the opened window in order to capture the access token. But after some redirect within the child window, I'm no longer available to interact with it via javascript.
So finally, I can't get the access token that the child window has retrieved and make visible for few seconds.
Is anyone can help me to get this user access token with node-webkit?
I really don't want to use a server (for hosting a web page) between my desktop app and facebook.
Thanks in advance for help.
With the help of an other question (here) I found a solution to my problem.
I post the code that I use now and I Hope it will help someone else:
var url = "https://www.facebook.com/dialog/oauth?&client_id=myBigClientID&redirect_uri=https://www.facebook.com/connect/login_success.html&response_type=token&scope=publish_actions";
function Response() {
this.access_token = null;
this.expires_in = null;
};
var response = new Response();
//function called every 500ms to check if token is in url
window.hashUpdate = function() {
if(window.loginWindow.closed){
window.clearInterval(intervalId);
start(); //just a callback that I'm using to start another part of my application (after I caught the token)
}
else {
var url = window.loginWindow.document.URL;
var tabUrl = url.split("#"); //first split to separate the domain part and the parameter part
var paramString = tabUrl[1]; //I concerned only by the second part after the '#'
if(paramString != undefined){
var allParam = paramString.split("&");
for (var i = 0; i < allParam.length; i++) {
var oneParamKeyValue = allParam[i].split("=");
response[oneParamKeyValue[0]] = oneParamKeyValue[1]; //store my token in form of key => value
};
//close the window after 1500ms
setTimeout(function(){
window.loginWindow.close();
}, 1500);
}
}
}
//open the url and start the watching process
window.loginWindow = window.open(this.url, 'Login facebook', false);
this.intervalId = window.setInterval("window.hashUpdate()", 500);
I am working on Weemo JS API for video conference.
1) I need some technical help for identify online user for conference.
2) How can i pass data from caller to callee?
3) How online user can disconnected from cloud?
please provide some technical ref for same.
Thanks.
You can know if a user is online or not by using the weemo.getStatus('USER_UID') method.
(void) getStatus('USER_UID')
When 'USER_UID' is the value of the target user Uid (String).
You will need to use the weemo.onGetHandler(name, obj) callback to catch the answer.
Here is an example of how to get the status of a user with a 'USER_ID' equal to 'userTestStatus':
var weemo = new Weemo('AppId', 'Token', 'Type');
weemo.onGetHandler = function(name, obj) {
switch(name) {
case 'status':
var uid = obj.uid;
if(obj.value == 0) {
console.log("User "+uid+" is offline with a status "+obj.value);
} else {
console.log("User "+uid+" is online with a status "+obj.value);
}
break;
}
};
weemo.onConnectionHandler = function(message, code) {
console.log("Connection Handler : " + message + ' ' + code);
switch(message) {
case 'sipOk':
weemo.getStatus('userTestStatus');
break;
}
};
weemo.initialize();
FYI: In this example I used the getStatus in the onConnectionHandler after receiving a "sipOk" because I want to make sure that my user is completly connected before runing a getStatus. Once you user is connected to the Weemo Cloud you can execute a getStatus out of the onConnectionHandler.
Once connected you can disconnect your user by using the weemo.reset() method. This will disconnect your user from the Weemo cloud.
(void) reset()
The reset function is used in order to properly disconnect the user from the cloud, and be able to connect to the real-time platform with other credentials.
You can find more details in the documentation and sample code available on the Weemo github here.
You can also find the full Weemo JavaScript API here
I am using symfony2 to build some app. In that app I have chat app. I am using attached session in chat.
1) On login I fire up event listener to catch user/pass from login, connect to openfire server and get sid and rid.
2) After that i am storing that data in session so I can use them later on every page where I have chat.
Problem occurs when page is reloaded/refreshed.
My guess this is because ajax request to url:7070/httpd-bind is canceled strophe sends terminate to openfire server. Bu I can not find anywhere terminate stanza.
I am have patched strophe.js to use sync on page unload but again that is not working.
Chat.connection.flush();
Chat.connection.sync = true; // Switch to using synchronous requests since this is typically called onUnload.
Chat.connection.disconnect();
Please suggest solution for this, I am on 10 hour coding and I have no idea how to solve this.
I can sotre user/pass in session but that is just stupid. Why attached session exists if I have to do that.
UPDATE
After trying to figure about this rid plus+1 etc I noticed that rid is changing on presence, on message on message sent on roster on roster change so I made a XMLHttpRequest on each to remember new rid in session. For some reason localstorage is sometimes working sometimes not.
Now i have rid up to date all the time.
I think I got this. Problem was in rid and presence.
1) First you have to figure out from your logs if your rid is increasing or decreasing.
My was decreasing by one. So I substract -1 from my Chat.connection.rid
2) In my openfire logs I figured out that I was sending unavailable status on page refresh
so I changed my window.unload function to send presence to online. N
Now I am refreshing page million times and i never got disconnected.
Now I just have to figure out how to remember connection.rid to localStorage for non HTML browsers.
To start openfire in debug mode you just add ./openfire.sh -debug. Then you will be able to se everything in debug.log
This did trick for me. If this is doing trick for you please +1 and accept answer.
Do not forget to terminate session on logout :)
UPDATE
This is my on window.onunload function
window.onunload = function(ev){
var initialPresence = $pres().c('show').t("cao").up().c('status').t("sad");
Chat.connection.send(initialPresence);
store.set('session_rid', parseInt(Chat.connection.rid)-1);
//save rooster contacts state
var contacts = document.getElementById('records').getElementsByTagName('li');
var id_value;
var class_value;
var status;
var el;
for(i= 0; i < contacts.length; i++){
el = contacts[i].getElementsByClassName("mood")[0];
status = el.textContent || el.innerText;
Array.prototype.slice.call(contacts[i].attributes).forEach(function(item) {
if(item.name == "id"){
id_value = item.value;
}
if(item.name == "class"){
class_value = item.value;
}
store.set('user'+i, { id: id_value, class_name: class_value, status : status });
});
}
Chat.disconnect();
}
This is my on window.onload function
window.onload = function(){
if(store.get("session_rid")){
var obj;
var id;
var class_name;
var status;
store.forEach(function(val, key) {
if(val !== "session_rid"){
setTimeout(function(){
obj = eval(key);
id = obj.id;
class_name = obj.class_name;
status = obj.status;
if(document.getElementById(id)){
document.getElementById(id).className = class_name;
document.getElementById(id).getElementsByClassName("mood")[0].innerHTML = "<span>"+status+"</span>";
}
}, 1000);
}
})
}
}
This is working for me. I used store.js to store data so it can work on IE.
I used attached sessions.
//json is from ajax call on some php script that has started attached session on user login
var obj = JSON.parse(json);
connection = new Strophe.Connection(BOSH_SERVICE);
connection.attach(obj.fulljid,
obj.sid,
(store.get("session_rid") ? store.get("session_rid"):obj.rid),
justDoIt);
full_jid = obj.fulljid;