send changes for notebook

This commit is contained in:
life
2015-01-25 13:24:57 +08:00
parent 93e5d7be6e
commit a137aada9f
12 changed files with 3122 additions and 30 deletions

50
node_modules/api.js generated vendored
View File

@@ -218,5 +218,55 @@ var Api = {
}
});
},
//------------
// 笔记本操作
//------------
addNotebook: function(notebook, callback) {
var me = this;
var data = {
title: notebook.Title,
seq: notebook.Seq,
parentNotebookId: notebook.ParentNotebookId
}
log('add notebook');
log(data);
needle.post(me.getUrl('notebook/addNotebook'), data, {}, function(err, resp) {
if(err) {
return callback(false);
}
var ret = resp.body;
log(ret);
if(Common.isOk(ret)) {
callback(ret);
} else {
callback(false);
}
});
},
updateNotebook: function(notebook, callback) {
var me = this;
var data = {
NotebookId: notebook.NotebookId,
Title: notebook.Title,
Usn: notebook.Title,
Seq: notebook.Seq,
ParentNotebookId: notebook.ParentNotebookId
}
needle.post(me.getUrl('notebook/updateNotebook'), data, {}, function(err, resp) {
if(err) {
return callback(false);
}
var ret = resp.body;
if(Common.isOk(ret)) {
callback(ret);
} else {
callback(false);
}
});
},
deleteNotebook: function(notebook, callback) {
var me = this;
}
};
module.exports = Api;

3
node_modules/async/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,3 @@
language: node_js
node_js:
- "0.10"

19
node_modules/async/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2010-2014 Caolan McMahon
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

1646
node_modules/async/README.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

11
node_modules/async/component.json generated vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"name": "async",
"repo": "caolan/async",
"description": "Higher-order functions and common patterns for asynchronous code",
"version": "0.1.23",
"keywords": [],
"dependencies": {},
"development": {},
"main": "lib/async.js",
"scripts": [ "lib/async.js" ]
}

1123
node_modules/async/lib/async.js generated vendored Executable file

File diff suppressed because it is too large Load Diff

43
node_modules/async/package.json generated vendored Normal file

File diff suppressed because one or more lines are too long

18
node_modules/note.js generated vendored
View File

@@ -1,3 +1,4 @@
var async = require('async');
var db = require('db');
var User = require('user');
var Notebook = require('notebook');
@@ -248,6 +249,7 @@ var Note = {
updateNoteForce: function(note, callback) {
note.IsDirty = false;
note.InitSync = true;
note.LocalIsNew = false;
Notes.update({NoteId: note.NoteId}, {$set: note}, {}, function (err, cnt) { // Callback is optional
if(err) {
console.log(err);
@@ -291,22 +293,30 @@ var Note = {
// notes是服务器的数据, 与本地的有冲突
// 1) 将本地的note复制一份
// 2) 服务器替换之前
fixConflicts: function(noteSyncInfo, noteWeb) {
fixConflicts: function(noteSyncInfo, noteWeb, callback) {
var me = this;
// 处理冲突
var conflictNotes = noteSyncInfo.conflicts;
for(var i in conflictNotes) {
var note = conflictNotes[i];
log('fix note conflicts');
async.eachSeries(conflictNotes, function(note, cb) {
var noteId = note.NoteId;
// 复制一份
me.copyNoteForConfict(noteId, function(newNote) {
if(newNote) {
// 更新之前的
me.updateNoteForce(note, function() {
cb();
// 前端来处理, 全量sync时不用前端一个个处理
noteWeb.fixSyncConflict && noteWeb.fixSyncConflict(note, newNote);
});
} else {
cb();
}
});
}
}, function() {
// 最后调用
callback && callback();
});
// 处理添加的
var addNotes = noteSyncInfo.adds;

39
node_modules/notebook.js generated vendored
View File

@@ -107,6 +107,7 @@ var Notebook = {
Seq: -1,
UserId: User.getCurActiveUserId(),
ParentNotebookId: parentNotebookId,
LocalIsNew: true,
IsDirty: true, // 必须, 同步后才为非dirty状态
// TODO UrlTitle
}
@@ -123,6 +124,16 @@ var Notebook = {
});
},
// 修改笔记本
updateNotebook: function(notebookId, callback) {
},
// 删除笔记本
deleteNotebook: function(notebookId, callback) {
},
// 重新统计笔记本的笔记数据
reCountNotebookNumberNotes: function(notebookId) {
db.notes.count({NotebookId: notebookId, IsTrash: false}, function(err, count) {
@@ -179,6 +190,7 @@ var Notebook = {
// 更新笔记本
updateNotebookForce: function(notebook, callback) {
notebook.IsDirty = false;
notebook.LocalIsNew = false;
NB.update({NotebookId: notebook.NotebookId}, {$set: notebook}, {}, function (err, updates) { // Callback is optional
if(err) {
console.log(err);
@@ -188,9 +200,34 @@ var Notebook = {
}
});
},
// 更新笔记本, NoteId可能也要更改
updateNotebookForceForSendChange: function(notebookId, notebook, callback) {
notebook.IsDirty = false;
notebook.LocalIsNew = false;
NB.update({NotebookId: notebookId}, {$set: notebook}, {}, function (err, updates) { // Callback is optional
if(err) {
console.log(err);
callback && callback(false);
} else {
callback && callback(notebook);
}
});
},
// 获得用户修改的笔记本
getDirtyNotebooks: function(callback) {
NB.find({UserId: User.getCurActiveUserId(), IsDirty: true}, function(err, notebooks) {
if(err) {
log(err);
return callback && callback(false);
} else {
callback(notebooks);
}
});
},
fixConflicts: function() {
}
};
module.exports = Notebook;

171
node_modules/sync.js generated vendored
View File

@@ -1,4 +1,5 @@
var db = require('db');
var async = require('async');
var Common = require('common');
var User = require('user');
var Tags = db.tags;
@@ -16,10 +17,18 @@ function log(o) {
var Sync = {
// 同步的信息, 返回给调用者
_syncInfo: {
notebook: {changeAdds: [], adds: [], deletes: [], updates: []},
note: {changeAdds: [], adds: [], deletes: [], updates: [], conflicts: []},
tag: {}
},
/*
_sendInfo: {
notebook: {adds: [], deletes: [], updates: []},
note: {adds: [], deletes: [], updates: [], conflicts: []},
tag: {}
},
*/
_needIncrSyncAgain: false,
// notebook
_syncNotebookIsLastChunk: false,
@@ -47,11 +56,23 @@ var Sync = {
me._totalHasSyncNoteNum = 0;
me._lockNote = 1;
// 同步信息
me._syncInfo = {
notebook: {ok: false, changeAdds: [], adds: [], deletes: [], updates: []},
note: {ok: false, adds: [], changeAdds: [], deletes: [], updates: [], conflicts: []},
tag: {ok: false, adds: [], changeAdds: [], deletes: [], updates: [], conflicts: []},
};
// 发送改变信息
/*
me._sendInfo = {
notebook: {ok: false, adds: [], deletes: [], updates: []},
note: {ok: false, adds: [], deletes: [], updates: [], conflicts: []},
tag: {ok: false}
};
*/
// 是否还要来一次增量同步 ?
me._needIncrSyncAgain = false;
},
//---------------
@@ -295,9 +316,11 @@ var Sync = {
},
// 记录LastSyncUsn, LastUpdateTime 同步时间
updateLastSyncState: function() {
updateLastSyncState: function(callback) {
var me = this;
User.updateLastSyncState();
User.updateLastSyncState(function() {
callback();
});
},
// 全量同步
@@ -315,10 +338,10 @@ var Sync = {
// 同步标签
me.syncTag(-1, function() {
// 更新上次同步时间
me.updateLastSyncState();
// send changes
me.sendChanges(callback);
me.updateLastSyncState(function() {
// send changes
me.sendChanges();
});
});
} else {
callback && callback(me._syncInfo);
@@ -334,13 +357,19 @@ var Sync = {
_notebookWeb: null,
_noteWeb: null,
// 处理冲突
fixConflicts: function() {
fixConflicts: function(callback) {
var me = this;
log('--------------')
var afterInfo = me._syncInfo;
log('处理冲突....')
log(me._syncInfo);
log(me._syncInfo.note.updates);
Notebook.fixConflicts(me._syncInfo.notebook, me._notebookWeb);
Note.fixConflicts(me._syncInfo.note, me._noteWeb);
Note.fixConflicts(me._syncInfo.note, me._noteWeb, function() {
// 避免无限循环, 别send changes了
if(!me._needIncrSyncAgain) {
// send changes
callback && callback();
}
});
},
// 增量同步
@@ -370,12 +399,11 @@ var Sync = {
// 同步标签
me.syncTag(lastSyncUsn, function() {
log('-------incr tag ok-----------')
// 更新上次同步时间
me.updateLastSyncState();
// send changes
me.sendChanges();
me.updateLastSyncState(function() {
// send changes
me.sendChanges();
});
});
} else {
log('-------incr note not ok-----------')
@@ -389,13 +417,118 @@ var Sync = {
});
},
//---------
// 发送改变
sendChanges: function(callback) {
var me = this;
// 先处理冲突
me.fixConflicts();
//---------
// 发送笔记本的更改
sendNotebookChanges: function(callback) {
var me = this;
// 获取所有笔记本的更改
Notebook.getDirtyNotebooks(function(notebooks) {
log('dirty notebooks');
log(notebooks);
if(!notebooks) {
callback && callback();
} else {
// 调api, 所有执行后再callback();
// 一个一个同步执行, 因为要有
async.eachSeries(notebooks, function(notebook, cb) {
var api = Api.updateNotebook;
if(notebook.LocalIsNew) {
api = Api.addNotebook;
} else if(notebook.LocalIsDelete) {
api = Api.deleteNotebook;
}
api.call(Api, notebook, function(newNotebook) {
// 更新失败
if(!newNotebook) {
return cb();
}
// 更新成功, 是否有冲突?
// newNotebook是服务器上的笔记本
// 没有更新成功
if(!newNotebook.NotebookId) {
if(newNotebook.Msg == 'conflict') {
me._syncInfo.notebook.conflicts.push(newNotebook);
// me._sendInfo.notebook.conflicts.push(newNotebook);
}
}
else {
// 更新
Notebook.updateNotebookForceForSendChange(notebook.NotebookId, newNotebook);
if(notebook.LocalIsNew) {
newNotebook.OldNotebookId = notebook.NotebookId;
me._syncInfo.notebook.changeAdds.push(newNotebook);
// me._sendInfo.notebook.adds.push(newNotebook);
} else {
me._syncInfo.notebook.updates.push(newNotebook);
// me._sendInfo.notebook.updates.push(newNotebook);
}
}
// 如果之前都很正常
if(!me._needIncrSyncAgain) {
// 检查是否有问题
if(User.getLastSyncUsn() + 1 == newNotebook.Usn) {
// 更新到本地lastSyncUsn
User.updateLastSyncUsn(newNotebook.Usn);
} else {
// newNotebook.Usn > User.getLastSyncUsn + 1, 表示服务器端在本次同步后, sendChanges之前有更新
// 那么, 还需要来一次incrSync, 之后
me._needIncrSyncAgain = true;
}
}
cb();
});
}, function() {
callback && callback();
});
}
});
},
// 发送笔记改变
sendNoteChanges: function(callback) {
log('send note changes');
callback && callback();
},
// 发送标签改变
sendTagChanges: function(callback) {
log('send note changes');
callback && callback();
},
sendChanges: function() {
var me = this;
log('send changes before...')
// 先处理冲突, 可以同时进行
me.fixConflicts(function() {
// send changes
log('send changes');
me._initSyncInfo(); // 重新初始化[]
async.series([
function(cb) {
me.sendNotebookChanges(cb);
},
function(cb) {
me.sendNoteChanges(cb);
},
function(cb) {
me.sendTagChanges(cb);
}
], function() {
// 重新再来一次增量同步
if(me._needIncrSyncAgain) {
log('-- _needIncrSyncAgain -- ')
me.incrSync(me._notebookWeb, me._noteWeb);
} else {
log('send changes 后解决冲突');
me.fixConflicts();
}
});
});
}
};

17
node_modules/user.js generated vendored
View File

@@ -125,7 +125,7 @@ User = {
},
// 同步后更新同步状态
updateLastSyncState: function() {
updateLastSyncState: function(callback) {
var me = this;
if(!Api) {
Api = require('api');
@@ -133,9 +133,24 @@ User = {
log('--updateLastSyncState---')
Api.getLastSyncState(function(state) {
if(state) {
me.LastSyncUsn = state.LastSyncUsn;
me.LastSyncTime = state.LastSyncTime;
db.users.update({UserId: me.getCurActiveUserId()}, {$set: state});
}
callback();
});
},
// send changes要用
getLastSyncUsn: function() {
var me = this;
return me.LastSyncUsn;
},
// 更新 send changes要用
updateLastSyncUsn: function(usn) {
var me = this;
me.LastSyncUsn = usn;
db.users.update({UserId: me.getCurActiveUserId()}, {$set: {LastSyncUsn: usn}});
}
};

12
test.js
View File

@@ -12,11 +12,13 @@ Notebook.addNotebook("3", "工作");
Notebook.addNotebook("4", "life2", "1");
*/
// Notebook.reCountNotebookNumberNotes('54bb2e89c596f2239a000000');
Api.addNotebook({
Title: "哈哈"
}, function() {});
// Api.auth('c@a.com', 'abc123');
var content = '<img src="http://localhost:9000/api/file/getImage?fileId=54c2083f99c37bea5f000001"> <img src="http://localhost:9000/api/file/getImage?fileId=54c2083f99c37bea5f000001">' + "\n" + '<img src="http://localhost:9000/api/file/getImage?fileId=54c2083f99c37bea5f000001">';
var reg = new RegExp('<img *src="' + Api.leanoteUrl + '/api/file/getImage', 'g');
content = content.replace(reg, '<img src="' + Server.localUrl + '/api/file/getImage');
console.log(content);
// var content = '<img src="http://localhost:9000/api/file/getImage?fileId=54c2083f99c37bea5f000001"> <img src="http://localhost:9000/api/file/getImage?fileId=54c2083f99c37bea5f000001">' + "\n" + '<img src="http://localhost:9000/api/file/getImage?fileId=54c2083f99c37bea5f000001">';
// var reg = new RegExp('<img *src="' + Api.leanoteUrl + '/api/file/getImage', 'g');
// content = content.replace(reg, '<img src="' + Server.localUrl + '/api/file/getImage');
// console.log(content);