具有双向同步功能的OneDrive客户端

onedrive-sync-client的Python项目详细描述


Build Status

双向单驱动器同步客户端

disclaimer:此实用程序处于早期阶段。虽然它的设计是为了在检测到冲突时尽快失败,以避免数据丢失,但不能保证您的数据绝对安全。在知道发生了什么之前,在测试环境中运行它

基于用python编写的Microsoft Graph,此实用程序将检测您在本地所做的更改和在云中发生的更改,并尝试在两侧合并它们。如果由于冲突而失败,例如,您在本地重命名了一个文件,但在手机上用另一个文件名分配了同一个文件,则此实用程序将在执行任何操作之前投诉并失败,以确保数据保持完整。

要试用它,只需在终端中键入(假设您使用的是gnu/linux,而~/.local/bin在您的$PATH)中即可

pip install --user onedrive-sync-client # Install
# If you want to use the latest snapshot use the following line instead
# pip install --user https://github.com/gzxu/onedrive-sync-client/archive/master.zip
onedrive --set-location ~/OneDrive      # Config
onedrive                                # Sync!

目前,这个实用程序利用extended attributes在本地保存文件标识符,而现代文件系统和发行版在默认情况下应该启用这个功能。将创建一个sqlite数据库,并将其用作中心位置,以保存首次运行时的基本信息,如上次同步时的login token或整个文件系统树的状态。我们将要求您授予访问OneDrive文件(当然)和“随时访问您的信息”的权限,这意味着您不必每次使用时都进行登录和授权。

算法

一个重要的背景是,与几乎所有云存储提供商一样,OneDrive会为每个文件或目录(文件夹)分配一个全局唯一的标识符,因为该标识符还链接到其他元数据,如是否允许匿名访问者查看该文件,以及元数据列表随时可能增长。这有效地降低了算法的复杂度。

首先,在两侧构建文件系统树层次结构。OneDrive为我们提供了a simple API以递归方式将整个树转储到云上,其中包含每个项的标识符和名称,此外,每个文件的校验和(当前实现不同)。利用上述信息容易构造本地树,并且可以从每个文件或目录的扩展属性中读取标识符信息。您可以通过getfattr -n user.onedrive.id FILENAME检查本地存储的标识符。最初使用扩展属性是因为它与相应的文件一起移动,但是默认的文件管理器nautilus在复制文件时复制所有扩展属性。这将导致重复的标识符。此外,对于新的本地创建的文件,将没有标识符,因此本地构建的树需要为每个文件分配一个临时标识符,并维护实际标识符和临时标识符之间的映射。同时,还加载上次同步时树的保存状态。

然后是三棵树,云树,本地树和保存的树。我们需要以双向方式合并它们。然后将云树与保存的树进行比较。尽管我们称它们为“树”,但它们实际上是按其标识符排序的节点列表。每个节点存储其名称、校验和(如果适用)以及其父节点的标识符。对于每个标识符,如果对应的节点在云树和保存的树中相同,则视为未更改。即使其父节点被重命名或移动,只要其父节点的标识符保持不变,该节点也将与其父节点一起移动。如果标识符只存在于云树中,则必须是新创建的;如果仅存在于基本树中,则必须在上次同步之后从云中移除该标识符。如果其父项的标识符不同,则必须移动它。如果其名称或校验和已更改,则必须重命名或重写。然后,我们在云树之间得到一个变化集还有那棵被拯救的树。为本地树所做的类似方法,但是由于会有重复的标识符,对于每个重复,将保留其中最相似的标识符,而其他标识符将被视为新创建的标识符。这不是最优的,因为如果我们在本地复制一个文件夹,会有大量的上传流量,因为我们需要上传整个文件夹。

现在我们有两个变更集,一个在云树和保存的树之间,另一个在本地树和保存的树之间。每个变更集由多个操作组成,每个操作都属于下列类型之一:

  • 用给定的名称和给定的校验和创建一个文件到给定的目录
  • 删除给定的文件
  • 用给定的校验和覆盖给定文件的内容
  • 用给定的名称重命名给定的文件并/或将其移动到给定的父目录
  • 使用给定目录的给定名称创建目录
  • 删除给定的目录(此目录必须为空)
  • 用给定的名称重命名给定的目录并/或将其(及其所有子目录)移动到另一个给定的父目录
  • 复制文件或目录(当前未实现和省略)

从上一步生成的这个集合是无序的,但是它们必须按顺序应用。这些步骤的某些排列是可以接受的,但其他的则会导致冲突。例如,不能在创建父文件之前创建该文件。操作可能与同一集合中的操作冲突,该集合表示从保存的树到新树的实际可能更改顺序;它们也可能与另一集合中的操作冲突,这可能导致合并过程无法实现。

冲突检查和脚本排序

有两种冲突。其中一个是两个集合之间的冲突,即两个集合不能同时修改同一个节点。另一种是,实际上不仅仅是冲突,而是在一个变更集中进行排序,并让它被排序。这两个集合之间不需要考虑顺序,因为云集合必须在本地集合之后应用,实际上它已经在本地集合之前应用。

对于每个标识符,对应的节点不能应用冲突操作。冲突操作可能不会发生在一个变更集中,而只发生在两个变更集中,因为它们是从同一棵树生成的。具有完全相同参数的两个操作不冲突,但如果不冲突,则它们在具有相同类型的操作时相互冲突。此外,删除节点与该节点上的任何其他操作都有冲突。此处不需要考虑添加节点,因为在同一标识符上不会有其他操作。

排序问题是一个拓扑排序问题。每一个操作都被建模为一个顶点,如果一个操作在另一个操作之后发生,它们之间会有一条有方向的边。此图中的循环表示冲突。

为了发现不同标识符之间的冲突,对每个操作的先决条件和效果进行标记和索引。有两种类型的先决条件,以及两种对应类型的效果:给定的目录存在,给定目录内的给定名称没有被占用。操作应该在这些操作之后应用,为其先决条件提供相应的效果。

  1. 创建文件
      先决条件:目的地必须存在
    • 先决条件:目的地中的名称必须可用
  2. 删除文件
    • 效果:释放该名称
  3. 重写文件
    • 无先决条件或效果
  4. 重命名和移动文件
      先决条件:目的地必须存在
    • 先决条件:目的地中的名称必须可用
    • 效果:释放原始名称
  5. 创建目录
      先决条件:目的地必须存在
    • 先决条件:目的地中的名称必须可用
    • 影响:此目录开始存在< > >
  6. 删除目录
    • 先决条件:必须发布所有当前名称
    • 效果:释放该名称
  7. 重命名并移动目录
      先决条件:目的地必须存在
    • 先决条件:目的地中的名称必须可用
    • 效果:释放原始名称

实际上,有些情况不在该算法的范围内,例如,创建两个具有不同标识符(当然)但在同一目录下具有相同名称的文件是不会被检测到的。这种冲突发生在两个变更集之间,并且只与名称冲突相关。应该有更多未公开的冲突,因此在应用之前应该测试生成的脚本。

脚本检查和优化

拓扑排序后,生成的脚本将应用于两棵树的测试副本,如果有删除目录的操作,则从该目录中删除项的任何操作都可以标记为忽略,作为优化。

应用脚本并保存树

rest api在Microsoft Graph documentation site中进行了描述,有一些地方需要特别注意。树作为标识符和属性表保存到数据库中。

delta列表

OneDrive为dump the whole tree提供了一个API。这棵树可能很大,传输过程可能很慢。为了解决这个问题,可以保存上次转储查询的结果,并使用delta api生成真正的云树。当delta api不可用时,可以使用回退方法。

批量请求

请求代理可用于临时存储请求,并在任何强制刷新之前使用batch API保存通信量。另外,一些http库还支持htp2.0以另外节省流量。然而,这涉及到一个更复杂的算法。

文件下载和上传

由于OneDrive支持部分下载,因此需要一个下载管理器,特别是当文件很大时。有两个上传api,还需要一个上传管理器。在良好的网络条件下,{a10}更易于使用,并且适合于小于4mib的文件。当文件太大或网络状况不好时,必须使用^{} API。若要通过此API上载文件,必须提供父标识符和文件名,并且由于服务器的错误,仅使用文件标识符创建上载会话是不可行的。

已知问题

  1. 一些应用程序,即Gedit,将删除附加到文件的已保存属性,因为它实际上创建了一个新文件并删除了旧文件。由于ID信息丢失,同步时我们必须执行相同的操作(删除并重新上载)
  2. 由于此实用程序中存在未解决的错误,增量功能暂时禁用

未来工作

  • []通过检测丢失的标识符并提示用户来解决上述问题
  • [X]解决上述错误并修改算法以覆盖上述情况
  • [X]通过修剪在云中优化删除
  • []事务同步以避免不可预知的异常
  • []通过省略两个变更集中相同的变更进行优化
  • [X]添加选项以强制使用云覆盖本地树,反之亦然
  • [X]使用^{}来检测更改,而不是检查和,以加快本地树的构造和OneDrive for Business and SharePoint Server 2016支持。校验和可以作为检测局部变化的辅助方法,^ {CD8}}s可以用来检测云
  • 的变化。
  • [X]尽可能在处理数据库时使用DAO
  • [X]使用sqlalchemy作为ORM引擎
  • []实现双赢DOWS和/或MacOS支持(简单但可能不必要的工作)
  • []提出一个更好的模型来描述这个问题,并在此基础上修改算法
  • []在注释中补充文档
  • []通过引入单元测试来清除bug
  • []上述批量请求代理
  • [X]针对不稳定网络连接的下载和上载管理器
  • []具有多线程支持的下载和上载管理器
  • []利用copy API,但是由于这是异步的,所以并行编程是必需的
  • []使用^{}以外的库支持http 2.0
  • []修改命令行用户界面,以可读的方式列出必要的信息
  • []妥善处理所有可能的异常情况
  • []引入日志框架
  • []设计简洁的图形用户界面
  • []在可能的端口到C++

许可证

这个项目是根据GNU Affero General Public License授权的。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java为什么需要ScheduledExecutorService。shutdown()使用我100%的CPU吗?   java如何加载应用程序。spring框架中的属性?   java立即绘制JFrame   java定时器不允许用户进行编辑   java如何通过在React应用程序中提交值来加载数据   java在Multimultiul maven项目中集成特性(文件)存储在哪里?   java Arjuna JTA事务意外回滚   java禁用edittext 安卓,在视图中使用if-else   java中的错误。图书馆从Matlab调用使用Cplex的Java函数时的路径   Java中的浮点计算错误   Java中C#IEnumerable的等价物是什么?是可协变的,不是可协变的   最终播放商店用户可见的java Apk名称