var async = require('async'); var db = require('db'); var User = require('user'); var Notebook = require('notebook'); var Tag = require('tag'); // var Api = require('api'); var Server = require('server'); var Common = require('common'); var Notes = db.notes; var Api = null; // require('api') function log(o) { console.log(o); } // 笔记服务 var Note = { /* type NoteOrContent struct { NotebookId string NoteId string UserId string Title string Desc string ImgSrc string Tags []string Content string Abstract string IsNew bool IsMarkdown bool FromUserId string // 为共享而新建 IsBlog bool // 是否是blog, 更新note不需要修改, 添加note时才有可能用到, 此时需要判断notebook是否设为Blog } */ // 更新笔记 updateNoteOrContent: function(noteOrContent, callback) { var userId = User.getCurActiveUserId(); noteOrContent['UserId'] = userId; log('update'); var date = new Date(); noteOrContent.UpdatedTime = date; noteOrContent['IsDirty'] = true; // 已修改 // 新建笔记, IsNew还是保存着 if(noteOrContent.IsNew) { noteOrContent.CreatedTime = date; noteOrContent['IsTrash'] = false; delete noteOrContent['IsNew']; noteOrContent['LocalIsNew'] = true; Notes.insert(noteOrContent, function (err, newDoc) { // Callback is optional if(err) { console.log(err); callback && callback(false); } else { // 为什么又设置成true, 因为js的对象是共享的, callback用到了noteOrContent.IsNew来做判断 noteOrContent['IsNew'] = true; callback && callback(newDoc); // 重新统计笔记本的笔记数量 Notebook.reCountNotebookNumberNotes(noteOrContent.NotebookId); // 标签 if(noteOrContent.Tags && noteOrContent.Tags.length > 0) { Tag.addTags(noteOrContent.Tags); } } }); // 更新笔记 } else { var updateFields = ['Desc', 'ImgSrc', 'Title', 'Tags', 'Content']; var updates = {}; var needUpdate = false; for(var i in updateFields) { var field = updateFields[i]; if(field in noteOrContent) { updates[field] = noteOrContent[field]; needUpdate = true; } } if('Content' in updateFields) { // 内容更新了, 因为内容是以后才从远程获取的, 获取内容后改变ContentIsDirty=false noteOrContent['ContentIsDirty'] = true; } if(needUpdate) { updates['IsDirty'] = true; updates.UpdatedTime = date; // Set an existing field's value Notes.update({NoteId: noteOrContent.NoteId}, { $set: updates }, {}, function (err, numReplaced) { if(err) { log(err); callback && callback(false); } else { callback && callback(noteOrContent); // 标签 if(noteOrContent.Tags && noteOrContent.Tags.length > 0) { Tag.addTags(noteOrContent.Tags); } } }); } } }, // 获取笔记列表 getNotes: function(notebookId, callback) { var me = this; me._getNotes(notebookId, false, callback); }, // 获取trash笔记 getTrashNotes: function(callback) { var me = this; me._getNotes('', true, callback); }, _getNotes: function(notebookId, isTrash, callback) { var userId = User.getCurActiveUserId(); var query = { UserId: userId, IsTrash: false, }; if(notebookId) { query['NotebookId'] = notebookId; } if(isTrash) { query['IsTrash'] = true; } Notes.find(query).sort({'UpdatedTime': -1}).exec(function(err, notes) { if(err) { log(err); return callback && callback(false); } return callback && callback(notes); }); }, // 得到笔记 getNote: function(noteId, callback) { var me = this; Notes.findOne({NoteId: noteId}, function(err, doc) { if(err || !doc) { log('不存在'); callback && callback(false); } else { callback && callback(doc); } }); }, // 远程修改本地内容 updateNoteContentForce: function(noteId, content, callback) { // // 改成"); log(content); Notes.update({NoteId: noteId}, { $set: {Content: content, InitSync: false, IsContentDirty: false} }, {}, function (err, numReplaced) { if(err) { log(err); callback && callback(false); } else { callback && callback(content); } }); }, /* // 同步内容 updateNoteContentForce: function(noteId, content, callback) { // 将笔记内容中 Notes.update({NoteId: noteId}, { $set: {Content: content, InitSync: false} }, {}, function (err, numReplaced) { if(err) { log(err); callback && callback(false); } else { callback && callback(content); } }); }, */ // 得到笔记内容 // noteId是本地Id getNoteContent: function(noteId, callback) { var me = this; log('getNoteContent------') me.getNote(noteId, function(note) { if(!Common.isOk(note)) { log('not ok'); log(note); callback && callback(false); } else { // 如果笔记是刚同步过来的, 那么内容要重新获取 if(note.InitSync) { log('need load from server'); if(!Api) { Api = require('api') } // 远程获取 me.getServerNoteIdByNoteId(noteId, function(serverNoteId) { if(!serverNoteId) { return callback && callback(false); } Api.getNoteContent(serverNoteId, function(noteContent) { // 同步到本地 if(Common.isOk(noteContent)) { me.updateNoteContentForce(noteId, noteContent.Content, function(content) { noteContent.Content = content; noteContent.NoteId = noteId; callback && callback(noteContent); }); } else { callback && callback(false); } }); }); } else { log('not need'); callback && callback(note); } } }); }, //---------------- // 同步 //---------------- getNoteByServerNoteId: function(noteId, callback) { var me = this; Notes.findOne({ServerNoteId: noteId}, function(err, doc) { if(err || !doc) { log('getNoteByServerNoteId 不存在' + noteId); callback && callback(false); } else { callback && callback(doc); } }); }, getNoteIdByServerNoteId: function(noteId, callback) { var me = this; Notes.findOne({ServerNoteId: noteId}, function(err, doc) { if(err || !doc) { log('getNoteIdByServerNoteId 不存在' + noteId); callback && callback(false); } else { callback && callback(doc.NoteId); } }); }, getServerNoteIdByNoteId: function(noteId, callback) { var me = this; Notes.findOne({NoteId: noteId}, function(err, doc) { if(err || !doc) { log('getServerNoteIdByNoteId 不存在'); callback && callback(false); } else { callback && callback(doc.ServerNoteId); } }); }, // 强制删除 // TODO 是否真的删除 ? // 有可能服务器上删除了是误删 ? deleteNoteForce: function(noteId, callback) { var me = this; Notes.remove({ServerNoteId: noteId}, function(err, n) { if(err) { callback && callback(false); } else { callback && callback(true); } }); }, // 添加笔记本, note object // note是服务器传过来的, 需要处理下fix // NoteId, ServerNoteId, NotebookId(本地的) addNoteForce: function(note, callback) { note.InitSync = true; // 刚同步完, 表示content, images, attach没有同步 note.IsDirty = false; note.ServerNoteId = note.NoteId; note.NoteId = Common.objectId(); Notebook.getNotebookIdByServerNotebookId(note.NotebookId, function(localNotebookId) { note.NotebookId = localNotebookId; Notes.insert(note, function (err, newDoc) { // Callback is optional if(err) { console.log(err); callback && callback(false); } else { callback && callback(newDoc); } }); }); }, // 更新笔记本, 合并之, 内容要重新获取 // note是服务器传过来的, 需要处理下fix updateNoteForce: function(note, callback) { var me = this; note.IsDirty = false; note.InitSync = true; note.LocalIsNew = false; me.getNoteIdByServerNoteId(note.NoteId, function(localNoteId) { note.NoteId = localNoteId; Notebook.getNotebookIdByServerNotebookId(note.NotebookId, function(localNotebookId) { note['NotebookId'] = localNotebookId; Notes.update({NoteId: localNoteId}, {$set: note}, {}, function (err, cnt) { // Callback is optional if(err) { console.log(err); callback && callback(false); } else { log('强制更新...'); callback && callback(note); } }); }); }); }, // 添加修改ServerNoteId; 更新修改usn updateNoteForceForSendChange: function(note, callback) { var me = this; note.IsDirty = false; note.InitSync = false; note.LocalIsNew = false; Notes.update({NoteId: note.NoteId}, {$set: note}, function(err, n) { if(err || !n) { log('updateNoteForceForSendChange err'); log(err); return callback && callback(false); } return callback && callback(true); }); }, // 服务器上的数据 // 为冲突更新, note已有有NoteId, ServerNoteId, 但NotebookId是服务器端的 updateNoteForceForConflict: function(note, callback) { var me = this; note.IsDirty = false; note.InitSync = true; note.LocalIsNew = false; Notebook.getNotebookIdByServerNotebookId(note.NotebookId, function(localNotebookId) { note['NotebookId'] = localNotebookId; Notes.update({NoteId: note.NoteId}, {$set: note}, {}, function (err, cnt) { // Callback is optional if(err) { console.log(err); callback && callback(false); } else { log('强制更新...'); callback && callback(note); } }); }); }, // 将本地冲突的笔记复制一份 // serverNoteId copyNoteForConfict: function(noteId, callback) { var me = this; me.getNote(noteId, function(note) { if(!note) { return; } // 新Id delete note['_id']; note.NoteId = Common.objectId(); note.ConflictNoteId = noteId; // 与noteId有冲突 note.ConflictTime = new Date(); // 发生冲突时间 note.ConflictFixed = false; // 冲突未解决 note.IsDirty = true; note.LocalIsNew = true; note.InitSync = false; // 都是本地的, 相当于新建的笔记 Notes.insert(note, function(err, newNote) { if(err) { callback(false); } else { callback(newNote); } }); }); }, // 处理冲突 // notes是服务器的数据, 与本地的有冲突 // 1) 将本地的note复制一份 // 2) 服务器替换之前 fixConflicts: function(noteSyncInfo, noteWeb, callback) { var me = this; // 处理冲突 if(!noteWeb) { return callback && callback(); } var conflictNotes = noteSyncInfo.conflicts; log('fix note conflicts'); log(conflictNotes); // 这里为什么要同步? 因为fixConflicts后要进行send changes, 这些有冲突的不能发送changes if(conflictNotes) { async.eachSeries(conflictNotes, function(note, cb) { // note是服务器上最新的 var noteId = note.NoteId; // 本地noteId // 复制一份 me.copyNoteForConfict(noteId, function(newNote) { if(newNote) { // 更新之前的 me.updateNoteForceForConflict(note, function(note2) { if(note2) { // 前端来处理, 全量sync时不用前端一个个处理 noteWeb && noteWeb.fixSyncConflict(note2, newNote); } cb(); }); } else { cb(); } }); }, function() { // 最后调用 callback && callback(); }); } else { callback && callback(); } // 发送改变的冲突 // 复制一份 // [待测] var changeConflicts = noteSyncInfo.changeConflicts; for(var i in changeConflicts) { var note = changeConflicts[i]; // note是本地的note // 复制一份 me.copyNoteForConfict(note.NoteId, function(newNote) { if(newNote) { // 更新之前的, 要先从服务器上得到服务版的 // 这里的note是本地的, 所以将服务器上的覆盖它 if(!Api) { Api = require('api'); } Api.getNote(note.ServerNoteId, function(serverNote) { serverNote.ServerNoteId = serverNote.NoteId; serverNote.NoteId = note.NoteId; me.updateNoteForceForConflict(serverNote, function(err, note2) { if(!err) { // 前端来处理, 全量sync时不用前端一个个处理 noteWeb && noteWeb.fixSyncConflict(note2, newNote); } }); }); } else { } }); } // 服务器没有, 但是是发送更新的, 所以需要作为添加以后再send changes if(noteSyncInfo.changeNeedAdds) { var needAddNotes = noteSyncInfo.changeNeedAdds; for(var i in needAddNotes) { log('need add '); var note = needAddNotes[i]; me.setIsNew(note.NoteId); } } // 处理添加的 var addNotes = noteSyncInfo.adds; log('has add...'); log(addNotes); noteWeb.addSync(addNotes); log('has updates...'); log(noteSyncInfo); log(noteSyncInfo.updates); // 处理更新的 noteWeb.updateSync(noteSyncInfo.updates); // 处理删除的 noteWeb.deleteSync(noteSyncInfo.deletes); }, // 获得用户修改的笔记 getDirtyNotes: function(callback) { Notes.find({UserId: User.getCurActiveUserId(), IsDirty: true}, function(err, notes) { if(err) { log(err); return callback && callback(false); } else { callback(notes); } }); }, // 在send delete笔记时成功 setNotDirty: function(noteId) { Notes.update({NoteId: noteId}, {$set:{IsDirty: false}}) }, // 在send delete笔记时有冲突, 设为不删除 setNotDirtyNotDelete: function(noteId) { Notes.update({NoteId: noteId}, {$set:{IsDirty: false, LocalIsDelete: false}}) }, setIsNew: function(noteId) { Notes.update({NoteId: noteId}, {$set:{LocalIsNew: true, IsDirty: true}}) } }; module.exports = Note;