Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
var HistoryAPI = { | ||
addPlace: function(place) { | ||
console.log(place); | ||
return IAC.request('sync-history', { | ||
method: 'addPlace', | ||
args: [place] | ||
}); | ||
} | ||
}; | ||
|
||
var SynctoHistoryAdapter = { | ||
update: function(kintoCollection) { | ||
kintoCollection.list().then(list => { | ||
console.log('history adapter update function called with this local copy of the remote data:', list); | ||
|
||
var historyRecords = list.data; | ||
var partialRecoreds = historyRecords.slice(0, 10); | ||
This comment has been minimized.
Sorry, something went wrong. |
||
historyRecords.forEach(function (decryptedRecord){ | ||
var record = decryptedRecord.payload | ||
if(!record.histUri || !record.visits || !record.visits[0]){ | ||
//console.log('invalid history: ', record); | ||
return ; | ||
} | ||
|
||
console.log('decrypted record', record); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
weilonge
Author
Owner
|
||
|
||
var visits = []; | ||
record.visits.forEach(function (elem){ | ||
visits.push(elem.date); | ||
}); | ||
|
||
var place = { | ||
url: record.histUri, | ||
title: record.title, | ||
visits: visits, | ||
visited: record.visits[0] | ||
}; | ||
HistoryAPI.addPlace(place).then(function (d){ | ||
console.log(d); | ||
}, function (e){ | ||
console.log(e); | ||
}); | ||
document.querySelector('#sync-time').textContent = | ||
This comment has been minimized.
Sorry, something went wrong.
michielbdejong
|
||
new Date().toString(); | ||
}); | ||
|
||
}); | ||
} | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,18 @@ | |
* consumed by the System app, so there will be no need to expose anything. | ||
*/ | ||
|
||
function arrayUnique(array) { | ||
var a = array.concat(); | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
weilonge
Author
Owner
|
||
for(var i=0; i<a.length; ++i) { | ||
for(var j=i+1; j<a.length; ++j) { | ||
if(a[i] === a[j]) | ||
a.splice(j--, 1); | ||
} | ||
} | ||
|
||
return a; | ||
}; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
weilonge
Author
Owner
|
||
|
||
(function() { | ||
|
||
function sendPortMessage(portName, message) { | ||
|
@@ -52,9 +64,20 @@ | |
function syncHistroyRequest(id, method, args){ | ||
var url = args[0].url; | ||
var visits = args[0].visits; | ||
var title = args[0].title; | ||
|
||
var places = appWindowManager.places; | ||
places.setVisits(url, visits); | ||
places.editPlace(url, (place, cb) => { | ||
This comment has been minimized.
Sorry, something went wrong.
michielbdejong
|
||
if(place.title === place.url){ | ||
This comment has been minimized.
Sorry, something went wrong.
michielbdejong
|
||
place.title = title; | ||
} | ||
place.visits = place.visits || []; | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
weilonge
Author
Owner
|
||
place.visits = arrayUnique(place.visits.concat(visits)); | ||
place.visits.sort((a, b) => { | ||
return b - a; | ||
}); | ||
This comment has been minimized.
Sorry, something went wrong.
michielbdejong
|
||
cb(place); | ||
}); | ||
} | ||
|
||
/** | ||
|
5 comments
on commit 2192fb5
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the way you merge the two sorted arrays place.visits
and visits
, by first concatenating them, then splicing out the duplicates in a double for-loop, and then sorting again, is probably not the most efficient algorithm. How about this alternative:
for (var i=0; i<visits.length; i++) {
if (place.visits.indexOf(visits[i]) === -1) {
place.visits.push(visits[i]);
}
}
place.visits.sort(function(a, b) {
return b - a;
});
Seems simpler and possibly faster?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel we need at least one unit test for the history adapter. Maybe just add it under https://github.com/weilonge/gaia/tree/master/apps/settings/test/unit for now, and then we can move it along with the code once we have the Synchronizer app to land this in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adapter 'syncs down' visits to places that exist on the Sync server but not in the places DataStore. But that's only step 1, we also need to 'sync up', so iterate over the places and their visits and check if they all exist in kintoCollection. If there is a place that's missing from the kintoCollection, use kintoCollection.add()
. If there is a place which is missing some visits in the kintoCollection, add the missing visits using http://kintojs.readthedocs.org/en/latest/api/#updating-a-record.
Since Kinto.js does not have auto-batching, and batch operations are not supported yet, this is going to very slow when there are hundreds of records to add or update. It's important for performance to do all these add
and update
operations in a batch operation, so that they go into one IndexedDB transaction instead of hundreds of slow IndexedDB transactions. But for now, let's just not batch them, and add a code comment, referring to Kinto/kinto.js#16, which mentions this important performance issue (we could do some measurements to confirm exactly how slow it is).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, and I forgot, we also need a function HistoryAdapter#handleConflict
, so we can do something like this:
var conflict = {
type: "incoming", // can also be "outgoing"
local: {
_status: "created",
id: "233a018a-fd2b-4d39-ba85-8bf3e13d73ec",
title: "local title",
},
remote: {
id: "233a018a-fd2b-4d39-ba85-8bf3e13d73ec",
title: "remote title",
}
};
myHistoryAdapter.handleConflict(conflict);
The only type of conflict we need to worry about is if one URL was visited both on desktop and on the phone. So you can always just:
- merge the
visits
arrays - use the
title
of the one which was visited lasted (title should never be different unless the visits are also different)
So something like:
function handleConflict(conflict) {
var merged = conflict.local;
// Merge visits from remote into visits from local:
for (var i=0; i<conflict.remote.visits.length; i++) {
if (merged.visits.indexOf(conflict.remote.visits[i]) === -1) {
merged.visits.push(conflict.remote.visits[i]);
}
}
merged.visits.sort(function(a, b) {
return b - a;
});
// Use title from remote if more recent:
if (conflict.remote.visited > merged.visited) {
merged.title = conflict.remote.title;
}
return merged;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey Michiel,
Thanks a lot for your comments, here are my feedback for them:
- I think the way you proposed is simpler. The precise performance will be decided after doing benchmark. (Just reading the code, I think that would be faster :-) ) So I will adopt your suggestion and remove the deduplication function.
- The test is done in the new PR[1].
- For 'sync up' case, I have some ideas to share. Any places modification should be monitored, and [places.js#editPlace] is the only entry point to put a place object as far as I know. We can modify [places.js#editPlace] to mark an attribute or enqueue the new information to a "waiting for sync-up" queue. When sync-up request is coming, upload the places in the queue. I would like to consult with Dale Harvey who is the author of places.js (git blame), so we probably can discuss this issue (correctness, performance, and test-case) in another bug.
- May I know where is the conflict object from? (kinto.js?) "last_modified" in a decrypted record is an important property for deciding the merging strategy. I did this in the new PR as well.
Besides, the suggestions of your above comment is implemented in the new PR[1] except item3, please help to review it. let's move the discussion to the new one. Thank you! :)
[1] #2
typo Recor[e]ds