Apollo GraphQL unsubscribe seems to be broken - apollo

We are using Apollo GraphQL with subscriptions (via websockets) in a node.js backend and a react frontend.
The app provides a list of devices. When a user clicks on one device he gets the monitoring data for the device with live updates (from the subscription). When the user clicks on another device the subscription is stoppen, the data for the next device is being loaded and subscribed.
I pasted the messages from the websocket connection below. I first tried to paste the raw log here, but the screenshot is much easier to read.
Please ignore the ids 1-5. Important for my problem is id 6 and 7. The id is created when clicking on the first device (at 11:15:35) and then the details are closed so the subscription is stopped (at 11:15:36). Now the user clicks another device and starts subscription 7. Some seconds later the system pushes data for both, the 6th and 7th subscription.
Is there something I can do so "stop" actually means "stop" or is this a bug?
Edit: as requested, here is the code I use to subscribe/unsubscribe (I had to cut some parts due to company regulations)
const subscription = useRef(null)
const { loading, data, error, subscribeToMore } = useQuery(getDevice, { variables: { deviceId } })
useEffect(() => {
return () => {
if (!subscription.current) return
subscription.current()
subscription.current = null
}
}, [deviceId])
if (!subscription.current) {
subscription.current = subscribeToMore({
document: geDeviceSubscription,
variables: {
deviceId
},
updateQuery: (prev, { subscriptionData }) => ({ device: subscriptionData.data.subscribeDevice })
})
}
Edit 2: It is for sure not my clients issue as it also happens if the use the GraphiQL gui, start a subscription and stop it again. The new data is not displayed but it is visible in the websocket connection in the network tab of the browser (chrome).

It seems to have been a bug in an older apollo graphql or nestjs-apollo-graphql version (We use those frameworks in the backend). After upgrading all the backend dependencies to "latest", the bug doesn't seem to persist.

Related

PWA: how to refresh content every time the app is opened

I created a PWA app which sends API call to my domotic server and prints the response on the home page (e.g. outside temperature and vacuum robot status).
While all the data get refreshed at very first app opening, if I minimize the app whithout completely shutting it off I have no data refreshing at all.
I was wondering how to force a refresh every time the app gets re-opened without having to do it manually (no pull-down to refresh, no refresh-button).
Found myself the solution adding the following code in service worker:
self.addEventListener('visibilitychange', function() {
if (document.visibilityState === 'visible') {
console.log('APP resumed');
window.location.reload();
}
});
Here is the solution that works.
You can place this code wherever you have access to the window object:
window.addEventListener("visibilitychange", function () {
console.log("Visibility changed");
if (document.visibilityState === "visible") {
console.log("APP resumed");
window.location.reload();
}
});
Consider this may affect user experience or data loss with a forced reload every time the user swipes between apps.

How can I use TTL to prevent a message backlog when using Firebase Cloud Messaging with Django-Push-Notifications?

I am working with Firebase Cloud Messaging in Django using django-push-notifications to deliver push notifications to our users via desktop notifications.
After a browser is fully closed (such as when the the computer is turned off), our users receive a backlog of all notifications previously sent next time they boot up.
While there are situations where a user would want to receive the entire backlog of messages, this is not one of them.
It seems the answer is to set TTL=0, as per this section of the FCM documentation, but my attempts are not resulting in the desired behavior.
Please help me better understand TTL in this context. If TTL is the right way to go, what is the proper way to format TTL in send_message() using django-push-notifications so that messages will not accumulate if not immediately delivered?
Here is what I have attempted:
devices.send_message(
body,
TTL=0,
time_to_live=0,
link='blah',
extra={'title': 'blah blah', 'icon': '/foo/bar.png'}
)
The format that you send seems different from the one in the documentation you linked. From the documentation:
{
"message":{
"token":"bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
},
"apns":{
"headers":{
"apns-expiration":"1604750400"
}
},
"android":{
"ttl":"4500s"
},
"webpush":{
"headers":{
"TTL":"4500"
}
}
}
}
So key here is that the time-to-live for a webpush message is set under webpush/headers/TTL, while you're adding it to the top-level.

How to intercept AWS SNS messages to iOs mobile endpoints in Xamarin?

The documentation on AWS -SNS for use of SNS within Xamarin iOS projects shows how to register an iOS device to receive messages from SNS, but not clear how to intercept those messages within the application and programtically respond to the message. How do I capture the incoming message, and process appropriately rather than just showing the text of the message received? Is this done by sending a different message than is shown in the AWS console, and where can I intercept it in my application?
This is the example I've been following:
public override bool FinishedLaunching(UIApplication app, NSDictionary options) {
// do something
var pushSettings = UIUserNotificationSettings.GetSettingsForTypes (
UIUserNotificationType.Alert |
UIUserNotificationType.Badge |
UIUserNotificationType.Sound,
null
);
app.RegisterUserNotifications(pushSettings);
app.RegisterForRemoteNotifications();
// do something
return true;
}
public override void RegisteredForRemoteNotifications(UIApplication application, NSData token) {
var deviceToken = token.Description.Replace("<", "").Replace(">", "").Replace(" ", "");
if (!string.IsNullOrEmpty(deviceToken)) {
//register with SNS to create an endpoint ARN
var response = await SnsClient.CreatePlatformEndpointAsync(
new CreatePlatformEndpointRequest {
Token = deviceToken,
PlatformApplicationArn = "YourPlatformArn" /* insert your platform application ARN here */
});
}
}
Here is the message I'm sending:
{
"APNS_SANDBOX":"{\"aps\":{\"alert\":\"This is my message\"}}"
}
This seems to work fine for displaying a text message sent from the AWS console, whether the app is running or not, but that's not what I need for my app. (e.g. a chess app, where the SNS messages are used to exchange moves made by a pair of users and the app displays them.)
The FinishedLaunching method contains several not altogether helpful "do something" , but I can't figure out how to, say call some method in my PCL when a particular message is received and pass the content of the message to that method.
You can subscribe the DidReceiveRemoteNotification() event in AppDelegate.cs to get your content you sent on SNS.
public override void DidReceiveRemoteNotification(UIApplication application, NSDictionary userInfo, Action<UIBackgroundFetchResult> completionHandler)
{
// retrieve something from a server somewhere
}
This event will trigger when user taps the notification to open the app and when this app is on background state or foreground state.
If this app is closed this event will not trigger, but we can also get the content in public override bool FinishedLaunching(UIApplication app, NSDictionary options) with the parameter options.
Moreover if you want to get it in PCL, we can make a MessagingCenter to achieve this:
Send content on native platform:
MessagingCenter.Send<object, NSDictionary>(this, "Notification", userInfo);
Then receive this MessagingCenter on PCL somewhere you like:
MessagingCenter.Subscribe<object, NSDictionary>(this, "Notification", (sender, dic) =>
{
});

How to send Firebase Cloud Message with AWS SNS? [duplicate]

I am using AWS resources for my android project, I am planning to add push notification service for my project with AWS SNS.there are few questions bothering me much. I did not find any questions regarding these, except one or two but with unclear explanations.
1.Does AWS support FCM? SNS work with GCM. But Google recommends to use FCM instead of GCM. I did not find AWS supporting FCM.
2.Do AWS store messages (or data) into their databases even after sending push notifications?
3.I tried putting FCM api key in SNS application platform, it is showing invalid parameters why?
FCM is backwards compatible with GCM. The steps for setting up FCM on AWS are identical to the GCM set up procedure and (at least for the moment) FCM works transparently with GCM and SNS with respect to server-side configuration.
However, if you are sending data payloads to the Android device they will not be processed unless you implement a client side service that extends FirebaseMessagingService. The default JSON message generator in the AWS console sends data messages, which will be ignored by your app unless the aforementioned service is implemented. To get around this for initial testing you can provide a custom notification payload which will be received by your device (as long as your app is not in the foreground)
There are GCM-FCM migration instructions provided by Google however the changes you need to make are predominantly on the App side.
The steps you need to follow to test GCM/FCM on your app with SNS are:
Create a Platform Application in SNS, selecting Google Cloud Messaging (GCM) as the Push Notification Platform, and providing your Server API key in the API key field.
Select the Platform Application and click the Create platform endpoint button.
Provide the InstanceID (Device Token) generated by your app. You must extend the FirebaseInstanceIDService and override the onTokenRefresh method to see this within your Android App. Once you have done this, uninstall and reinstall your app and your token should be printed to the Debug console in Android Studio on first boot.
Click the Add endpoint button.
Click on the ARN link for your platform application.
Select the newly created Endpoint for your device and click the Publish to endpoint button.
Select the JSON Message Format, and click the JSON message generator button.
Enter a test message and click the Generate JSON button
Now comes the "gotcha part".
The message that is generated by SNS will be of the form:
{
"GCM": "{ \"data\": { \"message\": \"test message\" } }"
}
As we mentioned earlier, data payloads will be ignored if no service to receive them has been implemented. We would like to test without writing too much code, so instead we should send a notification payload. To do this, simply change the JSON message to read:
{
"GCM": "{ \"notification\": { \"title\": \"test title\", \"body\": \"test body\" } }"
}
(For more information about the JSON format of an FCM message, see the FCM documentation.)
Once you have done this, make sure your app is not running on the device, and hit the Publish Message button. You should now see a notification pop up on your device.
You can of course do all this programmatically through the Amazon SNS API, however all the examples seem to use the data payload so you need to keep that in mind and generate a payload appropriate to your use case.
Now you can go to your firebase console (https://console.firebase.google.com/) select your project, click the gear icon and choose project settings, then click on the cloud messaging tab...
You'll see the legacy Server Key which is the GCM API Key and you'll have the option to generate new Server Keys which are the FCM versions
SNS will accept both versions but their menu option is still categorizing it under GCM
Here is picture for your reference:
Note that you can "accidentally" remove your Server Keys but the Legacy server key is not deletable. Also, if you click the add server key button, you'll get a new server key BELOW the first one, WITH NO WARNING! ...Nice job Google ;)
One more additional note to Nathan Dunn's great answer.
How to send data with the notification from SNS to Firebase.
We need to add data to the Json (inside the notification):
{
"default": “any value",
"GCM": "{ \"notification\": { \"body\": \”message body\”, \”title\”: \”message title \”, \"sound\":\"default\" } , \"data\" : {\”key\" : \”value\", \”key2\" : \”value\” } }”
}
In your FirebaseMessagingService implementation (Xamarin example)
public override void OnMessageReceived(RemoteMessage message)
{
try
{
var body = message?.GetNotification()?.Body;
var title = message?.GetNotification()?.Title;
var tag = message?.GetNotification()?.Tag;
var sound = message?.GetNotification()?.Sound;
var data = message?.Data
foreach (string key in data.Keys)
{
// get your data values here
}
}
catch (Exception e)
{
}
}
I tried to use solution with notification payload instead of data, but I did not receive push notifications on the mobile device. I found this tutorial https://youtu.be/iBTFLu30dSg with English subtitles of how to use FCM with AWS SNS step by step and example of how to send push notifications from AWS console and implement it on php with aws php sdk. It helped me a lot.
Just an additional note to Nathan Dunn's Answer: to add sound use the following JSON message
{
"GCM": "{ \"notification\": { \"text\": \"test message\",\"sound\":\"default\" } }"
}
It took me a while to figure out how to send the notification with the right payload (publish to topic). So I will put it here.
private void PublishToTopic(string topicArn)
{
AmazonSimpleNotificationServiceClient snsClient =
new AmazonSimpleNotificationServiceClient(Amazon.RegionEndpoint.EUWest1);
PublishRequest publishRequest = new PublishRequest();
publishRequest.TopicArn = topicArn;
publishRequest.MessageStructure = "json";
string payload = "\\\"data\\\":{\\\"text\\\":\\\"Test \\\"}";
publishRequest.Message = "{\"default\": \"default\",\"GCM\":\"{" + payload + "}\"}";
PublishResponse publishResult = snsClient.Publish(publishRequest);
}
Amazon does support FCM as all previous code has been migrated from GCM to FCM. Below article explains in detail.
Article Published by Amazon
To answer the questions:
AWS SNS does support FCM.
No AWS does not store messages after sending push notifications.
For a detailed tutorial on setting up FCM with SNS please read this article.

AWS Lambda for Client to Client Push Notifications

Thanks to this community I've learned that is possible to send AWS SNS Push notifications via Lambda with node.js (as a result of Parse migration). I am still struggling with the following:
Can this be done client to client x likes y's z. Where x is user 1, y is user 2 and z is the object being liked? If so, it seems like Cognito is not required that it can read directly from the database but is that accurate?
Does anyone have an example of how this was implemented?
Again, we don't want to broadcast to all users on a schedule but rather when a client performs an action.
Thanks so much in advance!
Let's say you have Device1 which creates a piece of content. That is distributed to a number of users. Device2 receives this content and "likes" it.
Assumption:
you have registered for push notifications on the device, and created a SNS endpoint on AWS. You have stored that endpoint ARN in your database, and associated it with either the Cognito Id, or the content Id. If your data is normalized, then you'd typically have the SNS endpoint associated with the device.
Your Lambda will need to have access to that data source and look up that SNS endpoint to send push notifications to. This will depend on what sort of data store you are using (RDS, DynamoDB, something else). What sort of access that is, and how you secure it is a whole other topic.
From your Lambda, you fetch the ARN to send the push notification to. If you pass in the content Id from the Like, and have the Cognito Id from the device that Liked it, you can then look up the information you need. You then construct a SNS payload (I'm assuming APNS in this example), then send it off to SNS.
var message = {
"default": "New Like!",
"APNS": {
"aps": {
"alert": "New Like!"
}
}
};
var deviceParams = {
Message: JSON.stringify(message),
Subject: "New Like",
TargetArn: targetArn,
MessageStructure: "json"
};
self.sns.publish(deviceParams, function (err) {
if (err) {
console.error("Error sending SNS: ", err);
}
});
It's not all done for you like it might be with Parse. You need to work a lot harder on AWS, but you have near unlimited power to do what you want.
If this is a bit too much, you may want to consider Google's newly updated Firebase platform. It's very Parse-like: https://firebase.google.com/
Hope that helps you move forward a bit.
Further reading:
http://docs.aws.amazon.com/sns/latest/dg/mobile-push-apns.html
https://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/Chapters/TheNotificationPayload.html
http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/SNS.html