Database - Graan/open GitHub Wiki
本地表
- User
- Issue
- IssueComment
- Label
- Repos
数据同步
方案一:通过Event
测试了如下接口:
- List repository events
GET /repos/:owner/:repo/events
- List issue events for a repository
GET /repos/:owner/:repo/issues/events
发现的问题:
- 接口1返回的事件只有几种类型:IssueCommentEvent只有created状态没有修改和删除事件,IssuesEvent只有opened和closed状态没有修改的事件
- 接口2返回的事件只发现了labeled和unlabeled,未发现关于修改的事件
综上所述,目前通过Event方式暂时行不通
方案二:每次打开app拉取所有Issue,IssueComment,Label更新
同步:定时从本地检查有修改的数据并上传,每次打开app优先上传本地待上传数据
更新:每次打开app上传完有改动数据后重新拉取所有数据更新本地,用户手动点更新按钮拉取所有数据更新本地,不做定时拉取所有数据(或拉取时间设置大一些),Issue和IssueComment接口提供了since参数,本地记录每次更新时间time,下次更新time以后的数据
缺点:
拉取数据时会把所有数据都拉取一遍,不太友好(通过since参数减少拉取量)- 多设备覆盖问题,同一条日记,假设3.1日A设备修改数据后未上传,3.2日B设备修改了数据上传了,3.3日打开A设备,会向上同步数据覆盖掉3.2日的数据
方案三:在.graan文件夹创建一个log文件
本地维护log表,同步到github
大体逻辑:
- 本地修改内容后首先同步到数据库中,并做标记
- 开启定时任务,检测表中数据改动并上传,上传成功后在log文件中标记该数据(类型,id,isSync,time ... )
- 上传log文件覆盖远端log文件
- 定时向下拉取log文件,跟本地log文件对比,把差异内容做同步
缺点:
- log文件的处理比较复杂,怎么对比,怎么解决多端登录后的冲突,数据也会越来越多,每次对比本地log和远端log产生的逻辑判断比较复杂且耗时
- 用户手动在github修改内容后无法写入到log文件中,因此无法根据log文件同步到最新内容
表结构
User
{
"login": "tianyu704",
"id": 7546212,//PrimaryKey
"avatar_url": "https://avatars3.githubusercontent.com/u/7546212?v=4",
"name": "Hugo.Guo",
"email": "[email protected]",
"created_at": "2014-05-11T02:07:59Z",
"updated_at": "2019-03-26T08:35:21Z"
}
Issue
{
"id": 410647133,//PrimaryKey
"number": 5,
"repository_url":"https://api.github.com/repos/tianyu704/Test"
"title": "记录",
"labels": [{
"id": 1217139811,
"url": "https://api.github.com/repos/tianyu704/Test/labels/_note",
"name": "_note",
"color": "ededed",
"default": false
}],
"state": "open",
"locked": false,
"comments": 1,
"created_at": "2019-02-15T07:56:07Z",
"updated_at": "2019-03-25T10:07:56Z",
"closed_at": null,
"body": "这里记录 大发发",
"has_local_change":1
}
IssueComment
{
"id": 463037067,//PrimaryKey
"created_at": "2019-02-13T03:00:29Z",
"updated_at": "2019-02-14T06:33:22Z",
"issue_url": "https://api.github.com/repos/tianyu704/Test/issues/1",
"body": "# 大标题\n```code hejeueu```\n* wws\n* zzzzz\n~~哈哈~~\n\n## 小标题",
"has_local_change":1,
"state":"" //delete/create/update
}
Reaction
{
"id": 1232112341234,
"content": "heart",
"comment_id": 1231341234,
"has_local_change": 0,
"state": "delete" // delete/create
}
Label
{
"id": 1258786034,//PrimaryKey
"url": "https://api.github.com/repos/tianyu704/Test/labels/_bookmark",
"name": "_bookmark",
"color": "ededed",
"default": false,
"state":"", //delete/create/""
"has_local_change":1
}
Repos
{
"id": 174089690,
"name": "butterknife",
"full_name": "tianyu704/butterknife",
"private": false,
"description": "Bind Android views and callbacks to fields and methods.",
"created_at": "2019-03-06T06:58:21Z",
"updated_at": "2019-03-06T06:58:24Z"
}
本地数据库操作及数据同步细节
- 创建仓库暂时只支持在线创建。创建完仓库的同时要在线创建默认的日记Issue,在线创建默认的日记IssueComment
- 用户切换到日记页面,检测当前仓库有没有日记Issue,没有先创建日记Issue,再创建日记IssueComment
- 其他Issue,IssueComment,Label表都离线操作,数据定时(暂定60s)统一上传和更新
- 循环拉取的顺序Repository->Issue->IssueComment->Reaction,Label可与Issue同时开始拉取
Issue表
- 用户修改笔记/书签的state(删除操作)、标题、内容、标签后优先修改到Issue表中,将has_local_change值改成1
- 用户创建笔记/书签,取当前时间戳作为Id存储到数据库中,并将has_local_change值改成1
- 定时上传Issue,检查has_local_change=1的数据,分为两组:第一组是number=0,代表新创建的Issue,遍历并执行创建接口,创建成功后将这条数据从数据库中删除并且把接口返回的Issue信息存入数据库完成上传操作;第二组是number≠0,代表是修改的Issue,遍历执行更新接口并把返回结果更新到本地数据库中完成上传操作
- 数据都上传完后,执行下载接口,下载前取当前系统时间sinceNew作为临时变量,请求Issue列表时传入since=上次更新时间,下载完成后将结果更新到数据库中,并更新本地since=sinceNew
Label表
- 用户创建Label后取当前时间戳作为Id,state="create",存入数据库中
- 用户删除Label,将state="delete",更新数据库
- 定时上传Label信息,取state="delete"的数据执行删除Label接口,删除成功后本地删除此Label
- 3执行完后执行更新Label操作,并更新本地数据库
- 去除冗余Label,查询state="create"且数据库中无关联的Issue的Label集合,遍历集合查询每条Label的url在Label库中是否有重复,有则删除此Label
说明:由于同步Issue表时,新创建的Label会通过更新Issue的方式在github端创建,因此上传Label表时无需再上传新建的Label,只需把删除的Label上传即可。冗余Label来自Issue上传后新Label会存储到Label库中,旧Label失效,但不能直接删除,有可能被其他Issue引用,但经过5中的过滤后可以保证此Label是冗余,再删除。本地创建且没有被Issue引用的Label上传不上传没有关系
IssueComment
- 用户修改日记时,修改相应字段,state="update",has_local_change=1,更新IssueComment表,如果有reaction的添加或删除,同时更新Reaction表
- 用户创建日记时,取时间戳作为Id,state="create",has_local_change=1存入IssueComment表中,如果有reaction的添加或删除,同时更新Reaction表
- 用户删除日记时,state="delete",has_local_change=1更新IssueComment表,将此IssueComment关联的reaction的state="delete"并更新
- 定时上传,查询has_local_change=1的数据根据state字段分类
- state="update",将更新内容上传并将返回结果更新到数据库,检查该IssueComment关联的reaction,把has_local_change=1的reaction根据state执行删除或创建的上传操作,成功后添加上新的reaction并删除旧的reaction
- state="create",将创建内容上传,成功后将旧IssueComment删除,将返回结果更新到数据库,检查旧IssueComment关联的reaction,更新comment_id为新IssueComment的id,再把has_local_change=1的reaction根据state执行删除或创建的上传操作,成功后添加上新的reaction并删除旧的reaction
- state="delete",将删除的IssueComment执行删除接口,成功后删除本地IssueComment并删除关联的reaction
- 4执行完后,执行更新IssueComment接口,更新本地表
Repository表
- 用拉取.graan文件方式获取repos列表
- 遍历repos根据id查询本地数据库中是否有repo,如果数据库中没有但存在相同名字的repo,则删除库中的repo及issue,comment,reaction,label等信息后存入新repo,否则直接存入新repo。
- 查询库中所有repo,判断是否都在拉取的repos列表中,如果有不存在的,请求拉取repo接口,如果接口返回404,则删除本地repo及其他相关表
- 拉取顺序。处理完Repository,可同时异步拉取Issue和label,拉取完Issue依次同步拉取->IssueComment->Reaction