Correct way to use OneDrive API to sync files

落爺英雄遲暮 提交于 2019-11-29 12:53:45

Synchronization requires a few different steps, some of which the OneDrive API will help you with, some of which you'll have to do yourself.

Change Detection
The first stage is obviously to detect whether anything has changed. The OneDrive API provides two mechanism to detect changes in the service:

  1. Changes for individual files can be detected using a standard request with an If-None-Match:

    await this.userDrive.Drive.Special.AppRoot.ItemWithPath(remotePath).Content.Request(new Option[] { new HeaderOption("If-None-Match", "etag") }).GetAsync();
    

    If the file doesn't yet exist at all you'll get back a 404 Not Found. Else if the file has not changed you'll get back a 304 Not Modified.
    Else you'll get the current state of the file.

  2. Changes for a hierarchy can be detected using the delta API:

    await this.userDrive.Drive.Special.AppRoot.Delta(previousDeltaToken).Request().GetAsync();
    

    This will return the current state for all items that changed since the last invocation of delta. If this is the first invocation, previousDeltaToken will be null and the API will return the current state for ALL items within the AppRoot. For each file in the response you'll need to make another round-trip to the service to get the content.

On the local side you'll need to enumerate all of the files of interest and compare the timestamps to determine if something has changed.

Obviously the previous steps require knowledge of the "last seen" state, and so your application will need to keep track of this in some form of database/data structure. I'd suggest tracking the following:

+------------------+---------------------------------------------------------------------------+
|     Property     |                                   Why?                                    |
+------------------+---------------------------------------------------------------------------+
| Local Path       | You'll need this so that you can map a local file to its service identity |
| Remote Path      | You'll need this if you plan to address the remote file by path              |
| Remote Id        | You'll need this if you plan to address the remote file by unique id         |
| Hash             | The hash representing the current state of the file                       |
| Local Timestamp  | Needed to detect local changes                                            |
| Remote Timestamp | Needed for conflict resolution                                            |
| Remote ETag      | Needed to detect remote changes                                           |
+------------------+---------------------------------------------------------------------------+

Additionally, if using the delta approach you'll need to store the token value from the delta response. This is item independent, so would need to be stored in some global field.

Conflict Resolution
If changes were detected on both sides your app will need to go through a conflict resolution process. An app that lacks an understanding of the files being synced would need to either prompt the user for manual conflict resolution, or do something like fork the file so there are now two copies. However, apps that are dealing with custom file formats should have enough knowledge to effectively merge the files without any form of user interaction. What that entails is obviously completely dependent on the file being synced.

Apply Changes
The final step is to push the merged state to wherever is required (e.g. if the change was local then push remote, if the change was remote then push local, otherwise if the change was in both places push both places). It's important to make sure this step occurs in such a way as to avoid replacing content that was written after the "Change Detection" step has taken place. Locally you'd probably accomplish this by locking the file during the process, however you cannot do that with the remote file. Instead you'll want to use the etag value to make sure the service only accepts the request if the state is still what you expect:

await this.userDrive.Drive.Special.AppRoot.ItemWithPath(remotePath).Content.Request(new Option[] { new HeaderOption("If-Match", "etag") }).PutAsync(newContentStream);
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!