Kinto / kinto.js

An Offline-First JavaScript Client for Kinto.
http://kintojs.readthedocs.io/
Other
318 stars 72 forks source link

What to do after received data from Websocket? #542

Open ptgamr opened 8 years ago

ptgamr commented 8 years ago

What should we do after received the changes from Websocket? Trigger collection.sync would be inefficient for me (data is already available in the websocket message)

//sample repsonse
{
  channel: "94b660c6-68f3-83c4-97fa-8e8ac4715204-kinto_demo_calendar-record",
  data: "the data that changes",
  event: "update"
}

I think we could create/update/delete record manually. But how to best update the lastModified time is still mysterious.

leplatrem commented 8 years ago

Good question!

You are right, triggering a sync() is very inefficient. That's we did on the 'calendar' demo here because it was easy for demonstration purposes.

You must store the data locally instead.

If you have chosen to go with the SERVER_WINS approach, it is even simpler, you just stick the incoming data into the local database, like this:

channel.onChange((response) => {
  if (response.event == "create") {
    store.create(response.data, {synced: true})
  }
});

The response.data should contain the last_modified attribute from the server, so — as far as I understand — you shouldn't worry about it.

If you want to detect conflicts, you'll have to go with code like:

channel.onChange((response) => {
  if (response.event == "update") {
    store.get(response.data.id)
     .then(function (existing) {
       if (existing.data._status != 'synced')
            // This was changed locally and not yet synced.
            // compare `existing` and `response.data`
            // or just ignore change (ie. CLIENT_WINS) 
       }
     });
  }
});

Tell us what you find out along the way! It would be nice to add info about that in the documentation!

ptgamr commented 8 years ago

Thanks @leplatrem for the detailed response. I'll try to do what you suggested.

However, I think it would be perfect if the kintojs client can just provide a simple API to work with for eg.

collection.syncIncomming(dataFromWebsocket, strategy)

which will return a SyncResultObject just like sync()

leplatrem commented 8 years ago

Good idea!

In your example dataFromWebsocket is what comes from kinto-pusher I guess.

What about something more generic like applyChange(action, data, strategy) ? (disclaimer: I'm not good at naming things)

If you have a draft of some working don't hesitate to share it as a start ;)

ptgamr commented 8 years ago

Hey @leplatrem, I detected that you guys have a very similar function in collection.js already: https://github.com/Kinto/kinto.js/blob/master/src/collection.js#L621 ;) Maybe we could make a public API for that?

Btw, I'm writing an Ember Data adapter to work with Kinto api: https://github.com/ptgamr/ember-kinto . There is a live demo at: https://ember-kinto-demo.herokuapp.com/

Here is the changes based on what you suggested above: https://github.com/ptgamr/ember-kinto/commit/354c9f59a3b918768013af051763987405f4a39c#diff-1551788d4134d14f484faa251ebee47eR103

Until now I saw that the concept of kinto fits quite nicely with Ember Data ;) Thanks for that!

n1k0 commented 8 years ago

Maybe we could make a public API for that?

It's actually part of the public API, though it's not documented in the user docs. Could you please tell if using the method works for your use case? If so we may want to document it better. If not we can still improve it :)

ptgamr commented 8 years ago

@n1k0 Sadly that I haven't figured out how to construct a SyncResultObject

import { SyncResultObject } from 'npm:kinto';
new SyncResultObject();

throws me an error:

TypeError: _npmKinto.SyncResultObject is not a constructor
n1k0 commented 8 years ago

Try

import { SyncResultObject } from "kinto/lib/collection"

Hint: you have sample import statements on top of each esdoc pages (for instance) :)

ptgamr commented 8 years ago

@n1k0 it's really hard for me to figure out what is inside the changeObject. Would you mind give me a hint?

n1k0 commented 8 years ago

@ptgamr Yeah, that's poorly documented, I agree. The change object contains two properties:

I should probably add what I just wrote into the docs.

ptgamr commented 8 years ago

Thanks @n1k0 ...

import { SyncResultObject } from "kinto/lib/collection" doesn't work for me... As I'm using Browserify to import the script into my ember page ember-browserify.

n1k0 commented 8 years ago

Does const {SyncResultObject} = require("kinto/lib/collection") work?

ptgamr commented 8 years ago

Nope. I guess I have to find another way to import kinto.js

n1k0 commented 8 years ago

That's very strange

ptgamr commented 8 years ago

@n1k0 for your references, this is the way I'm currently using to import kinto to ember: http://www.jimmylauzau.com/blog/2016/03/22/importing-node-modules-in-ember-js

n1k0 commented 8 years ago

Oh. It's probably an issue to file against ember-browserify then.

ptgamr commented 8 years ago

Yes.

Ember-browserify cannot be used with named imports e.g. import { foo } from 'bar'; as we have no way of knowing at the time of browserifying what portions of the import are being used.

ptgamr commented 8 years ago

@n1k0 I made a work around to copy the implementation of SyncResultObject class into my project (as it's fairy simple). And importChanges works like a charm! You can see the latest demo here: https://ember-kinto-demo.herokuapp.com/lists

n1k0 commented 8 years ago

Awesome :)

n1k0 commented 8 years ago

@ptgamr can we close this issue, or should further action be taken to fully address it?

ptgamr commented 8 years ago

@n1k would be nice if we could add one more section to the Tutorial (https://kintojs.readthedocs.io/en/latest/tutorial/#synchronizing-tasks) to explain how to deal with real-time changes from websocket. Cause I think this is a fairly common use-case, it will make life easier for other developers.

Regarding the importChanges api, it still a hack to re-implement the SyncResultObject. And I think even in the case when you include kinto.js script in your page, it's not possible to construct a new SyncResultObject() because the only reference we have on the page is Kinto, users are not able to access other parts of the lib very easily.

Would it be useful if we could add support for an API call which do not require users to pass in a SyncResultObject ? The api will create one internally.

n1k0 commented 8 years ago

would be nice if we could add one more section to the Tutorial

@ptgamr Would you be interested in writing it? :)

Would it be useful if we could add support for an API call which do not require users to pass in a SyncResultObject

Yeah probably. It's somewhat of a pain to figure out how to expose things in the compiled file though. If you have suggestions, I take them!

ptgamr commented 8 years ago

@n1k0 yes, I can find sometime prepare the PR this week. Cheers ;)

n1k0 commented 8 years ago

@ptgamr awesome, thank you 👍

lgleim commented 7 years ago

Wouldn't it make sense for this (both on the Kinto and the Kinto.js side) to make core?

leplatrem commented 7 years ago

Sorry, what do you mean «for this» ? Websockets? If so yes, it would make sense indeed. We took our time because we wanted a pluggable solution that is not tight to a commercial service, nor reimplementing a whole WS backend... It's very probable that the kinto-webpush plugin goes into core once it's stable and accepted.

lgleim commented 7 years ago

Websockets/Webpush is exactly what I meant. As far as I understand there is however no direct (automatic) handling of pushed changes in Kintojs. Will this be addressed as well?

Natim commented 7 years ago

We need to wait for the plugin to be working before doing that. For now there are two ways of handling that:

In the first case you can already use Kinto.JS with it. The second case is nice but if you miss a push message you start to be outdated.