CloudServices/Sync/FxSync/Developer/ClientAPI: Difference between revisions

Line 74: Line 74:
== Writing a Store class ==
== Writing a Store class ==


Your Store class (which extends <tt>Store</tt>, as defined in <tt>services/sync/modules/stores.js</tt>) has the job of creating and maintaining a set of Record objects from the underlying data.  The store must also make updates to the underlying data itself, to keep the data up-to-date with the user's latest changes, when the store is instructed to do so.
The Store object (which extends <tt>Store</tt>, as defined in <tt>services/sync/modules/engines.js</tt>) has the job of creating and maintaining a set of Record objects from the underlying data.  The store must also make updates to the underlying data itself, to keep the data up-to-date with the user's latest changes, when the store is instructed to do so.


The majority of the code you write for syncing a new data type will most likely be in the Store class.
The majority of the code you write for syncing a new data type will most likely be in the Store class.


Each Record that the Store keeps track of must be identified by a unique ID.  This can be a true GUID (Globally Unique ID), but it doesn't have to be -- it only has to be unique among all records in the store.  (So if an ID used for a bookmark record in the bookmark store is reused for a tab record in the tab store, that's fine.)
Each Record that the Store keeps track of must be identified by a unique ID (unique among all records in the store) called GUID. Depending of what type of data you're working with, you might already have GUIDs built into your data that you can make use ofIf not, you may have to invent your own mapping from data objects to GUIDs as long as it's consistent.  In this case, it is highly recommended to use <tt>Utils.makeGUID()</tt> helper:


Nevertheless, most of the code refers to them as GUIDs, so I'll use GUID for the rest of this article.
Depending of what type of data you're working with, you might already have GUIDs built into your data that you can make use of.  If not, you may have to invent your own mapping from data objects to GUIDs.  In this case, you will probably find the <tt>makeGUID()</tt> function (in Utils) useful:
Cu.import("resource://services-sync/util.js");
// ...
  let newGuid = Utils.makeGUID();
  let newGuid = Utils.makeGUID();


You can assign GUIDs to items in whatever way you see fit, as long as you are consistent with the mapping.  It's entirely up to your Store class to define and maintain this mapping.  Also keep in mind that although the data will be encrypted on the server, the GUIDs are public, so don't put passwords into them or anything.
In either case, ensure that the GUIDs are URL friendly (base64url is a recommended alphabet).


Your Store class '''must''' implement the following methods:
Your Store object '''must''' implement the following methods:


*<tt>itemExists(id)</tt>
*<tt>itemExists(id)</tt>
*<tt>createRecord(id, uri)</tt>
*<tt>createRecord(id, collection)</tt>
*<tt>changeItemID(oldId, newId)</tt>
*<tt>changeItemID(oldId, newId)</tt>
*<tt>getAllIDs()</tt>
*<tt>getAllIDs()</tt>
Line 101: Line 95:
*<tt>remove(record)</tt>
*<tt>remove(record)</tt>


You may also find it useful to override other methods of the base class, depending on what you're doing.
You may also find it useful to override other methods of the base implementation, for example <tt>applyIncomingBatch</tt> if the underlying storage for your data supports batch operations.
 
Since this is a lot of methods to write, I'll break them down one by one in the following sub-sections.


=== createRecord ===
=== createRecord ===


The <tt>createRecord( guid, uri )</tt> method gets called by the engine to request a new record for an item with a given GUID. It's your Store's responsibility to instantiate a Record object (of the class you defined earlier), assign the given GUID, and return it.
The <tt>createRecord( id, collection )</tt> method gets called by the engine to request a new record for an item with a given GUID. It's your Store's responsibility to instantiate a Record object (of the class you defined earlier), assign the given GUID, and return it.


=== itemExists(guid) ===
=== itemExists(guid) ===
Line 139: Line 131:
<tt>remove(record)</tt>
<tt>remove(record)</tt>
:The argument is a record which has been remotely deleted; your Store should locate the matching local item and delete it.  (Don't rely on the record that is passed in to this method having any of its attributes set correctly except for <tt>.id</tt>.  The <tt>.id</tt> should be al you need, anyway.)
:The argument is a record which has been remotely deleted; your Store should locate the matching local item and delete it.  (Don't rely on the record that is passed in to this method having any of its attributes set correctly except for <tt>.id</tt>.  The <tt>.id</tt> should be al you need, anyway.)
<tt>applyIncomingBatch</tt>
:TODO


=== Example Store class skeleton ===
=== Example Store class skeleton ===
Line 152: Line 147:
     // Return true if an item with given guid exists in the store.
     // Return true if an item with given guid exists in the store.
   },
   },
   createRecord: function(guid, uri) {
   createRecord: function(id, collection) {
     record = new FooRecord(uri);
     record = new FooRecord(uri);
     // Look up the data corresponding to this guid, by the mapping
     // Look up the data corresponding to this guid, by the mapping
canmove, Confirmed users
725

edits