How to deliver messages atomically when using Firebase without a backend logic - android

I´m creating this chat app using Firebase. I wanted to create a system
where every device having the chat app installed is responsible for delivering chat messages.
Even if the device did not send the message it plays a part in the pool of workers, that deliver chat messages.
Now for a normal chat app the device that creates the chat message can easily send the message using E.g. OneSignal.
In my case user can chat with abstract things and there can be many people listening for new chat messages. One is sending and 1000+ is listening.
Here is where the problem comes. If one device is responsible for notifying 1000+ other it can get really heavy on the load. I was thinking all other devices can help out with the delivery,
so I´m trying this Firebase database notification entry:
{
"NOTIFICATIONS" : {
"-Kg4_cnR9T8Efx77rL2n" : {
"targetId" : "-KfpVVenyQccKqAxxrvE",
"text1" : "There´s a message for you",
"text2" : "Pluto",
"text3" : "",
"time" : 1490447404504,
"type" : "chatMessage"
},
"-Kg4_eWQFZndhztPqSTp" : {
"targetId" : "-KfpWz7ZWBAa_8pLM7tI",
"text1" : "There´s a message for you",
"text2" : "Saturnus",
"text3" : "",
"time" : 1490447411536,
"type" : "chatMessage"
}
}
}
and when one device is creating a message it post this new NOTIFICATIONS that will be picked up by all devices that are listening.
Now since all devices is listening on the NOTIFICATIONS and will grab one NOTIFICATIONS and send the chat message heads up, to all other devices that are registered on the targetId the problem obviously arise.
Here are the TARGET_VISITORS. This are the users that are registers for new chat messages.
{
"TARGET_VISITORS" : {
"-KfpVVenyQccKqAxxrvE" : {
"HnhLyXRxUINmlltK3jdsfxx2QBYiQ53" : {
"notify" : true,
"time" : 1490300590623,
"userFirebaseId" : "HnhLyXRxUINmlltK3jdsfxx2QBYiQ53"
}
},
"-KfpWz7ZWBAa_8pLM7tI" : {
"HnhLrryXUINmlltK3jdsfxx2QBYi3455" : {
"notify" : true,
"time" : 1490300581677,
"userFirebaseId" : "HnhLrryXUINmlltK3jdsfxx2QBYi3455"
}
}
Can I use the Firebase Transaction for this?
Like one device pick up a NOTIFICATIONS and then gets maybe 10 TARGET_VISITORS (there can be 1000+), and in a Firebase transaction locking down TARGET_VISITORS to perform the chat message heads up delivery on his userFirebaseId or OneSignal PlayerId.?
After that the TARGET_VISITORS can save the NOTIFICATIONS id and by doing that prevent getting duplicate messages.
Maybe creating a visitor lock rule like:
"TARGET_VISITORS_LOCK": {
".read": "auth != null",
"$FirebaseId": {
// This need to be a final entity.
// we can write as long as old data or new data does not exist.
// In other words, we can write if we're deleting or creating data, but not updating data.
".write": "!data.exists() || !newData.exists() && auth != null"
}
},
And then run an Data Fan Out updateChildren on the TARGET_VISITORS_LOCK, if it fails it means some other device is running the updateChildren before me and sending the notification to the single device. What will happen her if device having an offline period?
Many devices in the pool of workers can have the same NOTIFICATIONS to try to send and they will fight over TARGET_VISITORS, so to speak
Then comes the problem to know when to remove a NOTIFICATIONS entry, remove it when all TARGET_VISITORS have been notified :) Yea this is quite fun :)
It´s all theoretical at this point and i´m reading a loot so hoping for some input about this?

Related

Not getting the "MESSAGE_DELIVERED" Firebase event

I am trying to measure the latency between having a message exit Firebase Servers and being received on an Android app via the Firebase SDK. I have BigQuery integrated with my Firebase project, and have tried adding the following code:
// In the manifest:
<meta-data android:name= "delivery_metrics_exported_to_big_query_enabled"
android:value="true"/>
// In my Application object:
FirebaseMessaging.getInstance().setDeliveryMetricsExportToBigQuery(true);
The code seems to be exporting data to BigQuery. However, to calculate what I want I need timestamps for two different types of events associated to the same message id, "MESSAGE_ACCEPTED" and "MESSAGE_DELIVERED". Then, all I have to do is run a simple query that calculates the timestamp difference between those two.
My problem is: I can never seem to get the "MESSAGE_DELIVERED" variant for a given message id. I only ever get the "MESSAGE_ACCEPTED" side of the equation.
I am sending messages to the Android device via my own JavaScript app, and the request I make is like so:
app.get('/triggerAnt', function(req, res){
axios.post('https://fcm.googleapis.com/fcm/send', {
to:<TOKEN_FOR_DEVICE_GOES_HERE>,
notification:{
"title":"TESTNOTIFICATIONLATENCY",
"body":"TESTINGLATENCY"
},
fcm_options: {
analytics_label:<LABEL_HERE>
}
}, {headers: headers})
.then((response) => {
console.log(response.status);
}, (error) => {
console.log(error);
});
})
I would like to point out that the notification does effectively reach the device and I can open it too.
Is this delay on BigQuery's side or am I doing something wrong?
Thank you.

How to send a notification based on spinner value on android app?

I'm doing my final year project about flood push notification. Previously, a user will retrieve notifications whenever the value in database changes from 0 to 1. But right now,in my app, the user can choose which places he parks his car and he can retrieved status and notification based on the park's place whether it's zero or one. As for example, User A set his spinner value in Mid Valley and User B set his spinner value in KPS. User A will get notification when FLOOD_STATUS_MID_VALLEY is 1, while User B didn't receive any notifications because FLOOD_STATUS_KPS is still 0. Anyone can help me on how to send notification based on the spinner value in the app?
Screenshot of my app
Screenshot
below is the python code that running on server to send notification based on a value called "FLOOD_STATUS" in firebase database
from pusher_push_notifications import PushNotifications
config = {
'apiKey': "APIKEY",
'authDomain': "car-app-push-notification.firebaseapp.com",
'databaseURL': "https://car-app-push-notification.firebaseio.com",
'projectId': "car-app-push-notification",
'storageBucket': "car-app-push-notification.appspot.com",
'messagingSenderId': "596729642105",
'appId': "APPID",
'measurementId': "G-9LMJGS1BDW"
}
firebase = pyrebase.initialize_app(config)
db = firebase.database()
beams_client = PushNotifications(
instance_id='49f62b05-bd81-4040-ab57-80afa56a8680',
secret_key='SECRET KEY',
)
def stream_handler(message):
print(message)
if(message['data'] is 1):
response = beams_client.publish_to_interests(
interests=['hello'],
publish_body={
'apns': {
'aps': {
'alert': 'Hello!',
},
},
'fcm': {
'notification': {
'title': 'Alert!',
'body': 'It is starting to flood, please remove your car immediately!',
},
},
},
)
print(response['publishId'])
my_stream = db.child("FLOOD_STATUS").stream(stream_handler,None)
As this is your FYP, I won't provide any code for this.
When a user changes where they parked, you will want to change their device interest to match the relevant location.
When the FLOOD_STATUS is updated to 1 for a given location, you send the notification to the matching interest.
I suggest that, when the user A select the MID_VALLEY in the Spinner you send the selected value to the server. I recommend you to have a look on this tutorial to see how to get the selected value from Spinner
At server side, when the FLOOD_STATUS_MID_VALLEY is 1 you only send the notification to the user A(because you knew the FCM token of the user A).
If you want to custom the item of Spinner you can watch this tutorial.

Firebase: Check for changes in JSON and automatically send notification

UPDATE:
Ok so from all the comments I got convinced that using Firebase is the best solution for a number of reasons but how would I check for that change (canceled == yes) in my json file from firebase and automatically send the notification if the course is canceled.
Sample JSON response:
{
"class" : "Class",
"time" : "00:00",
"trainer" : "T",
"canceled" : ""
},
{
"class" : "Class",
"time" : "00:00",
"trainer" : "T",
"canceled" : ""
}
INITIAL QUESTION
I am parsing a json api and one of the fields is called canceled.
I would like my app to set a notification whenever that canceled key has a value of yes and so far it's easy, just create a simple notification like in the android developer topic and if canceled == yes update the Builder and then notify();.
The issue here is how can I keep checking for changes in the json after the app has been closed and set the notification ?
I have access to the server and make changes to the api if required.
Can I do this without the help of any third party services?
As #Sujal mentioned With Android O you have restriction on running background service for a long time. So It's better move this thing to server side. Whenever there is a change in the status i.e. Whenever key canceled becomes yes send a notification to android device which would show the Notification.
Ref : https://firebase.google.com/docs/cloud-messaging/
Ref : https://www.codementor.io/flame3/send-push-notifications-to-android-with-firebase-du10860kb

Receive GCM Topic Push message in Titanium

I don't have any more hair to tear out and need help..
I want to send messages to a topic (or channel) from a server (via GCM) so it reaches all devices subscribing to that topic.
Sending push messages to individual devices works fine and the format for sending to topics is the same, except for specifying a deviceToken, specify the topic in the for /topics/mytopic
This is described here:
https://developers.google.com/cloud-messaging/downstream
https://developers.google.com/cloud-messaging/topic-messaging
On the Titanium side (Android for now but the plan is IOS too later on) I register the device to a channel "myChannel". I can verify this by a success message returned and also in Appcelerators console.
Now, I simulate a server with curl, and send a message to "myChannel" to GCM. The message response with success and I receive back a message_id from GCM.
curl -H "Content-Type:application/json" -H "Authorization:key=APIKEY" --data '{"to": "/topics/myChannel","data": {"payload":{ "message": "Hi!" } }}' https://gcm-http.googleapis.com/gcm/send
My problem is that this message is not routed to the device.
I am guessing there is some syntax conversion needed between the channel subscribed to in Titanium and the one I use to GCM but I don't know.
The funny thing is, as soon I put in the deviceToken in curl it works perfectly.
Am I missing something fundamental here? Is the channel not there to route the same message to multiple devices subscribing to it?
Any help, clues are much appreciated.
My code looks like this:
// Require the module
var CloudPush = require('ti.cloudpush');
// Initialize the module
CloudPush.retrieveDeviceToken({
success: deviceTokenSuccess,
error: deviceTokenError
});
CloudPush.addEventListener('callback', receivePush);
function receivePush(evt) {
alert("Notification received: " + JSON.stringify(evt.payload));
}
function deviceTokenSuccess(e) {
Alloy.Globals.DeviceToken = e.deviceToken;
Titanium.API.info(Alloy.Globals.DeviceToken);
// Subscribe to topic
var Cloud = require("ti.cloud");
var subscribe_data = {
device_token: Alloy.Globals.DeviceToken,
channel: Alloy.Globals.topicChannelID,
type: Ti.Platform.name == 'android' ? 'android' : 'ios'
};
Cloud.PushNotifications.subscribeToken(
subscribe_data, function (e) {
if (e.success) {
Titanium.API.info('Subscribed successfully');
} else {
Titanium.API.error('Error subscribing');
}
});
}
// Something went wrong getting the device token
function deviceTokenError(e) {
Titanium.API.error('Failed ' + e.error);
}
GCM doesn't know about channels. That's something Arrow tracks and translates to the subscribed tokens. So you need to send push via the Arrow API or Appcelerator Dashboard.
http://docs.appcelerator.com/platform/latest/#!/guide/Sending_and_Scheduling_Push_Notifications
http://docs.appcelerator.com/arrowdb/latest/#!/api/PushNotifications

Getting wrong data throug GCM push notification

I am building application using phonegap build and pushnotification plugin.
I can't understand why is field "event" (inside "data")always "message" even if i dont send it at all or if i send something else like "event":"registration". Also i dont get any other fields i include in data, like "message_id" and sort...
Here is example of rest request i am using for testing and it works fine (i can change message and it always sends correct message)
{
"data" : {
"event":"message",
"message":"some message"
},
"registration_ids" : ["APA9..."]
}
but when I try to send this:
{
"data" : {
"event":"newMessage",
"message_id":134,
"group":1
},
"registration_ids" : ["APA91b..."]
}
I still get event "message" and dont even see other fields in code.
Here is my code:
onNotificationGCM: function(e) {
switch( e.event )
{
case 'message':
alert(e.message);
break;
case 'newMessage':
alert ('entered newMessage');
var id = e.message_id;
var grp = e.group;
//something to do with theese two but it never enters here
break;
default:
alert('An unknown GCM event has occurred');
break;
}
It never gets to alert ('entered newMessage') and if I put alerts of fields group and e.message_id in case 'message', they are undefined.
Hope someone can help, thanks in advance (sorry for bad english).
Ok, issue was with push plugin from phonegap build, it forwarded only those two fields... Now it is updated and plugin now forwards all arguments sent under "payload" field. Hope it helps some1 else with similar issue

Categories

Resources