var db = require('db'); var Common = require('common'); var User = require('user'); var Tags = db.tags; var needle = require('needle'); var fs = require('fs'); var Api = require('api'); var Notebook = require('notebook'); var Note = require('note'); function log(o) { console.log(o); } // 同步服务 var Sync = { // 同步的信息, 返回给调用者 _syncInfo: { notebook: {adds: [], deletes: [], updates: []}, note: {adds: [], deletes: [], updates: [], conflicts: []}, tag: {} }, // notebook _syncNotebookIsLastChunk: false, _totalSyncNotebookNum: 0, // 需要同步的数量 _tocalHasSyncNotebookNum: 0, // 已同步的数量 _notebookMaxEntry: 1, // note _syncNoteIsLastChunk: false, _totalSyncNoteNum: 0, // 需要同步的数量 _noteMaxEntry: 1, _initSyncInfo: function() { var me = this; // notebook me._syncNotebookIsLastChunk = false; me._totalSyncNotebookNum = 0; me._totalHasSyncNotebookNum = 0; me._lockNotebook = 1; // note me._syncNoteIsLastChunk = false; me._totalSyncNoteNum = 0; me._totalHasSyncNoteNum = 0; me._lockNote = 1; me._syncInfo = { notebook: {ok: false, adds: [], deletes: [], updates: []}, note: {ok: false, adds: [], deletes: [], updates: [], conflicts: []}, tag: {ok: false} }; }, //--------------- // notebook //--------------- // 增加, 有锁 _lockNotebook: 1, _addSyncNotebookNum: function() { var me = this; if(me._lockNotebook) { me._lockNotebook = 0; me._totalHasSyncNotebookNum++; me._lockNotebook = 1; } else { me._addSyncNotebookNum(); } }, // 同步笔记本 _syncNotebookToLocal: function(notebooks, callback) { var me = this; function canCall() { // 是最后一块, 且 me._addSyncNotebookNum(); log(me._totalHasSyncNotebookNum + ' ' + me._totalSyncNotebookNum); if(me._syncNotebookIsLastChunk && me._totalHasSyncNotebookNum >= me._totalSyncNotebookNum) { me._syncInfo.notebook.ok = true; callback && callback(true); } } if(!notebooks || notebooks.length == 0) { return canCall(); } for(var i in notebooks) { var notebook = notebooks[i]; // 得到本地的, 与之对比 (function(notebook) { var usn = notebook.Usn; var notebookId = notebook.NotebookId; // 1) 服务器端删除了, 本地肯定删除 if(notebook.IsDeleted) { log('delete: '); log(notebook); Notebook.deleteNotebookForce(notebookId, function() { me._syncInfo.notebook.deletes.push(notebookId); canCall(); }); return; } // 2) 查看本地的, 与本地合并 Notebook.getNotebook(notebookId, function(notebookLocal) { // 2.1 本地没有, 表示是新建 if(!notebookLocal) { log('add: ...') // TODO Notebook.addNotebookForce(notebook, function(notebook) { me._syncInfo.notebook.adds.push(notebook); canCall(); }); } else { // 2.2 本地是否修改了, 需要合并, 使用服务端的数据 if(notebook.IsDirty) { log('冲突....') // 2.3 服务器是最新的, 用服务器的 } else { } // 这里都是用服务器端的数据, 不处理冲突 Notebook.updateNotebookForce(notebook, function(notebook) { if(notebook) { me._syncInfo.notebook.updates.push(notebook); } canCall(); }) } }); })(notebook); } }, syncNotebook: function(afterUsn, callback) { var me = this; Api.getSyncNotebooks(afterUsn, me._notebookMaxEntry, function(notebooks) { log('syncNotebook') log(notebooks); if(Common.isOk(notebooks)) { me._totalSyncNotebookNum += notebooks.length; // 证明可能还有要同步的 if(notebooks.length == me._notebookMaxEntry) { me._syncNotebookToLocal(notebooks); var last = notebooks[notebooks.length-1]; me.syncNotebook(last.Usn, callback); } else { log('no more'); me._syncNotebookIsLastChunk = true; me._syncNotebookToLocal(notebooks, callback); } } else { // 同步失败 me._syncInfo.notebook.ok = false; me._syncInfo.notebook.msg = "cann't get all chunks"; callback && callback(false); } }); }, //------------- // note //------------- // 增加, 有锁 _lockNote: 1, _addSyncNoteNum: function() { var me = this; if(me._lockNote) { me._lockNote = 0; me._totalHasSyncNoteNum++; me._lockNote = 1; } else { me._addSyncNoteNum(); } }, // 同步笔记到本地 _syncNoteToLocal: function(notes, callback) { var me = this; function canCall() { // 是最后一块, 且 me._addSyncNoteNum(); log(me._totalHasSyncNoteNum + ' ' + me._totalSyncNoteNum); if(me._syncNoteIsLastChunk && me._totalHasSyncNoteNum >= me._totalSyncNoteNum) { me._syncInfo.note.ok = true; callback && callback(true); } } if(!notes || notes.length == 0) { return canCall(); } for(var i in notes) { var note = notes[i]; // 得到本地的, 与之对比 (function(note) { var usn = note.Usn; var noteId = note.NoteId; // 1) 服务器端删除了, 本地肯定删除 if(note.IsDeleted) { log('delete: '); log(note); Note.deleteNoteForce(noteId, function() { me._syncInfo.note.deletes.push(noteId); canCall(); }); return; } // 2) 查看本地的, 与本地合并 Note.getNote(noteId, function(noteLocal) { // 2.1 本地没有, 表示是新建 if(!noteLocal) { log('add: ...') // TODO Note.addNoteForce(note, function(note) { me._syncInfo.note.adds.push(note); canCall(); }); } else { // 2.2 本地是否修改了, 冲突, 报告给前端, 前端处理 // 冲突, 将本地修改的笔记复制一份(设置冲突字段, ConflictNoteId), 远程的覆盖本地的 if(note.IsDirty) { log('冲突....') me._syncInfo.note.conflicts.push(note); // 2.3 服务器是最新的, 用服务器的 } else { // 服务器是最新的, 本地没动过, 则覆盖之 Note.updateNoteForce(note, function(note) { if(note) { me._syncInfo.note.updates.push(note); } canCall(); }); } } }); })(note); } }, syncNote: function(afterUsn, callback) { var me = this; Api.getSyncNotes(afterUsn, me._noteMaxEntry, function(notes) { log('syncNote') log(notes); if(Common.isOk(notes)) { me._totalSyncNoteNum += notes.length; // 证明可能还有要同步的 if(notes.length == me._noteMaxEntry) { me._syncNoteToLocal(notes); var last = notes[notes.length-1]; me.syncNote(last.Usn, callback); } else { log('no more'); me._syncNoteIsLastChunk = true; me._syncNoteToLocal(notes, callback); } } else { // 同步失败 me._syncInfo.note.ok = false; me._syncInfo.note.msg = "cann't get all chunks"; callback && callback(false); } }); }, // 同步标签 syncTag: function(afterUsn, callback) { callback && callback(true); }, // 全量同步 fullSync: function(callback) { var me = this; me._initSyncInfo(); // 同步笔记本 me.syncNotebook(-1, function(ok) { if(ok) { log('------------------') // 同步笔记 me.syncNote(-1, function(ok) { if(ok) { // 同步标签 me.syncTag(-1, function() { callback && callback(me._syncInfo); }); } else { callback && callback(me._syncInfo); } }); } else { log('no-------') callback && callback(me._syncInfo); } }); }, // 增量同步 incrSync: function() { var me = this; me._initSyncInfo(); log('full sync start'); // 得到当前LastSyncUsn User.getLastSyncInfo(function(lastSyncUsn, lastSyncTime) { // 同步笔记本 me.syncNotebook(-1, function() { // 同步笔记 me.syncNote(-1, function() { // 同步标签 me.syncTag(-1, function() { callback && callback(me._syncInfo); }); }); }); }); }, // 发送改变 sendChanges: function() { } }; module.exports = Sync;