The Firebase chat application seems to suggest that all clients will receive the messages sent to a given FireBase url.
Now, one way of ensuring that users only receive messages sent to a specific channel is to filter messages at the client, but this would mean that all messages will be propagated to all clients and the client would do the filtering.
Is there any way to establish channels at the Firebase server - or does this mean that one would need to create separate firebases for separate channels, which would mean that if one wanted user-specific push-messages, it might require creating one channel/firebase for each user.
So, what is the suggested solution?
The Firebase Data Structure makes this quite easy, actually! The demo app puts the chat messages in the root of the Firebase (i.e. https://samplechat.firebaseio.com/), but you could just as easily use separate locations within your Firebase for separate chats, e.g. /chat1, /chat2, etc. Or better yet, you could have a /chats/ location with an arbitrary number of chats underneath, each named uniquely (possibly using push()).
Then a user could receive and push messages to a particular chat by referencing it directly (e.g. https://samplechat.firebaseio.com/chats/chat-id/) and then they won't get any data for any other chats.
Related
Seems like majority of solutions here require the developer to manually save each user's push token in addition to Firebase saving these tokens as well, then iterate through these and send out notifications. This is not really desirable since I would be storing push tokens in two separate places and need to make sure their lifecycle management is synchronized, which is error prone π’Is there a better way?
Some options I considered:
Give each user a person/unique topic, then map out a geolocation per topic; then filter through these locations, aggregate these topics into batches of 500 and send a push. This is probably the best option so far π€·ββοΈ but seems like a silly use of topics API.
Bucket users in cities, with each city corresponding to a topic; then find all cities near a location, and send a push to those topics. This is doable, but lots of complex city mapping code without much flexibility (vs. considering a simple radius).
Manually store push token β user β geolocation; filter out the ones you want, then send a push to the token specifically. This is problematic for many reasons (multiple device management, push token lifecycle management, data duplication, etc.)
Ideally, there is a way to send out a push notification to a list of user IDs, without even touching push tokens, is there a way to do this?
The only way to associate a device token to a user ID is to store that mapping yourself. You should also assume that one user could have multiple devices. FCM doesn't have a concept of a "user". It only knows device tokens. Your app has to bring the concept of a user, then map that to tokens in code.
Note that any messaging solution that requires topics is not "secure". Anyone can effectively receive messages from any topic.
I am using FCM console to send push messages to the users. Until now I am targetting using User Segments through which I can filter users based on language. But now I need to allow users to subscribe or unsubscribe to the type of alerts they can receive. So I am exploring the option Topics. But now from firebase console I can either target users based on User Segments or Topics.
I want to be able to use Topics with the options I can get in User Segments(where I can filter based on language). Is there a way to make this possible?
Thanks,
Sindhu
Segments can't be targeted with topics. Segments are populated by data collected by Firebase Analytics, and don't identify individual devices. Topics are just names that you make up, and the names must match between the device and server.
You will need to find a way to match up users in a segment to the topic that you create for that segment. You could try to use Remote Config to give clients the name of a topic that matches their segment, then use FCM to subscribe to that topic.
I'm trying to get started implementing Web Push in one of my apps. In the examples I have found, the client's endpoint URL is generally stored in memory with a comment saying something like:
In production you would store this in your database...
Since only registered users of my app can/will get push notifications, my plan was to store the endpoint URL in the user's meta data in my database. So far, so good.
The problem comes when I want to allow the same user to receive notifications on multiple devices. In theory, I will just add a new endpoint to the database for each device the user subscribes with. However, in testing I have noticed that endpoints change with each subscription/unsubscription on the same device. So, if a user subscribes/unsubscribes several times in a row on the same device, I wind up with several endpoints saved for that user (all but one of which are bad).
From what I have read, there is no reliable way to be notified when a user unsubscribes or an endpoint is otherwise invalidated. So, how can I tell if I should remove an old endpoint before adding a new one?
What's to stop a user from effectively mounting a denial of service attack by filling my db with endpoints through repeated subscription/unsubscription?
That's more meant as a joke (I can obvioulsy limit the total endpoints for a given user), but the problem I see is that when it comes time to send a notification, I will blast notification services with hundreds of notifications for invalid endpoints.
I want the subscribe logic on my server to be:
Check if we already have an endpoint saved for this user/device combo
If not add it, if yes, update it
The problem is that I can't figure out how to reliably do #1.
I will just add a new endpoint to the database for each device the user subscribes with
The best approach is to have a table like this:
endpoint | user_id
add an unique constraint (or a primary key) on the endpoint: you don't want to associate the same browser to multiple users, because it's a mess (if an endpoint is already present but it has a different user_id, just update the user_id associated to it)
user_id is a foreign key that points to your users table
if a user subscribes/unsubscribes several times in a row on the same device, I wind up with several endpoints saved for that user (all but one of which are bad).
Yes, unfortunately the push API has a wild unsubscription mechanism and you have to deal with it.
The endpoints can expire or can be invalid (or even malicious, like android.chromlum.info). You need to detect failures (using the HTTP status code, timeouts, etc.) when you try to send the push message from your application server. Then, for some kind of failures (permanent failures, like expiration) you need to delete the endpoint.
What's to stop a user from effectively mounting a denial of service attack by filling my db with endpoints through repeated subscription/unsubscription?
As I described above, you need to properly delete the invalid endpoints, once you realize that they are expired or invalid. Basically they will produce at most one invalid request. Moreover, if you have high throughput, it takes only a few seconds for your server to make requests for thousands of endpoints.
My suggestions are based on a lot of experiments and thinking done when I was developing Pushpad.
Another way is to have a keep alive field on you server and have your service worker update it whenever it receives a push notification. Then regularly purge endpoints which haven't been responded to recently.
I have a server that needs to receive real time updates from Firebase, for multiple users, where each user grants Oauth access to his Firebase data to my app.
My server is implemented using Firebase REST Streaming, based on Server Sent Events.
I need to know if there is a way to multiplex Firebase data pertaining to multiple users on a single stream.
I would like to be able to set up the stream with Oauth tokens pertaining to multiple users, and to subsequently receive real time updates pertaining to the multiple users on the same stream.
Otherwise, it seems that I need to maintain a separate stream per Oauth token, which seems to be non-scalable.
I think Twitter have a Site Streams feature like what I am looking for in their API, implemented via an envelope that indicates the user the message is targetted to.
Does Firebase support anything similar?
A single Firebase REST call will only monitor a single node. E.g.
curl 'https://samplechat.firebaseio-demo.com/users/jack/name.json'
You can control what data is returned from under that node with the orderBy, startAt,endAtandlimitTo...` parameters. E.g.
curl 'https://samplechat.firebaseio-demo.com/users/.json?orderBy="name"&startAt="Jack"'
There is no way to have a single REST request return data from different nodes/nodesets. So unless you find a way to gather all data you want to return under single node, where it can be returned by a single set of query parameters (orderBy, etc), you will have to execute multiple REST requests to get your data.
Note that the SDKs that Firebase provides internally use a web-socket protocol, so are not impacted by this limitation. If an SDK is available for your server-side language (e.g. node.js, Java), you could solve it by using that one.
Could you validate my approach for using Firebase to manage a user notification system?
Basically I want to have user specific channels as well as more general channels which hold notifications. These notifications would appear on an intranet if the user has not viewed them before.
The idea being a server side action will update Firebase endpoints using the REST API either for a specific user or broadcast to everyone. The specific user messages I can easily mark as read and therefore not show them again, its the general broadcast I am struggling slightly with.
I could add a flag(user ID) to the general broadcast to indicate its read but I am concerned about performance as the client would have to check historic broadcast messages for the existence of this flag. I could add a user id to create a new endpoint which should be quicker.
e.g. /notification/general/ - contains the message, this triggers the client which then checks to see if /users/USERID/MessageID exists if it doesnt display the message and create this end point.
Is there something I am missing or is that the best approach?
Are the messages always consumed in-order? If so you could have each client remember the ID of the last message it read in each public channel. You could then use "startAt" on the queue to limit it to only new messages.
If they're not consumed in order, then you'll need some way of storing data about which ones were read and which ones weren't. Perhaps you can have each message get sent out to everyone's personal queue, and then have each user remove read messages.
Since there are already undividual user messages, why not just deliver the broadcasts to everyone individually (think email) rather than trying to store a single copy and figure out who read it.
To reduce bulk, you could store the message content separately, and simply store the ids in a user's queue. Then when they are viewed, you flag them per-user without any additional complexity.
At 100k of users receiving 100 messages a day including broadcasts, with a standard firebase ID (around 20 characters), that comes out to 210,000,000 characters a year (i.e. nothing for a database, and probably still far less than the actual bulk of storing the message body), assuming they never expire and get deleted.