incr 同步完成, 待send changes

This commit is contained in:
life
2015-01-24 14:41:24 +08:00
parent 6aef83697c
commit 93e5d7be6e
12 changed files with 411 additions and 62 deletions

View File

@@ -102,13 +102,13 @@ $(function() {
$("#loginBtn").html("loading...").addClass("disabled");
ApiService.auth(email, pwd, function(ret) {
$("#loginBtn").html("Sign in").removeClass("disabled");
// console.log(ret);
if(ret.Ok) {
$("#loginBtn").html("Success...");
location.href = 'index.html';
} else {
showMsg(ret.Msg);
}
});
});
});

49
node_modules/api.js generated vendored
View File

@@ -1,6 +1,6 @@
var db = require('db');
var Common = require('common');
var User = require('user');
var Common = require('common');
var Tags = db.tags;
var needle = require('needle');
var fs = require('fs');
@@ -8,12 +8,17 @@ var fs = require('fs');
function log(o) {
console.log(o);
}
log(Common);
log(db);
log("??")
// 远程数据服务
var Api = {
leanoteUrl: 'http://localhost:9000',
baseUrl: 'http://localhost:9000/api',
getUrl: function(url, param) {
if(!User) {
}
var url = this.baseUrl + '/' + url;
var token = User.getToken();
param = param || {};
@@ -32,12 +37,17 @@ var Api = {
// 登录
auth: function(email, pwd, callback) {
var me = this;
log({emai: email, pwd: pwd});
// log({emai: email, pwd: pwd});
// log(this.getUrl('auth/login', {email: email, pwd: pwd}));
needle.get(this.getUrl('auth/login', {email: email, pwd: pwd}), function(error, response) {
if(error) {
return callback && callback(false);
}
// needle.get('http://localhost/phpinfo.php?email=xx', {emai: email, pwd: pwd}, function(error, response) {
var ret = response.body;
// 登录成功, 保存token
log(ret);
// log('login ret');
// log(ret);
if(Common.isOk(ret)) {
ret.Pwd = pwd;
User.setCurUser(ret);
@@ -87,7 +97,12 @@ var Api = {
var me = this;
var url = this.getUrl('notebook/getSyncNotebooks', {afterUsn: afterUsn, maxEntry: maxEntry});
needle.get(url, function(error, response) {
if(error) {
return callback && callback(false);
}
var ret = response.body;
log(ret);
log(Common);
if(Common.isOk(ret)) {
callback && callback(ret);
} else {
@@ -100,6 +115,9 @@ var Api = {
var url = this.getUrl('note/getSyncNotes', {afterUsn: afterUsn, maxEntry: maxEntry});
log(url);
needle.get(url, function(error, response) {
if(error) {
return callback && callback(false);
}
var ret = response.body;
if(Common.isOk(ret)) {
callback && callback(ret);
@@ -108,12 +126,34 @@ var Api = {
}
});
},
getLastSyncState: function(callback) {
var me = this;
log('--getSyncState--')
var url = this.getUrl('user/getSyncState');
log(url);
needle.get(url, function(error, response) {
if(error) {
return callback && callback(false);
}
var ret = response.body;
log('--getSyncState--ret---')
log(ret);
if(Common.isOk(ret)) {
callback && callback(ret);
} else {
callback && callback(false);
}
});
},
// 获取笔记内容, 获取之后保存到笔记中
getNoteContent: function(noteId, callback) {
var me = this;
var url = this.getUrl('note/getNoteContent', {noteId: noteId});
log(url);
needle.get(url, function(error, response) {
if(error) {
return callback && callback(false);
}
var ret = response.body;
log('--------')
log(ret);
@@ -136,6 +176,9 @@ var Api = {
var url = me.getUrl('file/getImage', {fileId: fileId});
log(url);
needle.get(url, function(err, resp) {
if(err) {
return callback && callback(false);
}
// log(resp.body);
/*
{ 'accept-ranges': 'bytes',

5
node_modules/common.js generated vendored
View File

@@ -8,7 +8,7 @@ var ObjectId = require('objectid');
// console.log(gui.App);
function log(o) {console.log(o)}
// log("<>>>>>>>>>>>>>>>>>>>>");
var Common = {
objectId: function() {
return ObjectId()
@@ -22,11 +22,12 @@ var Common = {
if(!ret) {
return ret;
}
if(typeof ret == 'object') {
// 数组
if('length' in ret) {
return true;
}
if(typeof ret == 'object') {
if('Ok' in ret && !ret.Ok) { // 指明了Ok
return false;
}

81
node_modules/note.js generated vendored
View File

@@ -80,6 +80,7 @@ var Note = {
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) {
@@ -144,18 +145,16 @@ var Note = {
});
},
// 远程修改本地内容
updateNoteContentForce: function(noteId, content, callback) {
// <img src="http://localhost:9000/api/file/getImage?fileId=54c2083f99c37bea5f000001">
// 改成<img src="http://localhost:3232/api/file/getImage?fileId=xxx"
var reg = new RegExp('<img *src="' + Api.leanoteUrl + '/api/file/getImage', 'g');
content = content.replace(reg, '<img src="' + Server.localUrl + '/api/file/getImage');
var reg = new RegExp('src="' + Api.leanoteUrl + '/api/file/getImage', 'g');
content = content.replace(reg, 'src="' + Server.localUrl + '/api/file/getImage');
// log("----<>");
// log(content);
log("----<>");
log(content);
Notes.update({NoteId: noteId}, { $set: {Content: content, InitSync: false, IsContentDirty: false} }, {}, function (err, numReplaced) {
if(err) {
log(err);
@@ -220,6 +219,8 @@ var Note = {
//----------------
// 强制删除
// TODO 是否真的删除 ?
// 有可能服务器上删除了是误删 ?
deleteNoteForce: function(noteId, callback) {
var me = this;
Notes.remove({NoteId: noteId}, function(err, n) {
@@ -247,15 +248,81 @@ var Note = {
updateNoteForce: function(note, callback) {
note.IsDirty = false;
note.InitSync = true;
Notes.update({NoteId: note.NoteId}, {$set: note}, {}, function (err, updates) { // Callback is optional
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);
}
});
},
// 将本地冲突的笔记复制一份
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) {
var me = this;
// 处理冲突
var conflictNotes = noteSyncInfo.conflicts;
for(var i in conflictNotes) {
var note = conflictNotes[i];
var noteId = note.NoteId;
me.copyNoteForConfict(noteId, function(newNote) {
if(newNote) {
me.updateNoteForce(note, function() {
// 前端来处理, 全量sync时不用前端一个个处理
noteWeb.fixSyncConflict && noteWeb.fixSyncConflict(note, newNote);
});
}
});
}
// 处理添加的
var addNotes = noteSyncInfo.adds;
log('has add...');
log(addNotes);
noteWeb && noteWeb.addSyncNotes(addNotes);
log('has updates...');
log(noteSyncInfo);
log(noteSyncInfo.updates);
// 处理更新的
noteWeb.updateSyncNotes(noteSyncInfo.updates);
// 处理删除的
noteWeb.deleteSyncNotes(noteSyncInfo.deletes);
}
};
module.exports = Note;

4
node_modules/notebook.js generated vendored
View File

@@ -188,5 +188,9 @@ var Notebook = {
}
});
},
fixConflicts: function() {
}
};
module.exports = Notebook;

93
node_modules/sync.js generated vendored
View File

@@ -79,10 +79,13 @@ var Sync = {
me._addSyncNotebookNum();
log(me._totalHasSyncNotebookNum + ' ' + me._totalSyncNotebookNum);
if(me._syncNotebookIsLastChunk && me._totalHasSyncNotebookNum >= me._totalSyncNotebookNum) {
// 防止多次callback
if(!me._syncInfo.notebook.ok) {
me._syncInfo.notebook.ok = true;
callback && callback(true);
}
}
}
if(!notebooks || notebooks.length == 0) {
return canCall();
@@ -184,18 +187,28 @@ var Sync = {
// 同步笔记到本地
_syncNoteToLocal: function(notes, callback) {
var me = this;
function canCall() {
function canCall(isEmpty) {
// 为空时来判断是最后一次了, 可以之前的还没处理完
if(isEmpty && me._totalHasSyncNoteNum < me._totalSyncNoteNum) {
return;
}
// 是最后一块, 且
me._addSyncNoteNum();
log('notes: ' + me._totalHasSyncNoteNum + ' ' + me._totalSyncNoteNum + ' ' + me._syncNoteIsLastChunk);
// log('notes: ' + me._totalHasSyncNoteNum + ' ' + me._totalSyncNoteNum + ' ' + me._syncNoteIsLastChunk);
if(me._syncNoteIsLastChunk && me._totalHasSyncNoteNum >= me._totalSyncNoteNum) {
// 防止多次callback
if(!me._syncInfo.note.ok) {
log('note->next');
me._syncInfo.note.ok = true;
callback && callback(true);
}
}
}
// 为什么会出现最后 > 的情况, 是因为这里length == 0 也判断了
if(!notes || notes.length == 0) {
return canCall();
return canCall(true);
}
for(var i in notes) {
@@ -229,7 +242,7 @@ var Sync = {
} else {
// 2.2 本地是否修改了, 冲突, 报告给前端, 前端处理
// 冲突, 将本地修改的笔记复制一份(设置冲突字段, ConflictNoteId), 远程的覆盖本地的
if(note.IsDirty) {
if(noteLocal.IsDirty) {
log('冲突....')
me._syncInfo.note.conflicts.push(note);
return canCall();
@@ -258,7 +271,7 @@ var Sync = {
me._totalSyncNoteNum += notes.length;
// 证明可能还有要同步的
if(notes.length == me._noteMaxEntry) {
me._syncNoteToLocal(notes);
me._syncNoteToLocal(notes, callback);
var last = notes[notes.length-1];
me.syncNote(last.Usn, callback);
} else {
@@ -281,6 +294,11 @@ var Sync = {
callback && callback(true);
},
// 记录LastSyncUsn, LastUpdateTime 同步时间
updateLastSyncState: function() {
var me = this;
User.updateLastSyncState();
},
// 全量同步
fullSync: function(callback) {
@@ -296,7 +314,11 @@ var Sync = {
if(ok) {
// 同步标签
me.syncTag(-1, function() {
callback && callback(me._syncInfo);
// 更新上次同步时间
me.updateLastSyncState();
// send changes
me.sendChanges(callback);
});
} else {
callback && callback(me._syncInfo);
@@ -309,30 +331,71 @@ var Sync = {
});
},
// 增量同步
incrSync: function() {
_notebookWeb: null,
_noteWeb: null,
// 处理冲突
fixConflicts: function() {
var me = this;
log('--------------')
log(me._syncInfo);
log(me._syncInfo.note.updates);
Notebook.fixConflicts(me._syncInfo.notebook, me._notebookWeb);
Note.fixConflicts(me._syncInfo.note, me._noteWeb);
},
// 增量同步
incrSync: function(notebookWeb, noteWeb) {
var me = this;
me._notebookWeb = notebookWeb;
me._noteWeb = noteWeb;
me._initSyncInfo();
log('full sync start');
log('inc sync start');
// 得到当前LastSyncUsn
User.getLastSyncInfo(function(lastSyncUsn, lastSyncTime) {
User.getLastSyncState(function(lastSyncUsn, lastSyncTime) {
// 没有上次同步的时间, 则需要进行一次全量同步, 不可能会发生
if(!lastSyncUsn) {
log('error!!');
return;
}
// 同步笔记本
me.syncNotebook(-1, function() {
me.syncNotebook(lastSyncUsn, function(ok) {
if(ok) {
log('-------incr notebook ok-----------')
// 同步笔记
me.syncNote(-1, function() {
me.syncNote(lastSyncUsn, function(ok) {
if(ok) {
log('-------incr note ok-----------')
// 同步标签
me.syncTag(-1, function() {
callback && callback(me._syncInfo);
me.syncTag(lastSyncUsn, function() {
log('-------incr tag ok-----------')
// 更新上次同步时间
me.updateLastSyncState();
// send changes
me.sendChanges();
});
} else {
log('-------incr note not ok-----------')
me.fixConflicts();
}
});
} else {
me.fixConflicts();
}
});
});
},
// 发送改变
sendChanges: function() {
sendChanges: function(callback) {
var me = this;
// 先处理冲突
me.fixConflicts();
callback && callback();
}
};

58
node_modules/user.js generated vendored
View File

@@ -13,13 +13,17 @@ Token
LastLoginTime
IsActive // 是否是活跃用户
*/
// var User = {}
var Api = null; // require('api');
// 用户基本信息
var User = {
User = {
token: '',
userId: '',
email: '',
username: '',
LastSyncUsn: -1,
LastSyncTime: null,
// 登录后保存当前
setCurUser: function(user) {
if(user) {
@@ -61,13 +65,20 @@ var User = {
init: function(callback) {
console.log("......user init.......")
var me = this;
db.users.findOne({IsActive: true}, function(err, doc) {
if(err || !doc) {
db.users.findOne({IsActive: true}, function(err, user) {
if(err || !user || !user.UserId) {
log('不存在');
callback && callback(false);
} else {
me.setCurUser(doc);
callback && callback(doc);
// me.setCurUser(doc);
me.token = user.Token;
me.userId = user.UserId;
me.email = user.Email;
me.username = user.Username;
me.LastSyncUsn = user.LastSyncUsn;
me.LastSyncTime = user.LastSyncTime;
callback && callback(user);
}
});
},
@@ -89,6 +100,43 @@ var User = {
},
getCurUserAttachsAppPath: function() {
return 'data/' + this.getCurActiveUserId() + '/attachs';
},
getCurUser: function(callback) {
var me = this;
db.users.findOne({_id: me.getCurActiveUserId()}, function(err, doc) {
if(err) {
callback(false);
} else {
callback(doc);
}
});
},
getLastSyncState: function(callback) {
var me = this;
me.getCurUser(function(user) {
if(user) {
callback(user.LastSyncUsn, user.LastSyncTime);
} else {
callback(false, false);
}
})
},
// 同步后更新同步状态
updateLastSyncState: function() {
var me = this;
if(!Api) {
Api = require('api');
}
log('--updateLastSyncState---')
Api.getLastSyncState(function(state) {
if(state) {
db.users.update({UserId: me.getCurActiveUserId()}, {$set: state});
}
});
}
};
module.exports = User;

View File

@@ -414,15 +414,16 @@ function log(o) {
</div>
<ul class="pull-right" id="editorTool">
<li><a class="ios7-a " id="saveBtn" title="ctrl+s"
<li><a class="ios7-a " id="saveBtn" title="Save ctrl+s"
data-toggle="dropdown">
<span class="fa fa-save"></span>
Save</a></li>
</a></li>
<li class="dropdown" id="attachDropdown">
<a class="ios7-a dropdown-toggle" data-toggle="dropdown" id="showAttach">
<a class="ios7-a dropdown-toggle" data-toggle="dropdown" id="showAttach" title="Attachments">
<span class="fa fa-paperclip"></span>
attachments<span id="attachNum"></span>
<span id="attachNum"></span>
</a>
<div class="dropdown-menu" id="attachMenu">
<ul id="attachList">
@@ -451,13 +452,13 @@ function log(o) {
</li>
<li><a class="ios7-a " id="tipsBtn"
data-toggle="dropdown">
data-toggle="dropdown" title="Tips">
<span class="fa fa-question"></span>
Tips</a></li>
</a></li>
<li><a class="ios7-a " id="contentHistory"
data-toggle="dropdown">
data-toggle="dropdown" title="Histories">
<span class="fa fa-history"></span>
Histories</a></li>
</a></li>
</ul>
</div>

View File

@@ -11,7 +11,6 @@ UserService.init(function(userInfo) {
UserInfo = userInfo;
location.href = 'note.html';
} else {
alert(2);
location.href = 'login.html';
}
});

View File

@@ -628,8 +628,8 @@ Note.changeNote = function(selectNoteId, isShare, needSaveChanged, callback) {
cacheNote.InitSync = false;
}
ret = ret || {};
log(">>")
log(ret);
// log(">>")
// log(ret);
Note.contentAjax = null;
if(seq != Note.contentAjaxSeq) {
return;
@@ -744,14 +744,20 @@ Note.renderNote = function(note) {
// 笔记是新render的, 没有污染过
note.isDirty = false;
}
};
// render content
Note.renderNoteContent = function(content) {
setEditorContent(content.Content, content.IsMarkdown, content.Preview);
// 只有在renderNoteContent时才设置curNoteId
Note.curNoteId = content.NoteId;
}
// life
// 重新渲染到左侧 desc, 因为笔记传过来是没有desc的
content.Desc = Note.genDesc(content.Content);
content.ImgSrc = Note.getImgSrc(content.Content);
Note.renderChangedNote(content);
};
// 初始化时渲染最初的notes
/**
@@ -845,6 +851,26 @@ Note.renderNotes = function(notes, forNewNote, isShared) {
})(i), i*2000);
}
}
;
Note._getNoteHtmlObjct = function(note, isShared) {
var baseClasses = "item-my";
if(isShared) {
baseClasses = "item-shared";
}
var classes = baseClasses;
var tmp;
if(note.ImgSrc) {
tmp = tt(Note.itemTpl, classes, note.NoteId, note.ImgSrc, note.Title, Notebook.getNotebookTitle(note.NotebookId), goNowToDatetime(note.UpdatedTime), note.Desc);
} else {
tmp = tt(Note.itemTplNoImg, classes, note.NoteId, note.Title, Notebook.getNotebookTitle(note.NotebookId), goNowToDatetime(note.UpdatedTime), note.Desc);
}
if(!note.IsBlog) {
tmp = $(tmp);
tmp.find(".item-blog").hide();
}
return tmp;
},
Note._renderNotes = function(notes, forNewNote, isShared, tang) { // 第几趟
var baseClasses = "item-my";
if(isShared) {
@@ -1866,3 +1892,81 @@ $(function() {
// 定时器启动
Note.startInterval();
//----------------------
// 冲突解决, 增量sync时
// note是服务器端的笔记, newNote是本地复制后的笔记
Note.fixSyncConflict = function(note, newNote) {
// Note.cache[note.NoteId] = note;
// Note.cache[newNote.NoteId] = newNote;
Note.addNoteCache(note);
Note.addNoteCache(newNote);
var target = $(tt('[noteId="?"]', note.NoteId)); //
// 如果当前笔记在笔记列表中, 那么生成一个新笔记放在这个笔记上面
if(target.length > 0) {
var newHtmlObject = Note._getNoteHtmlObjct(note);
newHtmlObject.insertBefore(target);
}
// 当前这个换成新复制的
target.attr('noteId', newNote.NoteId);
// 重新render 左侧下, 因为有冲突了, 不要render内容啊
// 如果当前编辑的是这个笔记, 那切换到newNote上来
if(Note.curNoteId == note.NoteId) {
Note.curNoteId = newNote.NoteId;
}
};
// 添加同步的notes
Note.addSyncNotes = function(notes) {
if(isEmpty(notes)) {
return;
}
for(var i in notes) {
var note = notes[i];
Note.addNoteCache(note);
// 添加到当前的笔记列表中
var newHtmlObject = Note._getNoteHtmlObjct(note);
log(newHtmlObject);
$('#noteItemList').prepend(newHtmlObject);
}
}
// 更新
Note.updateSyncNotes = function(notes) {
log("??")
if(isEmpty(notes)) {
return;
}
log("what?")
for(var i in notes) {
var note = notes[i];
note.InitSync = true; // 需要重新获取内容
Note.addNoteCache(note);
// 如果当前修改的是本笔记, 那么重新render之
log('->>>')
log(Note.curNoteId);
if(Note.curNoteId == note.NoteId) {
log('yes---');
Note.changeNote(Note.curNoteId);
}
}
}
// 删除
Note.deleteSyncNotes = function(notes) {
if(isEmpty(notes)) {
return;
}
for(var i in notes) {
var noteId = notes[i];
note = Note.getNote(noteId);
if(note) {
Note.clearCacheByNotebookId(note.NotebookId);
delete Note.cache[noteId];
// 如果在笔记列表中则删除
$(tt('[noteId="?"]', note.NoteId)).remove();
}
}
}

View File

@@ -973,3 +973,10 @@ $(function() {
Notebook.contextmenuSearch.showMenu(e, $p);
});
});
//---------------
// 笔记本解决冲突
Notebook.fixConflict = function() {
};

View File

@@ -1304,6 +1304,12 @@ function fullSync(callback) {
});
}
// 增量同步
function incrSync() {
log('full sync');
SyncService.incrSync(Notebook, Note);
}
// note.html调用
// 实始化页面
// 判断是否登录
@@ -1312,6 +1318,7 @@ function initPage() {
$(function() {
// 获取笔记本
Service.notebookService.getNotebooks(function(notebooks) {
log(notebooks);
Notebook.renderNotebooks(notebooks);
});
@@ -1345,9 +1352,14 @@ function initPage() {
UserService.init(function(userInfo) {
if(userInfo) {
UserInfo = userInfo;
// 之前已同步过, 就不要full sync了
if('LastSyncUsn' in UserInfo) {
_init();
} else {
fullSync(function() {
_init();
});
}
} else {
location.href = 'login.html';
}