笔记类app之Leanote同步机制 韩俊强的博客

简介: 背景最近在移动开发App时遇到一个问题:在服务端与客户端之间需要进行修改,删除,更新,添加等操作同步,为此研究了一番,其中Leanote参考了印象笔记App的同步原理。Leanote同步机制参考Evernote的机制, 关于Evernote的同步机制参考: http://dev.

背景


最近在移动开发App时遇到一个问题:在服务端与客户端之间需要进行修改,删除,更新,添加等操作同步,为此研究了一番,其中Leanote参考了印象笔记App的同步原理。

Leanote同步机制参考Evernote的机制, 关于Evernote的同步机制参考: http://dev.evernote.com/media/pdf/edam-sync.pdf


前言


Leanote主要由Notebook, Note, Tag, File(图片/附件)组成. File依附于Note存在. 当Note删除时, 其包含的File也会删除.

每个帐户(User), Notebook, Note, Tag都含有字段 Usn(Update Sequence Number), 它是整个同步系统中最重要的字段. User的Usn用于标识账户中的每一次修改, 每次修改Notebook, Note, Tag后User的Usn就会+1. 而Notebook, Note, Tag的Usn标识着一个对象最后一次被修改时的账户Usn.

举个例子, 在某一个时刻User的Usn是100. 我添加一个笔记Note1, 那么User的USN会变成101, 此时该Note1的USN也是101. 然后我再添加一个笔记Note2,这时User的Usn会变成102,Note2的Usn也是102,Note1的还是101. 这样一来我们每次同步后记录一下当时User的Usn保存为LastUSN, 下次同步的时候如果账户的Usn > LastUsn,说明账户中有东西被修改了, 此时需要先将服务器端的修改同步到本地.

当帐户第一次登录时, 此时需要进行一次全量同步, 即将服务器上所有和数据都同步到本地. 而之后用户在本地操作后, 就需要每次同步所修改的数据.

同步基本的步骤如下:

  1. Pull: 判断服务端是否有新数据, 即 通过 本地LastSyncUsn 和 服务器端Usn对比, 如果本地LastSyncUsn < 服务器端Usn, 表示服务端有修改, 此时需要同步服务器上的数据到本地. 详情请见 "同步数据".
  2. Push: 将本地修改的数据发送到服务器端. 详情请见 "发送改变".
  3. 保存状态: 获取最新同步状态, 保存服务器端最新的Usn为本地LastSyncUsn.



同步数据 Pull


从服务器端同步数据到本地.

先判断服务端是否有新数据, 即 通过 本地LastSyncUsn 和 服务器端Usn对比, 如果本地LoastSyncUsn < 服务器端Usn, 表示服务端有修改, 此时需要同步服务器上的数据到本地.

同步数据步骤:

  1. 同步Notebook
  2. 同步Note
  3. 同步Tag

同步Notebook, Note, Tag的步骤基本一致, 现拿同步Notebook作为示例, 伪代码为:

// 获取远程要同步的数据
var lastSyncUsn = getLastSyncUsn(); // 本地保存的上次同步的Usn
function syncNotebook(lastSyncUsn) {
    var afterUsn = lastSyncUsn; // 表示取lastSyncUsn之后的notebook
    while(true) {
        // 调用api, 取afterUsn的10个笔记本
        var notebooks = api.call('/api/notebook/getSyncNotebooks?afterUsn=afterUsn&maxEntry=10');
        // 将获取到的notebooks存到本地
        updateNotebookToLocal(notebooks);

        // 如果取到的notebook == 10, 表示很可能还有要同步的notebook
        if(notebooks.length == 10) {
            afterUsn = notebooks[notebooks.length-1].Usn; // 取最大的Usn作为下一个标准
        }
        // 如果 < 则表示不够了, 没有要同步的Notebook了.
        else {
            break;
        }
    }
}

// 将远程数据保存到本地
function updateNotebookToLocal(notebooks) {
    for(var i = 0; i < notebooks.length; ++i) {
        var notebook = notebooks[i];
        // 获取本地的Notebook
        var localNotebook = getLocalNotebook(notebook.NotebookId);

        // 服务器端已删除了, 此时删除本地的
        if(notebook.IsDeleted) {
            deleteLocalNotebook(notebook.NotebookId);
        }
        else {
            // 如果本地没有修改, 那么将notebook保存到本地
            if(!localNotebook.IsDirty) {
                db.updateToLocal(notebook.NotebookId, notebook);
            }
            // 本地有更新, 此时需要处理冲突
            else {

            }
        }
    }
}

获取Note, Tag要同步的数据的API为

  • /api/note/getSyncNotes
  • /api/tag/getSyncTags



如何处理冲突?


冲突发生的原因: 本地修改了, 且服务器上也修改了. 此时同步服务器上的数据到本地, 发送本地数据的IsDirty=true. 此时需要处理冲突.

处理冲突由客户端来完成, 最极端的做法是: 客户端可以完全将服务器上的数据覆盖到本地, 或者完全舍弃服务器端的数据而使用本地修改的数据.

但这样做很可能会丢失数据, 所以当遇到冲突时, 应该将服务器上的数据下载到本地和本地冲突的数据进行关联, 最后采用哪个数据由用户来决定.


发送改变 Push


将本地修改的数据发送到服务器端.

发送改变步骤:

  1. 发送修改的Notebook
  2. 发送修改的Note
  3. 发送修改的Tag

发送改变, 即得到本地修改过的Notebook, Note, Tag, 然后将修改后的信息发送到服务器端. 所以本地需要有一个标识来识别哪些数据改变了. 比如可以设置一个IsDirty的字段来标识. 如果本地的Note修改了, 更新该Note的IsDirty为true, 待发送改变成功后, 设其IsDirty=false.

下面通过发送Notebook改变作为例子:

function sendNotebookChanges() {
    var dirtyNotebooks = getDirtyNotebooks();
    for(var i = 0; i < dirtNotebooks.length; ++i) {
        var dirtyNotebook = dirtyNotebooks[i];
        // 调用api, 发送改变, 必须要传usn, 服务器端根据传过去的usn来判断是否冲突
        var ret = api.call('/api/notebook/updateNotebook?usn=dirtyNotebook.Usn&title=dirtyNotebook.Title');
        // 修改成功, 将服务器端返回的Usn更新到本地, IsDirty设为false
        if(ret.Ok) {
            updateLocalNotebook(Notebook.Id, {Usn: ret.Usn, IsDirty: false});
        }
        // 更新失败, 有冲突, 表示服务器上的数据新于本地, 此时需要解决冲突, 
        // 解决冲突的方法可以将服务器的数据覆盖到本地
        else if(ret.Msg == "conflict") {
            var serverNote = apil.call('/api/notebook/getNotebook?notebookId=dirtyNotebook.id');
            updateNotebookToLocal(serverNote);
        }
    }
}

修改Note, Tag的api为:

  • /api/note/updateNote, deleteNote
  • /api/tag/addTag, deleteTag



获取最新同步状态


调用API "/api/user/getSyncState" 获取最新同步状态, 将Usn保存到本地为LastSyncUsn;


iOS开发者交流群:446310206


目录
相关文章
|
8月前
|
移动开发 小程序 Android开发
基于 uni-app 开发的废品回收类多端应用功能与界面说明
本文将对一款基于 uni-app 开发的废品回收类多端应用,从多端支持范围、核心功能模块及部分界面展示进行客观说明,相关资源信息也将一并呈现。
269 0
|
监控 数据可视化 数据挖掘
【开发者必看—电商篇】数据赋能电商类App转化率循序增长
通过友盟+ 数据分析工具,团队深入分析了用户行为路径、转化漏斗、停留时间及错误事件等关键数据,定位到用户体验与产品性能的问题。经过精准优化,包括简化购物流程、修复技术故障及提升稳定性,最终显著提高了用户转化率。这一案例展示了数据驱动在产品优化中的重要作用。
【开发者必看—电商篇】数据赋能电商类App转化率循序增长
|
监控 搜索推荐 数据挖掘
【开发者必看—阅读篇】数据赋能阅读类App精准获客
友盟+深度数据洞察技术,可以实现用户获取的高精准度与快速增长。
【开发者必看—阅读篇】数据赋能阅读类App精准获客
|
开发工具
uniapp, 短剧视频类App实现参考,支持滑动播放,仿抖音 仿陌陌 短视频 无限滑动播放 视频流
阿里云点播服务web播放器sdk,短剧视频类App实现参考。仿抖音 仿陌陌 短视频 无限滑动播放 视频流。无uniapp video 原生组件的层级、遮挡、覆盖问题,适合与不同功能视图组合使用,实现丰富的应用功能。
uniapp, 短剧视频类App实现参考,支持滑动播放,仿抖音 仿陌陌 短视频 无限滑动播放 视频流
|
Web App开发 Java 视频直播
FFmpeg开发笔记(四十九)助您在毕业设计中脱颖而出的几个流行APP
对于软件、计算机等专业的毕业生,毕业设计需实现实用软件或APP。新颖的设计应结合最新技术,如5G时代的音视频技术。示例包括: 1. **短视频分享APP**: 集成FFmpeg实现视频剪辑功能,如添加字幕、转场特效等。 2. **电商购物APP**: 具备直播带货功能,使用RTMP/SRT协议支持流畅直播体验。 3. **同城生活APP**: 引入WebRTC技术实现可信的视频通话功能。这些应用不仅实用,还能展示开发者紧跟技术潮流的能力。
339 4
FFmpeg开发笔记(四十九)助您在毕业设计中脱颖而出的几个流行APP
|
Web App开发 5G Linux
FFmpeg开发笔记(四十四)毕业设计可做的几个拉满颜值的音视频APP
一年一度的毕业季来临,计算机专业的毕业设计尤为重要,不仅关乎学业评价还积累实战经验。选择紧跟5G技术趋势的音视频APP作为课题极具吸引力。这里推荐三类应用:一是融合WebRTC技术实现视频通话的即时通信APP;二是具备在线直播功能的短视频分享平台,涉及RTMP/SRT等直播技术;三是具有自定义动画特效及卡拉OK歌词字幕功能的视频剪辑工具。这些项目不仅技术含量高,也符合市场需求,是毕业设计的理想选择。
474 6
FFmpeg开发笔记(四十四)毕业设计可做的几个拉满颜值的音视频APP
|
编解码 Java Android开发
FFmpeg开发笔记(四十五)使用SRT Streamer开启APP直播推流
​SRT Streamer是一个安卓手机端的开源SRT协议直播推流框架,可用于RTMP直播和SRT直播。SRT Streamer支持的视频编码包括H264、H265等等,支持的音频编码包括AAC、OPUS等等,可谓功能强大的APP直播框架。另一款APP直播框架RTMP Streamer支持RTMP直播和RTSP直播,不支持SRT协议的直播。而本文讲述的SRT Streamer支持RTMP直播和SRT直播,不支持RTSP协议的直播。有关RTMP Streamer的说明参见之前的文章《使用RTMP Streamer开启APP直播推流》,下面介绍如何使用SRT Streamer开启手机直播。
397 4
FFmpeg开发笔记(四十五)使用SRT Streamer开启APP直播推流
|
Web App开发 Android开发
FFmpeg开发笔记(四十六)利用SRT协议构建手机APP的直播Demo
实时数据传输在互联网中至关重要,不仅支持即时通讯如QQ、微信的文字与图片传输,还包括音视频通信。一对一通信常采用WebRTC技术,如《Android Studio开发实战》中的App集成示例;而一对多的在线直播则需部署独立的流媒体服务器,使用如SRT等协议。SRT因其优越的直播质量正逐渐成为主流。本文档概述了SRT协议的使用,包括通过OBS Studio和SRT Streamer进行SRT直播推流的方法,并展示了推流与拉流的成功实例。更多细节参见《FFmpeg开发实战》一书。
1267 1
FFmpeg开发笔记(四十六)利用SRT协议构建手机APP的直播Demo
|
Web App开发 缓存 编解码
FFmpeg开发笔记(三十八)APP如何访问SRS推流的RTMP直播地址
《FFmpeg开发实战》书中介绍了轻量级流媒体服务器MediaMTX,适合测试RTSP/RTMP协议,但不适用于复杂直播场景。SRS是一款强大的开源流媒体服务器,支持多种协议,起初为RTMP,现扩展至HLS、SRT等。在FFmpeg 6.1之前,推送给SRS的HEVC流不受支持。要播放RTMP流,Android应用可使用ExoPlayer,需在`build.gradle`导入ExoPlayer及RTMP扩展,并根据URL类型创建MediaSource。若SRS播放黑屏,需在配置文件中开启`gop_cache`以缓存关键帧。
1232 2
FFmpeg开发笔记(三十八)APP如何访问SRS推流的RTMP直播地址
图库,设计类软件,App视频截图软件,外加设计图库,在你截取视频就能够实现图片收录,通过设计类网站后台控制系统,可以提前设置好,统计的分类内容,定义好分类,自动收录图片,再将截图汇总整理展示
图库,设计类软件,App视频截图软件,外加设计图库,在你截取视频就能够实现图片收录,通过设计类网站后台控制系统,可以提前设置好,统计的分类内容,定义好分类,自动收录图片,再将截图汇总整理展示
图库,设计类软件,App视频截图软件,外加设计图库,在你截取视频就能够实现图片收录,通过设计类网站后台控制系统,可以提前设置好,统计的分类内容,定义好分类,自动收录图片,再将截图汇总整理展示

热门文章

最新文章