A better way to detect a change in a parse class? - ios

Currently I set up a timer that every 2 seconds makes a query to a parse class to see if any data has changed. If the data has changed it calls the refreshData method so my view can be updated with the new parse data.
So when ever data is updated in the parse class it will almost instantly be updated in the app.
The problem is this causes a lot of unnecessary web traffic, which I need to avoid.
What can I do to replace the timer with something that detects when data is changed in the parse class then tells the app to call the refreshData method?

afterSave Triggers
//this will trigger everytime the className objects has changed
Parse.Cloud.afterSave("className", function(request) {
//Do some stuff here //like calling http request or sending push 'data has changed' to installed mobile device
console.log("Object has been added/updated"+request.object.id);
});
https://parse.com/docs/js/guide#cloud-code-aftersave-triggers
You need to deploy first a cloud code then it will handle your problem :-)
In some cases, you may want to perform some action, such as a push, after an object has been saved. You can do this by registering a handler with the afterSave method. For example, suppose you want to keep track of the number of comments on a blog post. You can do that by writing a function like this:
Parse.Cloud.afterSave("Comment", function(request) {
query = new Parse.Query("Post");
query.get(request.object.get("post").id, {
success: function(post) {
post.increment("comments");
post.save();
},
error: function(error) {
console.error("Got an error " + error.code + " : " + error.message);
}
});
});
The client will receive a successful response to the save request after the handler terminates, regardless of how it terminates. For instance, the client will receive a successful response even if the handler throws an exception. Any errors that occurred while running the handler can be found in the Cloud Code log.
If you want to use afterSave for a predefined class in the Parse JavaScript SDK (e.g. Parse.User), you should not pass a String for the first argument. Instead, you should pass the class itself.

I'm not sure if my solution will fit with your needs, but using beforeSave trigger within CloudCode, combined to DirtyKeys will save you time and queries : http://blog.parse.com/learn/engineering/parse-objects-dirtykeys/
With DirtyKeys you can detect once some change was done on your class, and then you can build new trigger and do whatever you need once done.

Related

Redirect API call fetches from Service Worker

This is a really annoying issue. I am using a third party login in my application. When a user logins in through the third party, it redirects an api call to the server.
ex: /api/signin/github?code=test&state=test
For some strange reason this API call is getting fetched from the service worker instead on the server which handles the login logic.
ex:
Without seeing your service worker's fetch event handler, it's hard to say exactly what code is responsible for that.
In general, though, if there are URLs for which you want to tell the service worker never to respond to, you can just avoid calling event.respondWith(...) when they trigger a fetch. There are lots of ways to avoid doing that, but an early return is straightforward:
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
if (url.pathname === '/api/signin/github') {
// By returning without calling event.respondWith(),
// the request will be handled by the normal browser
// network stack.
return;
}
// Your fetch event response generation logic goes here.
event.respondWith(...);
});

Make periodic HTTP requests with service worker

Is it possible to make HTTP requests in background with service worker, when users are not visiting my webpage. I want to make periodic requests to my webpage (e.g. 3 seconds)?
There is a feature called periodicSync, but i didn't understand how to use it.
I've not tried implementing this but for me the clearest overview has been this explanation.
Making periodic requests involves first handling the Service Worker ready event, invoking the periodicSync.register() function with config options. The register() function returns a Promise that allows you to deal with success or rejection of the periodic sync registration.
registration.periodicSync.register()
Pass a 'config' object parameter with the following properties:
tag
minPeriod
powerState
networkState
You may then register listeners against the periodicSync event. E.g (slightly simplified example based on the explanation.
self.addEventListener('periodicsync', function(event) {
if (event.registration.tag == 'my-tag') {
event.waitUntil(doTheWork()); // "do the work" asynchronously via a Promise.
}
else {
// unknown sync, may be old, best to unregister
event.registration.unregister();
}
});

Firebase Offline, determine if items were saved to server and not just local cache

I have a messaging app and I'm using firebase Offline, When I updatechildvalues, it goes to the local cache and then to the server. However, when i turn off my internet, it only goes to the local cache, and if i close the app, the data is lost.
is there a way to determine if something was saved to the server instead of the local cache?
if not, what is the most effective way, to determine if something was successfully sent to the server.
I tried an observe value, but it also observes offline updates.
A completion listener will fire only when the data is written to the server. See an example:
let message = ["name": "puf", "text": "Hello from iOS"]
ref!.childByAutoId().setValue(message) { (error) in
print("Error while writing message \(error)")
}
But if there's been an app restart in between the write operation and the commit to server, that callback won't be fired. There is no workaround for that at the moment.
I had the same problem, and it can be solved using cloud function. Basically, just create a cloud function called when your message is created, and set a "persisted" field to true to this message. It will propagate to your client, who will treat any message without the "persisted" property as a message not sent yet.
exports.confirmMessageSave = functions.database
.ref('/chat/messages/{channelId}/{messageId}')
.onCreate(function(event) {
var message = event.data.val();
var updateFanOut = {};
updateFanOut['/messages/' + event.params.channelId + '/' + event.params.messageId + '/persisted'] = true;
return admin.database().ref('/chat').update(updateFanOut);
});

Do Parse Cloud Code triggers need response

Since I'm kinda new to cloud code, I have the question mentioned above!
1) Do cloud code triggers, beforeSave - afterSave etc, need to call response.success and response.error when they are done?
2) If so, is it possible for the client to receive that response?
Edit: For the first question, I realised that it's necessary for the "before" triggers only...
The second question remains unanswered!
In a beforeSave() trigger, the response.sucess() is returned to the client like this.
It's only in case of error that it could be interesting to return a specific message (for a business validation before save for i.e)
So in your cloud code you could write :
Parse.Cloud.beforeSave("MyObject", function(request, response) {
//business validation then if fail :
response.error("there was an error blabla...");
}
});
Then the Client will receive a Parse Exception with the corresponding message

How to send and receive domain objects with rabbitMQ plugin and grails

I've went over the excellent documentation for the rabbitMQ plugin. However, I am still confused about a few things.
Scenario
My application will take a file upload from the user, do various things to the file and accordingly set certain properties on the domain object. Some of this work can be labor intensive so I am using a queue. I envision requests being queued and the consumer picking up the requests from the queue and consuming them.
Questions
I want to store a domain object in the queue. I do this by: rabbitSend 'myqueue', colorObj. colorObjis an object of domain class Color
However, in the ColorService handleMessage(...) When I fetch the item from the queue, the item is not of type Color. Please note that on the rabbitMQ dashboard I can see the items being inserted in the queue, so my queue initiation in config.groovy is fine (I am using amq.direct)
How can I send and fetch a domain object from the queue?
From the behavior I've seen thus far, the handleMessage does not need to be instantiated. Even if I don't call the ColorService it still executes handleMessage by itself. Is that a normal behavior?
Below is the code:
controller
Color colorObj = colorService.newRequest(params, request.getFile('color.filename')
if (colorObj.validate)
rabbitSend 'myqueue', colorObj
...
service
class ColorService {
static rabbitQueue = 'myqueue'
void handleMessage(message) {
println "came in message: " + message instanceof Color //this prints false
}
}
As Tim says, if you can get by with just passing the domain instance ID that is simplest. You do need to be careful of changes to the domain instance while the message is in transit though.
Alternatively, if it's the data you're interested in, I prefer to serialise the objects as JSON using something like
rabbitSend 'myqueue', (colorObj as JSON).toString()
Of course, now your listener is receiving a string, so you'll have to convert it back:
void handleMessage(String message) {
def color = new Color(JSON.parse(message))
println "came in message: " + color instanceof Color
}
There is a little bit of discussion around this on the GPRABBITMQ-15 issue.
As it shows in the documentation, you can either send a String or a Map
Why not send the id of your domain object:
rabbitSend 'myqueue', colorObj.id
Then, load it back in when the message is processed:
void handleMessage(message) {
println "Got ${Color.get( message )}"
}
Or, if you don't need the domain object until the message is processed, send a map of all the required data, and have the service create the domain object after it is processed successfully?

Resources