zoukankan      html  css  js  c++  java
  • Evernote Sync Via EDAM (代码篇)

    预备结构

    这里同步某一个特定笔记本的所有笔记的实现,而且笔记都是不带资源的。另外同步笔记是不需要处理重名问题的

    在同步之前首先必然需要构造两个类,分别代表服务器端的数据,和本地端的数据,以及他们的一些操作。

    下面给出这两个类的定义,详细代码太长。明后天完成整个程序后,会把所有的代码放到GitHub中进行开源。

    其中在服务端的构造函数中完成了登入获取NoteStroe等功能,本地端的构造函数完成了从本地文件读取数据的功能

       1: class EvernoteServer
       2: {
       3:     public EvernoteServer()
       4:  
       5:     //创建AdageNotebook
       6:     private Notebook CreateAdageNotebook()
       7:  
       8:     //获取AdageNotebook下的所有的Note的元数据
       9:     //执行这个函数会在更新服务器中Note的Updated
      10:     public List<Note> GetActiveNotes()
      11:  
      12:     //获取在被删除的(在回收站中)Notes的元数据
      13:     //但是这个方法没办法获取永久性删除的数据。
      14:     public List<Note> GetInactiveNotes()
      15:  
      16:     //向服务端添加Note
      17:     //会对参数note的Guid 时间戳 USN等信息做修改
      18:     public void AddNote(Note note)
      19:  
      20:     //向服务端更新Note
      21:     //会对参数note的Guid 时间戳 USN等信息做修改
      22:     public void UpdateNote(Note note)
      23:  
      24:     //从服务端删除Note
      25:     public void DeleteNote(Note note)
      26:  
      27:     //从服务器获取带Content信息的Note
      28:     //执行这个函数会在更新服务器中note的Updated
      29:     public Note GetNote(Note note)
      30:  
      31:     //从服务器获取USN
      32:     public Int32 USN
      33:  
      34: }
       1: class LocalStroage
       2: {
       3:     public List<Note> AllNotes
       4:  
       5:     //获取本地存储的实例,从Config.LocalDataFileName读取获得。
       6:     public LocalStroage()
       7:  
      12:  
      13:     //根据模板创建一个Note,可以不添加到_list
      14:     public Note CreateNote(String adage, Boolean isAdd)
      15:     
      16:     //在本地存储添加Note
      17:     public void AddNote(Note note)
      18:  
      19:     //将于note.guid相同的节点,内容用newAdage替换
      20:     public void UpdateNote(Note note, String newAdage)
      21:  
      22:     //把list中与note.guid相同的节点用note的内容更新
      23:     //这里有可能发生,同步时服务器端把一个标记为deleted的节点更新成active的节点
      24:     public void UpdateNote(Note note)
      25:  
      26:     //从本地存储删除Note
      27:     public void DeleteNote(Note note)
      28:  
      29:     //永久性删除Note
      30:     public void ExpungeNote(Note note)
      31:  
      32:     //清除有删除标记的节点
      33:     public void Clean()
      34:  
      35:     //根据参数note的内容克隆一个Note
      36:     //克隆出来的Guid是不同的
      37:     //参数isAdd,时候将克隆出来的note加入到list
      38:     public Note CloneNote(Note note, Boolean isAdd)
      39:  
      40:     //保存到文件中
      41:     public void Save()
      42:  
      43:     //从文件中读取
      44:     private List<Note> Read()
      45: }

     

    细节

    从网络端获取的Note和本地的Note是不同对象的引用,所以做所有的本地操作的内部都要进行GUID的比对。

    执行向服务器添加Note时,参数中的note的GUID和正在添加到服务器的GUID是不同的。可以通过NoteStore.createNote(...)的返回值进行修正。这个返回值是刚刚添加进去的Note的元数据

    与添加和更新时传入的Note参数中的属性中的USN,Created,Updated等参数是不会被更新的,也是要根据返回值进行修正,这点对USN特别重要。

    GetActiveNotes 和 GetInactiveNotes在有非常多笔记的情况下要时候多次读取合并,类似于之前理论中的同步块问题

    进行读取操作(GetActiveNotes GetInactiveNotes GetNote)时会刷新服务器端的Updated时间戳,这个直接导致不能使用Updated判断服务器端是否被修改

    本地要设计一个彻底删除的方法,不然本地的数据文件会越来越大

     

    数据分析

    通过服务器端的特性和本地操作时的一些设置。我设计出一下的数据

    //本地新建的数据 是本地没有被删除的Notes和服务端所有(包括回收站中)Notes的差集

    //本地删除的数据 Active == false 这个在本地执行删除时要设置
    //本地修改的数据 Updated > Config.LastSyncTime 本地执行时要修改Note.Updated 因为时间我只用来判断本地数据是否被修改,所以我的LastSyncTime其实是本地时间

    //服务器新建的数据 服务器没有被删除的Notes和本地所有的(包括被标记为删除的)Notes的差集

    //服务器删除的数据 通过GetInactiveNotes 获取到的数据
    //服务器修改的数据 USN> Config.LastUSN

    同步策略

    有两个个会冲突的地方

    冲突1:X端删除了note1,Y端修改了note1,处理方式两端都保留被Y端删除过的note1

    冲突2:X端修改了note1,Y端也修改了note1,报告给用户,让用户决定保存那个端的,或者保存两端。保存两端即做一个克隆,个头克隆出来note一个新的GUID。关于这个冲突处理,我设计了一个事件机制,里面放了一个ConfilctResolution的枚举,通过事件传递到外部,让外部处理。或者是采用默认方案(保存两侧)

    同步代码

    主要分为查询和执行两个部分。

    执行部分的顺序是 新建 更新除了冲突2以外的东西 删除 处理冲突2

    这个顺序先更新后删除很自然的处理好了冲突1。

    查询部分大量的使用了LINQ语句,为了调试方便,没有进行太多优化(我也不太会优化这个东西)

    具体代码如下

       1: //将本地数据文件与网络同步
       2:        public void Sync()
       3:        {
       4:            //本地新建的数据 serverNotesList.Exists(s => s.Guid == l.Guid) == false
       5:            //本地删除的数据 Active == false
       6:            //本地修改的数据 Updated > Config.LastSyncTime
       7:  
       8:            //服务器新建的数据 loaclNotesList.Exists(l=>l.Guid==s.Guid) == false
       9:            //服务器删除的数据 InactiveNotesList
      10:            //服务器修改的数据 USN > Config.LastUSN
      11:  
      12:            _server = new EvernoteServer();
      13:  
      14:            #region 查询
      15:  
      16:            //获取本地的所有Note
      17:            List<Note> localAllNotes = new List<Note>();
      18:            localAllNotes.AddRange(_local.AllNotes);
      19:            //获取本地活动的Note
      20:            List<Note> localActiveNotes =  localAllNotes.FindAll(l => l.Active == true);
      21:            //获取本地删除掉的Notes
      22:            List<Note> localInactiveList = localAllNotes.FindAll(n => n.Active == false);
      23:  
      24:            //获取服务器端中活动的Note
      25:            List<Note> serverActiveNotes = _server.GetActiveNotes();
      26:            //获取服务器端回收站中的Note
      27:            List<Note> serverInactiveNotes = _server.GetInactiveNotes();
      28:            //获取服务器端所有的Note
      29:            List<Note> serverAllNotes = new List<Note>();
      30:            serverAllNotes.AddRange(serverActiveNotes);
      31:            serverAllNotes.AddRange(serverInactiveNotes);
      32:  
      33:            //需要添加到本地的Notes////////////////////
      34:            var localNeedAddNotes = serverActiveNotes.FindAll(
      35:                                 s => !localAllNotes.Exists(l => l.Guid == s.Guid));
      36:  
      37:            //需要添加到服务器的Nots///////////////////
      38:            var serverNeedAddNotes = localActiveNotes.FindAll(
      39:                                 l => !serverAllNotes.Exists(s => s.Guid == l.Guid));
      40:  
      41:  
      42:            //本地修改过的Notes
      43:            var localUpdatedNotes = 
      44:                localActiveNotes.FindAll(l =>
      45:                    serverAllNotes.Exists(s => s.Guid == l.Guid) &&
      46:                                             l.Updated > Config.LastSyncTime);
      47:            //服务器端修改过的Notes
      48:            var serverUpdatedNotes = 
      49:                serverActiveNotes.FindAll(s =>
      50:                    localAllNotes.Exists(l => l.Guid == s.Guid) &&
      51:                    s.UpdateSequenceNum > Config.LastUSN);
      52:  
      53:            //出现冲突的Notes///////////////////////
      54:            var conflictList = localUpdatedNotes.FindAll(
      55:                                l => serverUpdatedNotes.Exists(s => s.Guid == l.Guid));
      56:  
      57:            //本地需要更新的Notes/////////////////////
      58:            var localNeedUpdateNotes = serverUpdatedNotes.FindAll(
      59:                                     s => !conflictList.Exists(c => c.Guid == s.Guid));
      60:  
      61:  
      62:            //服务器需要更新的Notes////////////////////
      63:            var serverNeedUpdateNotes = localUpdatedNotes.FindAll(
      64:                                l => !conflictList.Exists(c => c.Guid == l.Guid));
      65:  
      66:  
      67:  
      68:            //需要删除的本地Notes/////////////////////////
      69:            var localNeedDeleteNotes = serverInactiveNotes.FindAll(
      70:                       i => localAllNotes.Exists(l => l.Guid == i.Guid) &&
      71:                            !localUpdatedNotes.Exists(l => l.Guid == i.Guid));
      72:  
      73:  
      74:            //需要删除的服务器端的Notes////////////////////
      75:            var serverNeedDeleteNotes = localInactiveList.FindAll(
      76:                        l => serverActiveNotes.Exists(s => s.Guid == l.Guid) &&
      77:                             !serverUpdatedNotes.Exists(s => s.Guid == l.Guid));
      78:            #endregion
      79:  
      80:            #region 操作
      81:            //向本地添加Notes
      82:            foreach(Note metadata in localNeedAddNotes)
      83:            {
      84:                Note note = _server.GetNote(metadata);
      85:                _local.AddNote(note);
      86:            }
      87:            //向服务器添加Notes
      88:            foreach(Note note in serverNeedAddNotes)
      89:            {
      90:                _server.AddNote(note);
      91:            }
      92:  
      93:            //更新本地
      94:            foreach(Note metadata in localNeedUpdateNotes)
      95:            {
      96:                Note note = _server.GetNote(metadata);
      97:                _local.UpdateNote(note);
      98:            }
      99:            //更新服务器
     100:            foreach(Note note in serverNeedUpdateNotes)
     101:            {
     102:                _server.UpdateNote(note);
     103:            }
     104:  
     105:            //本地删除
     106:            foreach(Note note in localNeedDeleteNotes)
     107:            {
     108:                _local.ExpungeNote(note);
     109:            }
     110:            //从服务器删除
     111:            foreach(Note note in serverNeedDeleteNotes)
     112:            {
     113:                _server.DeleteNote(note);
     114:                _local.ExpungeNote(note);
     115:            }
     116:            ////////////冲突处理//////////
     117:            //报告冲突,获得处理方法
     118:            //这里只实现在在两端都保留的方法
     119:            foreach(Note localNote in conflictList)
     120:            {
     121:                //获取服务器冲突的Note
     122:                Note serverNote = _server.GetNote(localNote);
     123:  
     124:                //尝试交给外部,获取冲突解决方案
     125:                if(ConfilctHappen  != null)
     126:                {
     127:                    _confilctEvenArgs.LocalAdage = localNote.Title;
     128:                    _confilctEvenArgs.ServerAdage = serverNote.Title;
     129:                    ConfilctHappen(this, _confilctEvenArgs);
     130:                }
     131:  
     132:                switch(_confilctEvenArgs.Result)
     133:                {
     134:                    case ConfilctResolution.SaveBoth:
     135:                        //将localNote进行一个克隆,并且把克隆的Note加入到local
     136:                        Note cloneNote = _local.CloneNote(localNote, true);
     137:                        //把localNote更新成serverNote
     138:                        _local.UpdateNote(serverNote);
     139:                        //把cloneNote提交到服务器
     140:                        _server.AddNote(cloneNote);
     141:                        break;
     142:                    case ConfilctResolution.SaveServer:
     143:                        _local.ExpungeNote(localNote);
     144:                        _local.AddNote(serverNote);
     145:                        break;
     146:                    case ConfilctResolution.SaveLocal:
     147:                        _server.DeleteNote(localNote);
     148:                        _server.AddNote(localNote);
     149:                        break;
     150:                    default:
     151:                        break;
     152:                }
     153:  
     154:                //消除这一次验证的选择
     155:                _confilctEvenArgs.Result = ConfilctResolution.SaveBoth;
     156:            }
     157:  
     158:            //记录LastSyncTime
     159:            Config.LastSyncTime = Config.NowTime;
     160:            //记录LastUSN
     161:            Config.LastUSN = _server.USN;
     162:            //保持local,因为在server.addNote等方法中可能会改变Note的部分属性
     163:            _local.Save();
     164:            //清理local中没有用到的标记为删除的节点
     165:            _local.Clean();
     166:            #endregion
     167:  
     168:            //刷新内存中的列表
     169:            RefreshAdageCollection();
     170:            this.GenRandomAdage();
     171:        }
  • 相关阅读:
    nginx负载均衡
    saltstack高效运维
    nginx入门与实战
    web service基础知识
    centos tomcat解压版安装
    centos yum 安装jdk1.7
    centos7安装opencv3.4.1(同样适用于最新版本4.2.0)
    正向代理与反向代理,正向代理与反向代理的应用
    MySQL日期 字符串 时间戳互转
    idea svn提交时,performing vcs refresh时间很长的解决办法
  • 原文地址:https://www.cnblogs.com/atskyline/p/2709414.html
Copyright © 2011-2022 走看看