I'm making a website which is going to have different chatrooms. Any user can create a chatroom at any time, and another user may join a chatroom when it is available. Max two users can chat in a single chatroom at the same time, but multiple chatrooms can exist.
I'm using AngularJS and PHP, with the PubNub API for the chat functionality. The created chatroom will be stored in a MySQL database, with the following fields:
User1: the user who created the chatroom. It may change or be null if it leaves.
User2: it will be null at first place and will store the user's name of the person who joins the chatroom.
Closed: when both users are offline, it will be true (1), then nobody can join anymore.
I have to update the columns "user1" or "user2" when any of the users leaves the chatroom. Then, check if both users are offline and then update the closed value.
I know that I can save the user's last connection by calling a PHP function via AJAX every 60 seconds, for example. Even I could check if the other user is still online by checking his last connection in the same function, but who is going to call the function to check if the last user left?
I wonder if I have to do that verification every time either any users request the available chatlists or I have to resolve it with another approach.
I guess that I can set a timeout function in PHP each time a user joins/creates a chatroom. That function is going to update the user column to null and update the closed value if both are null. When the user is in the chatroom, each 60 seconds another function will be called to postpone the first one. But I don't know if it is possible, and if it is possible using shared hosting.
I hope you can help me and thank you very much for your attention.
PubNub Presence: Realtime vs Polling
The answer is - do not poll for presence, instead, have your server listen for changes in channel presence using PubNub Presence Web Hooks. Please read this article thoroughly as it details all the aspects of PubNub's Presence Web Hooks and then review the official documentation for PubNub Presence Web Hooks. The sample code for implementing the REST endpoint on your server to receive the web hooks is Node but you can use that code to implement that in PHP if required but if you can use Node for this purpose, it might be a better choice (and you could still use PHP for everything else).
I know your server has a chat room creation process that inserts new chat room record in your database so you don't need to know when the channel becomes active, but when user1 subscribes to the chat room channel, PubNub will send a channel active event via a web hook to your server, if you need to know when that happens.
When user2 subscribes to user1's chat room channel, PubNub will send a join event to your server via web hook and your server can use that event to update your database with user2's information.
Simultaneously, user1 and user2 will subscribe to the chat room channel and monitor presence (rather than poll with hereNow) and receive the join events, as well. When either user leaves the chat room (unsubscribes from the channel) PubNub will send a leave event via web hook to your server and directly to the user that is still subscribed.
Once the last user leaves the chat room, PubNub will send a channel inactive event to your server and your server can invoke its chat room closed process to update your database as required.
This is a fairly high level design and there are some other details to consider but the message here is do not poll PubNub for presence information. Only use hereNow to get the current state of presence of a channel and listen for further presence events from that point forward either via web hooks to your server or via presence/subscribe to your clients apps. In implementation, you actually subscribe with presence (listen for presence events) and then call hereNow.
For a more detailed discussion of your requirements as it pertains to PubNub, I would recommend contacting PubNub Support to put you in touch with a Customer Success Manager and Solution Architect.
Related
I want to develop real time chat with channels and these are my needs:
PHP backend to manage site
Redis as session and data primary storage
Pub/Sub to send messages only to channel's interested users
one WebSocket connection with which the messages will be send and received.
(optional) NodeJS to use great npm packages like timesync or socket.io
I see two different architectures to achieve this:
with Socket.io
with Crossbar.io
These are my questions:
Which architecture I should choose and why?
The key is the user id cannot be obtained from client, because it can be malformed. So in the first architecture I think on every socket message I should attach PHPSESSID value from cookie and on sever-side retrieve PHP session from Redis. Am I right or there is better way to get user id?
I wonder if getting user id in second architecture can be done differently?
Edit:
I choosed Crossbar.io, cause it is very powerful and allows to communicate many different language applications in real time. After studying examples, I come up with this:
On every login user have generated secret key in database.
PHP client (Thruway) connect to Crossbar server and register custom WAMP-CRA authenticator
User's browser connect to Crossbar server and is challenged. Secret and auth_id (user id) are loaded from DB with page load, so it
can accomplish challenge and send response.
PHP authenticator search in DB for user with provided secret and id equal to auth_id. If there is, then it successfully authenticate
session. Now we can trust that auth_id is real user id.
These are my question:
How I can get auth_id on subscribe?
I also added cookie authentication and browser is remembered after authentication. But when I look in Chrome DevTools there is any cookie nor value in local storage. Even after clearing cache my browser is still remember by Crossbar. I wonder how it is possible?
Edit2:
Maybe I was misunderstood, but the main question was choosing appropriate architecture and getting trusted user id. There was no attention so I awarded bounty and after that I was downvoted. I read a lot about real-time apps and finally decided to use Crossbar.io, so I edited question to be related to it. Then people started upvoting, proposing another architectures, but not really answering my questions. After all I managed to do it myself and presented my answer.
About getting user id:
Every real-time chat examples which I saw, was getting id from client. It is unsafe, because client easily can manipulate it, so I needed to find another method. After reading WAMP specs I finally figured out that I have to authenticate user not only in app, but also in Crossbar.io. I choosed the dynamic WAMP-CRA method and implemented as following:
PHP app connect to Crossbar server and register custom authenticator (similar to example)
After user login in app there is generated secret key for him and saved in database. After logout, key is destroyed.
Workflow:
Every loaded page contain user id and secret key loaded from db:
<script>
auth_id = '<?php echo $user->id ?>';
secret_key = '<?php echo $user->secret_key ?>';
</script>
User browser connect to Crossbar.io server and get response with challenge from custom authenticator.
It calculate signature using key and send along with auth_id to Crossbar.io server
Authenticator gets from DB secret for provided auth_id and calculate signature. Then signatures are compared and if they are equal then authentication is successfull.
Now auth_id contain user id and we can trust its value. Now you can refer section 'How I can get auth_id on subscribe?'.
Answers:
How I can get auth_id on subscribe?
By default publishers and subscribers does not have any knowledge about each other, but documentation show there is option to change it by configuring disclosure of caller identity. Then you can get auth_id from callback details:
PHP:
$onEvent = function ($args, $argsKw, $details, $publicationId) use ($session) {
$auth_id = $details->publisher_authid;
...
}
$session->register('com.example.event', $onEvent);
JS:
function on_event(args, kwargs, details) {
auth_id = details['publisher_authid'];
...
}
session.subscribe('com.example.event', on_event);
I also added cookie authentication and browser is remembered after authentication. But when I look in Chrome DevTools there is any cookie nor value in local storage. Even after clearing cache my browser is still remember by Crossbar. I wonder how it is possible?
First of all, clearing cache and hard reload does not remove cookies. When I was asking this question there was any cookie presented, but today I can see cbtid:
There was Chrome update two days ago, so maybe this was caused by bug in previous version.
I deeply light Streamer which is used by NASA to forward truck loads of data per second.The most reliable server for real-time messaging.
Power web, mobile, tablet, desktop, and IoT apps.
Optimized data streaming for web and mobile.
Lightstreamer enables several forms of real-time messaging. It is flexible enough to be used in any scenario, including mission critical applications.
► Real-time Data Push and Web Sockets
► In-App Messaging and Push Notifications
► Pub-sub with fan-out broadcasting and one-to-one messaging
► Firewall and proxy friendly
► Adaptive bandwidth throttling
As for your first question to get the auth_id on subscription , just monitor connection subscriptions then store tier upon successful connection.
Also cookies are not recommended , use jwt.JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.Authentication is one of the big parts of every application. Security is always something that is changing and evolving.JWT helps you solve that concern.Since it is stateless.
PHP Ratchet is one of the best implementations I've used for real-time communications via WebSockets. Its based on ZMQ Sockets which is used in several online gaming applications and chat applications.
The following examples will get you started pretty quick and will answer your questions around auth_id and subscriptions:
http://socketo.me/docs/hello-world
http://socketo.me/docs/push
Overview of the Architecture:
http://socketo.me/docs/push#networkarchitecture
I would advice creating individual connections(toppics) per conversation as it doesn't really take a hit on performance and will add an additional layer of security per chat.
I have an app where basically players challenge each other. At some point their challenge completes and I need to provide them (both of them - there are two players) with an update message, like 'Hey, you won and got 100500 points'. And vice versa - "Hey You looose"
I use websockets and pusher api to tackle the live updates, this works perfectly when player is "online". But what if they are not? The way to go for me looks like I can still handle the event with pusher and instead just displaying the message, I can store it to db to table challenge_notifications with fields messages and seen = 0. it's ok, but what would be the best way then to show this to the player when he comes online next time? I don't want to have ajax request on every page load checking to see if there are any unseen notifications for the user.
I probably somehow need to fetch all pending notifications only once, when they get online?
I use Laravel 5 for my backend.
There was a recent post on the Pusher blog about how to detect if a user is online or not using the Pusher HTTP API: Enabling Smart Notifications with Pusher and SendGrid.
The example uses SendGrid, but you could instead store the update to a database, send them a Push Notification, an SMS etc.
what would be the best way then to show this to the player when he comes online next time?
I guess there are two forms of "coming online":
The user is no longer on the site and has to navigate to the site. In that case as the page loads you can query the DB and serve them up any missed notifications directly (this would seem the easiest solution). Or, if it fits your app architecture, make a single AJAX request when the page loads to get any missed notifications.
If the user has gone offline due to them being mobile or having a bad network connection. In that case you can bind to the connected event using pusher.connection.bind('connected', function() {}); and then make a query to see if they've missed any notifications.
In summary: it would seem that querying the DB for any missed notifications upon normal page render (on the server) would be the simplest solution and wouldn't required much resource usage. But there are alternative mechanisms of delivering a notifications (email, SMS) if they're not online.
I have a website running on shared server with apache/mysql/php. Each of the pages of the site belongs to one registered user and this user,once logged in can edit the page. Other users that are not owners of the page can only look at these pages but cannot do anything else.
Now I'm planning to add chat functionality to my application. The basic idea is that if owner of the page opens it in a browser, and is logged in, he will be shown for other users (that will be anonymous) as "available for chat". Other users visiting the page will be able to send him messages and vice versa. Anonymous users do not need to communicate with each other and they can communicate only with registered user (owner of the page). So basic structure would be like that:
anonymous user(s) visits the page. Registered owner of the page is not looking at the same page and chat is not available.
Registered owner logs in and opens his page in a browser. All registered users in real time are informed owner is available for chat now.
Anonymous users can send him messages.
Registered user receives the messages and can respond back to each user
Other users can join and chat with registered user any time. It all happens in real time and registered user can see who comes in to visit his page and goes away.
Now, in step 3 and 4 I need to know if the registered user is still logged in. If so then the messages can be passed further to intended user. If not then instead I need to send a message that the owner (registered user) is no longer available for chat.
I'm looking for advice on how to best implement it:
using old school php and ajax calls. So every user would send ajax request every second or so to server and server would keep track of each conversation somehow. Relatively easy to implement I think. I'm not expecting large number of users but I can imagine this would be heavy on the server.
using node.js.
Now my questions:
What could be possible problem with solution 1 above. Would that be too heavy on a server constantly throwing ajax requests at it? would would be reasonable number of users I could accept?
Using node js on my shared hosting.. assuming its possible to install it and run it on separate port, how would I best go about checking if registered user is still logged in or not? Any ideas would be much appreciated as am out of ideas here.
You're right that the PHP/Ajax calls can cause quite a bit of server load, especially if your Apache/PHP stack needs a lot of memory to bootstrap. Many chat modules in PHP systems, e.g. Drupal, actually offload this responsibility onto a specialized node.js server (the second approach you mentioned) to facilitate scaling.
Another approach you may consider is to use a real-time network such as PubNub to facilitate this user-to-user data transfer. PubNub has a toolkit called Presence which can help with telling who is subscribed or unsubscribed to each channel.
To fit this to your requirements, I imagine that each user will register with the page they are viewing upon landing on it, by issuing this call in your JavaScript:
<script src="https://cdn.pubnub.com/pubnub.min.js"></script>
<script>
var pubnub = PUBNUB({
uuid : '12345-page35' //You can define this for each user
})
pubnub.subscribe({
channel : 'site-wide-chat,page35', //Subscribe to two channels!
message : receive_chat, //Callback function
presence : user_joined //Callback function
})
</script>
When the "owner" logs in the other users viewing the page are notified. You can accomplish that like this:
function user_joined(event) {
if (event.uuid.match(/page35/)) { //You can set your own test here
// .... admin available for chat
}
}
Presence also has a bunch of nifty features such as the ability to get all users subscribed to the current channel:
pubnub.here_now({
channel : 'page35',
callback : function(m){console.log(m)}
});
I hope this helps you build your minimum viable product. Since everything is implemented at the programming language level, you should have a lot of flexibility crafting a customizable chat solution without adding additional complexity or overhead on your server.
I am a newbie API developer using PHP and we have a new client who wants to include chat system in the app that he wants to develop. I already created the native way by creating a table in mysql with sender, receiver, message, time_stamp field and I already created a set and get API call for Messages. But the client seems not satisfied because by default it is not real time. My front-end developer just call the GetMessage() on an X seconds.
What I want is to make it real time just like what Facebook or Skype app do. When new messages was inserted in the database the server will just poke the app that there is a new message via push notification I think? So in that case the app will not get messages on every X seconds. So basically once I hit the send button, on the other side, the receiver will just see it synchronously.
Take a look at something called triggers. They are activated in mysql when insert, update or delete-event occurs. An important thing though is that SQL has to used for triggers to be executed. The triggers would not execute from external api's.
You might for an example set some value in a table that tells that a new message has arrived for a certain user when a new insert is made into the db.
Starting points:
http://dev.mysql.com/doc/refman/5.0/en/triggers.html
http://dev.mysql.com/doc/refman/5.0/en/faqs-triggers.html
I am building a website app using Facebook PHP API. My current scenario is I want my server side to get updates from Facebook when a user of mine app(he already give the access_token) has some updates. e.g.: if the user post a comment, if someone post a comment on his wall, send him a message, I wish in my server side I can get this notification.
I have checked out the graph API's realtime updates, but I didn't get if I can use the realtime updates to do the above tasks. I wonder if someone know if the realtime updates can do this or not.
The second solution would be: since I have the access_token, I can periodically check the information of the user to see if there is any new updates. The disadvantage of this approach is that it puts lot of heavy on my server side.
The real-time updates API documentation says:
"You can't subscribe to these user connections yet: home, tagged, posts, photos, albums, videos, groups, notes, events, inbox, outbox, updates, accounts. We will add support for more properties and connections in the future."
The three examples you listed are all not available at the moment. For now, you will need to poll the Graph API every so often to check. You will want to prompt the user for offline_access extended permission to be able to check this later after they leave your site.