I'm using Php and MySQL.
I have just signup for pubnub push API and successfully made my first push notification using the PHP Push API provided by Pubnub. I'm new into this Realtime technology so I have come up with some questions which I find confusing to understand myself. I have googled many times and searched all over stackoverflow. I didn't get any relevant suggestions or questions elsewhere, so I'm writing down my question here seeking your advice and expertise help.
Pubnub says it's not a good thing to create more than two channels per client. So, in my application, I have a requirement to create more than two channels to listen to notifications happening everywhere on my website but I will go with two channels for every logged in users as Pubnub suggested.
Logged in users listens to Channel1-Public
Logged in users listens to private UsersOwnDynamic-Channel to receive notifications related and only meant for him.
FYI: This link in PubNub says about creating LongChannel names to avoid Channel Snooping
My questions are given below:
A. Do I always have to create a new private Dynamic channel name everytime I logged into the website. If so, how would other users know how to send a notification to my private Channel.Or, do I just need to have only one static channel name stored in database table, so that other authenticated users will query the table and get my private channel name to sent me notifications. If this is the case, don't you think if a hacker get hold of some private channel name of certain users, they will be able to listen to that channel?
B.I'm using PHP and MySQL, so I still cannot think out a way or come up with a solution to send message to private channels of another user.
Lets take an example for a simple friend request system.
- UserA sends a friend request to UserB.
- UserB is listening to his own dynamic private channel name called DynamicPrivateChannelB
(how will UserA find the channel name for UserB which is private? Im thinking the only way for this is that the private channel of UserB should be stored in a database table for every loggedin users to query. Am I thinking the right way ? )
<?php
//first way. How can i possibly achieve this.
$sqlquery = "sent friend request from userA to userB";
require('Pubnub.php');
$pubnub = new Pubnub( 'pubkey', 'subkey' );
$pubnub->publish( array(
'channel' => 'how do i find the private channel name for userB to sent this notification?',
'message' => array('friend_request' => 'A friend request') )
);
//2nd way ? Is this the right way ?
$sqlquery = "sent friend request from userA to userB";
$privatechannelofuserB = "get the channel name of userB from the db table";
require('Pubnub.php');
$pubnub = new Pubnub( 'pubkey', 'subkey' );
$pubnub->publish( array(
'channel' => '$privatechannelofuserB',
'message' => array('friend_request' => 'A friend request') )
);
?>
C. If we are always generating dynamic private channel names, storing in database table, updating whenever new dynamic channel names are generated. I think it will cause a problem because some message won't get delivered as new dynamic private channel names replaces old ones.
D. So, I have many notifications to sent to a single channel like New Friends request, New Private message replies, New gifts requests and many others like that. How do I sent all these data to a channel and how to find out and parse the incoming new notifications data. I know JSON is the format to send but im not sure about the format of sending.
According to this link, a single Pubnub channel can contain only up to 100 messages. Does it mean that if 200 messages comes at once to a single channel the first 100 gets delivered and the remaining is on queue ? How about if 10,000 messages comes at once to a single channel ? Do all the remaining messages stays in queue ? if so, how does it gets delivered to the subscriber in realtime ?
Let me give another simple scenario that I'm trying to achieve.
UserA is authenticated and logged in to the website.
UserA generates his own Dynamic channel name, UserAx732dsw3efsdfsdfsdf
UserA starts listening to his newly created channel UserAx732dsw3efsdfsdfsdf (Now, userA should start receiving messages from others)
- UserB sends a private message to userA. (Now, only userA should get notified on his private channel about the new private
message, how can userB or the System find out the channel
name UserAx732dsw3efsdfsdfsdf because, this is a private channel
generated dynamically by userA , neither the System or
userB has accessed to it. This same thing is happening for userB as well, if userB should be notified by any other entity or by the system again, there should be a way to find out the dynamic
channel name of userB .
Another issue is this scenario is that, if a user is dynamically generating channel name everytime he/she logged in to the website. What will happen to all the messages that was sent to the dynamic channel ? Do pubnub saves all the created channel names on their server? Is there any way that a system or a user can find out whether a channel name is still being own and atleast one user is listening to the channel ?.
I'm curious to know this because of the following concepts that I have:
UserA creates dynamicChannelA when he/she logged in to the website at 1AM.
UserA starts getting lots of notification pushout to his dynamic channel dynamicChannelA
Now, UserA logs out from the website at 1:30 AM, what will happen to the many other users who are still pushing out notification
to his dynamicChannelA because by the next time when UserA
logs into the website, UserA will be listening to different
dynamic channel name.UserA won't be listening to his previous
channel dynamicChannelA .
I'm thinking to use the method of retrieving channel name of a particular user from the database table. Is there any method or way to prevent unauthorised subscription of the channel? Because anybody can subscribe to the channel name if they have the subscribe key and channel name no matter how long the channel name is. I'm just curious because all subscription is happening in the client side and the subscription key and channel names are visible.
There's no one single way of tackling the issues that you've run into. Our customers have used a wide variety of design patterns to deal with them. I myself have run into this type of thing building PubNub apps and I'll help you as much as I can.
Pubnub says its not a good thing to create more than two channels per client. So, in my application, i have a requirement to create more than two channels to listen to notifications happening everywhere on my website but i will go with two channels for every logged in users as Pubnub suggested.
Logged in users listens to Channel1-Public
Logged in users listens to private UsersOwnDynamic-Channel to receive notifications related and only meant for him.
This is a good way to do it, and the way many of our massive scale customers do it. A global channel and a private, user-only channel.
A.
Do i always have to create a new private Dynamic channel name everytime i logged into the website.
Not necessarily, though this is a good way. You can use PUBNUB.uuid() in JavaScript on the client-side to do this. Or, generate it server-side using PHP and render it to the client. Maybe you could set it as a cookie so the client always has access to it.
If so, how would other users know how to send a notification to my private Channel.
They could get the id's from the PHP server; either via the global channel or the user's own private channel, which they are listening to.
Or, do i just need to have only one static channel name stored in database table, so that other authenticated users will query the table and get my private channel name to sent me notifications.
You could do it this way too. You might have the global channel the users can send to be different then the global channel they are listening to. Only the server has that subscribe key. Thus, authenticated users send a message to the server that tells it "I need the appropriate user keys", then the server does a query and sends a message back on that users private channel.
If this is the case, don't you think if a hacker get hold of some private channel name of certain users, they will be able to listen to that channel?
If you withhold the subscribe key on the global send channel, only the server can see the chatter on that channel.
B.
Im using PHP and mysql, so i still cannot think out a way or come up with a solution to send message to private channels of another user.
Lets take an example for a simple friend request system.
- UserA sends a friend request to UserB.
- UserB is listening to his own dynamic private channel name called DynamicPrivateChannelB
(how will UserA find the channel name for UserB which is private? Im thinking the only way for this is that the private channel of UserB should be stored in a database table for every loggedin users to query. Am i thinking the right way ? )
This is very similar to your previous question. There's no one way to do it, but the design pattern I outlined above should work. To recap this design pattern:
Server side
Listens on Global-user-send-channel for user messages. The server is the only entity that has this subscribe key
Can query db to get user-ids, and then send to the various ids at will
Can also send on the Global-user-receive-channel, which all clients are listening on. The server is the only entity that has this publish key.
Client side
Listens on Global-user-receive-channel. This is how it gets mass server broadcasts. Cannot send on this channel (only has subscribe key)
Sends server messages on Global-user-send-channel. Cannot recieve on this channel (only has publish key)
Listens on private user channel. This is how user gets private messages. It can also use this for client-to-client communication.
Prevent abuse by appending all private messages with a private, per-user key stored on the server, and provided during the initial page-load. That way, a client knows if a message claiming to be from the server is legit.
C.
If we are always generating dynamic private channel names, storing in database table, updating whenever new dynamic channel names are generated. I think it will cause a problem because some message won't get delivered as new dynamic private channel names replaces old ones.
If you're careful about when you generate new channel names, this shouldn't be a problem. Keep in mind, the client can always say on the Global-user-send-channel 'hey, I'm here! this is my id. keep me updated'. I usually design my apps to have the clients automatically shout this out every 30 seconds or so.
D.
So, i have many notifications to sent to a single channel like New Friends request, New Private message replies, New gifts requests and many others like that. How do i sent all these data to a channel and how to find out and parse the incoming new notifications data. I know JSON is the format to send but im not sure about the format of sending.
JSON is good for sending and recieving. The way I do it is to have a property called "name" which defines what type of message it is. For example:
{
"id" : "blah_blah_unique_id", // sender_client_id
"name" : "friend_request", // type of message
"data" : { // the data itself
"requested_friend_id" : "blah_blah_some_other_unique_id"
}
}
You can actually use whatever format you want, but we'll wrap it in JSON (usually that means just wrapped in quotes) when it gets pushed through PubNub.
Hope this helps!
New Questions
According to this link, a single Pubnub channel can contain only upto 100 messages. Does it mean that if 200 messages comes at once to a single channel the first 100 gets delivered and the remaining is on queue ? How about if 10,000 messages comes at once to a single channel ? Do all the remaining messages stays in queue ? if so, how does it gets delivered to the subscriber in realtime ?
The 100 message limit is in regards to PubNub.history. If someone is subscribed and 200 messages come in, they will receive all 200 messages.
(Now, only userA should get notified on his private channel about the new private message, how can userB or the System find out the channel name UserAx732dsw3efsdfsdfsdf because, this is a private channel generated dynamically by userA , neither the System or userB has accessed to it. This same thing is happening for userB as well, if userB should be notified by any other entity or by the system again, there should be a way to find out the dynamic channel name of userB .
There's no one-size-fits-all solution to this question, but what I'd do is have the server generate that unique id on page load and render it to the client on your initial HTTP request.
Another issue is this scenario is that, if a user is dynamically generating channel name everytime he/she logged in to the website. What will happen to all the messages that was sent to the dynamic channel ? Do pubnub saves all the created channel names on their server?
You don't have to dynamically generate every time. You could.... but you also set a cookie with that unique id, or pull it from the database and render it to the client on page load (that's what I'd do). We don't save channel names.
Is there any way that a system or a user can find out whether a channel name is still being own and atleast one user is listening to the channel ?.
Not out of the box, but you could implement this easily. Just have your server send out a ping and set up your clients to always respond to pings if they're listening.
Now, UserA logs out from the website at 1:30 AM, what will happen to the many other users who are still pushing out notification to his dynamicChannelA because by the next time when UserA logs into the website, UserA will be listening to different dynamic channel name.UserA won't be listening to his previous channel dynamicChannelA .
The way you can prevent this is periodic (every 30 seconds?) pings from the server, who can keep track if users are still there. In the coming months we'll be launching a presence API to do this automatically, btw.
Im thinking to use the method of retrieving channel name of a particular user from the database table. Is there any method or way to prevent unauthorised subscription of the channel? Because anybody can subscribe to the channel name if they have the subscribe key and channel name no matter how long the channel name is. Im just curious because all subscription is happening in the client side and the subscription key and channel names are visible
The main way is strategically witholding publish/subscribe keys. You're right that anyone with the proper details can listen in - this is a big problem of client-only systems. For the time being, you'll have to come up with creative ways to get around it.
Related
Intro
We're developing a system to support multiple real-time messages (chat) and updates (activity notifications).
That is, user A can receive via Web Socket messages for :
receiving new chat messages
receiving updates for some activity, for example if someone like their photo.
and more.
We use one single WebSocket connection to send all these different messages to the client.
However, we also support multiple applications/clients to be open by the user at the same time.
(i.e - user A connect on their web browser, and also from their mobile app, at the same time).
Architecture
We have a "Hub" that stores a map of UserId to a list of active websocket sessions.
(user:123 -> listOf(session#1, session#2))
Each client, once websocket connection is established, has its own Consumer which subscribes to a pulsar topic "userId" (e.g - user:123 topic).
If user A connected on both mobile and web, each client has its own Consumer to topic user:A.
When user A sends a new message from session #1 to user B, the flow is :
user makes a REST POST request to send a message.
service stores a new message to DB.
service sends a Pulsar message to topic user:B and user:A.
return 200 status code + created Message response.
Problem
If user A has two sessions open (two clients/websockets), and they send a message from session #1, how can we make sure only session #2 gets the message ?
Since user A has already received the 200 response with the created message in session #1, there's no need to send the message to him again by sending a message to his Consumer.
I'm not sure if it's a Pulsar configuration, or perhaps our architecture is wrong.
how can we make sure only session #2 gets the message ?
I'm going to address this at the app level.
Prepend a unique nonce (e.g. a guid) to each message sent.
Maintain a short list of recently sent nonces,
aging them out so we never have more than, say, half a dozen.
Upon receiving a message,
check to see if we sent it.
That is, check to see if its nonce is in the list.
If so, silently discard it.
Equivalently, name each connection.
You could roll a guid just once when a new websocket is opened.
Or you could incorporate some of the websocket's addressing
bits into the name.
Prepend the connection name to each outbound message.
Discard any received message which has "sender" of "self".
With this de-dup'ing approach
there's still some wasted network bandwidth.
We can quibble about it if you wish.
When the K-th websocket is created,
we could create K topics,
each excluding a different endpoint.
Sounds like more work than it's worth!
I am trying to implement private messaging with socket.io for my mobile applications which have a direct messaging feature like Instagram. Right now, I am using Node.js and React Native. I am kinda new to socket.io. I saw many examples of that. However, one thing is not clear in my mind.
User clicks "send message" button. Then I create a socket connection and the user joins a room with socket id. Then user sends a message to that room.
The problem here is, how other user will get the message? Because at this point, I don't think other user knows the room id. Of course if there is a better solution for that, I am open to every suggestion.
One thing you can do is create a room for each person. When the person logs into your app and connects with socket.io, you'll want to have them automatically join the room with their user id.
Then when someone wants to send them a message, they can just send the message to the room for the receiving user.
However, I think if you are building a messaging app, socket.io is not the right way to go. As far as I know you can't listen on sockets while the app is in the background (and even if you could, it would drain your users' battery life). You should use push notifications instead and use the data field (e.g. zo0r/react-native-push-notification and firebase).
I'm working on a private chat messenger application using react-native node and socket.io and need to set up the structure of the project and the data. the internet seems to be overloaded with ton of different answers and I was hoping to get some answers about the problems I have with these solutions
So as far as I understand from the official socket.io documentation
https://socket.io/docs/rooms-and-namespaces/#Namespaces
namespaces were meant to "separate concerns within your application by introducing separation between communication channels" which sounds exactly like what I need for creating a separation between different conversation.
and rooms "Within each namespace, you can also define arbitrary channels that sockets can join and leave."
Here is the data structure I had in mind:
Conversations (namespaces) table -
id, namespace, user1, user2
Messages table-
conversationId, content, from(user1/2)
Here is the general flow I had in mind :
Step 1 -
User connect the main namespace ('/')
Step 2 -
The server returns a list of all user's conversations (namespaces) from the conversation table in the database
Step 3 -
Connect the user to (all?) his namespaces (or should I only connect him to the conversation he enters?)
Step 4 -
Join to default 'chat' room under each namespace (is this really necessary in a private chat application ? I know on slack for example it make sense because we speak to the same group of people under different channels, but is there any other advantage for room that I'm missing? and if it does necessary should the user join all the rooms belongs to him when the applications first fire or should I only join him into the room he enters?)
Step 5 -
When a user enters specific conversations he get all the chat history under this conversation (from Messages table in the database)
Step 6 -
When a new conversation is added we add a record to the conversation table (and we emit 'newConversation' event to the entire namespace/room that include just the sender for now (how do I make sure to notify the receiver about the new namespace related to him should I emit the event to the main name space and validate the access right on connection to namespace attempt or should I use a solution like #)) perhaps this is out of the socket.io scope and should be left to the server to deal with ?
Step 7 -
When a new message is sent we add it to the messages table and emit 'newMessage' event to the entire namespace/room
# on many places I saw some versions of the following solution:
How to send a message to a particular client with socket.io
which basically suggest storing a dictionary relating between each user and his socket id, what I don't understand is, every time a user refresh/login/logout he receive a new socket id and all the events we emitted to his previous socket id will now be lost
My expected result is a chat like whatsapp or facebook messenger (but with private conversations only) where you get notified in messages in other conversation even when you are on the home page and not inside a specific conversation
I am an inexperienced developer, i just started learn node.js socket.io.
I want to make notification for each user if there's post in their wall or someone has replied(commented) to the user's post, just like in the fac*book/go*gle+ notification.
I follow the tutorial here http://www.codesizzle.com/node-js-and-socket-io/
I'm combining it with laravel4 and redis as the handler that publish the message/notif to redis, then nodejs will listen to redis and if there's post/event then send it using socket io to user's browser
Based on my understanding, example:
userA posts something to userB
userB receive the notif that says "user A has posted something on your wall"
to achieve this:
I need to make userB subscribes to its own channel, maybe using his id
then when userA post something, laravel4 will receive the ajax post data
laravel insert the post to MySQL and publish the user's id + his post to redis
after that nodejs will receive the event and publish it to userB's browser.
my question is in my statement "userB subscribes to its own channel, maybe using his id." this means userB will subscribe to channel maybe notif-channel-{userId} -> notif-channel-967 , if i have thousands of users then i will have thousands of different channel, maybe from notif-channel-1 until notif-channel-50000,
will it become a problem?
what is the best practice?
does the flow already correct?
thankyou
note :sorry for the bad english.
UPDATE
After reading some more articles, i think i change the flow to:
UserA posts somethingn on UserB's wall
Then send ajax post to laravel so i can put the message/post into the db
After that emit/push event to socketio thats working on nodejs server to handle the event and push it to userB's channel, tell userB that userA has posted something
If success then notify UserA that his posts is successfull
notice that i dont involve redis in the above flow, any feedbacks?
Using sockets to do this is a pretty complicated way of doing things. It's possible, but all you really need to do is add a timed post request from that page (client side) to check for new comments.
All you really need at that point is in the db. From, To, Date, Message.
With sockets you'd have to set up a channel for each user that has a 'wall', and anyone that is viewing a persons 'wall' will have to subscribe to it, and if it's a lot of people, you will have issues when you need to expand. That means using redis with sockets.io.
While that's 'cool' to do, it's overkill in my opinion.
Build a microservice which has socket connections using caching systems and even data warehousing techniques, and at database level use triggers, when data is crud
Use parse db server which has cool feature of subscribing to live query.
I started looking into node and socket.io.
I already have created a simple chat application and I am amazed at how easy it was.
Now, I would like to take a little bit further and provide a list of online users that have the ability to chat with each other in private.
What would be the best way to approach this?
I read on 0.7's new room feature. Would that be a way to go? Dynamically create a new room each time 2 users need to chat in private? But how the second user is going to be notified of the new room created, so that he can connect there?
Is it better to handle all the above logic myself? Store the rooms and users server side and loop through them each time and send messages to the appropriate ones?
Thanks
If the only functionality you want is for two people to be able to send messages to one another (and not groups of people to have a room), then the logic could be something like this:
When a user connects, store their connection in an object keyed by their username (or in any other data structure that ensures you can find a specific user's connection).
When a Bob wants to talk to Jeff, send the server an event stating such.
The server looks up Jeff's Socket.IO connection in the object from step 1.
The server uses this connection to send Jeff (and only Jeff) the private message.
Hej Thomas
if theres only 2 users talking you dont need use publish att all just send that message from the client to the server and let the server locate the other client and send it down.