implement the recommended way to enumerate changes

This commit is contained in:
skilion 2017-05-28 20:54:57 +02:00
parent 3d8daa086d
commit 691862b18f
4 changed files with 23 additions and 28 deletions

View file

@ -5,7 +5,7 @@ static import log;
final class Config final class Config
{ {
public string refreshTokenFilePath; public string refreshTokenFilePath;
public string statusTokenFilePath; public string deltaLinkFilePath;
public string databaseFilePath; public string databaseFilePath;
public string uploadStateFilePath; public string uploadStateFilePath;
public string syncListFilePath; public string syncListFilePath;
@ -17,7 +17,7 @@ final class Config
this(string configDirName) this(string configDirName)
{ {
refreshTokenFilePath = configDirName ~ "/refresh_token"; refreshTokenFilePath = configDirName ~ "/refresh_token";
statusTokenFilePath = configDirName ~ "/status_token"; deltaLinkFilePath = configDirName ~ "/delta_link";
databaseFilePath = configDirName ~ "/items.sqlite3"; databaseFilePath = configDirName ~ "/items.sqlite3";
uploadStateFilePath = configDirName ~ "/resume_upload"; uploadStateFilePath = configDirName ~ "/resume_upload";
userConfigFilePath = configDirName ~ "/config"; userConfigFilePath = configDirName ~ "/config";

View file

@ -60,7 +60,7 @@ int main(string[] args)
if (resync || logout) { if (resync || logout) {
log.log("Deleting the saved status ..."); log.log("Deleting the saved status ...");
safeRemove(cfg.databaseFilePath); safeRemove(cfg.databaseFilePath);
safeRemove(cfg.statusTokenFilePath); safeRemove(cfg.deltaLinkFilePath);
safeRemove(cfg.uploadStateFilePath); safeRemove(cfg.uploadStateFilePath);
if (logout) { if (logout) {
safeRemove(cfg.refreshTokenFilePath); safeRemove(cfg.refreshTokenFilePath);

View file

@ -104,24 +104,24 @@ final class OneDriveApi
} }
// https://dev.onedrive.com/items/view_delta.htm // https://dev.onedrive.com/items/view_delta.htm
JSONValue viewChangesById(const(char)[] id, const(char)[] statusToken) JSONValue viewChangesById(const(char)[] id, const(char)[] deltaLink)
{ {
checkAccessTokenExpired(); checkAccessTokenExpired();
if (deltaLink) return get(deltaLink);
const(char)[] url = itemByIdUrl ~ id ~ "/delta"; const(char)[] url = itemByIdUrl ~ id ~ "/delta";
url ~= "?select=id,name,eTag,cTag,deleted,file,folder,root,fileSystemInfo,remoteItem,parentReference"; url ~= "?select=id,name,eTag,cTag,deleted,file,folder,root,fileSystemInfo,remoteItem,parentReference";
if (statusToken) url ~= "&token=" ~ statusToken;
return get(url); return get(url);
} }
// https://dev.onedrive.com/items/view_delta.htm // https://dev.onedrive.com/items/view_delta.htm
JSONValue viewChangesByPath(const(char)[] path, const(char)[] statusToken) JSONValue viewChangesByPath(const(char)[] path, const(char)[] deltaLink)
{ {
checkAccessTokenExpired(); checkAccessTokenExpired();
if (deltaLink) return get(deltaLink);
string url = itemByPathUrl ~ encodeComponent(path) ~ ":/delta"; string url = itemByPathUrl ~ encodeComponent(path) ~ ":/delta";
// HACK // HACK
if (path == ".") url = driveUrl ~ "/root/delta"; if (path == ".") url = driveUrl ~ "/root/delta";
url ~= "?select=id,name,eTag,cTag,deleted,file,folder,root,fileSystemInfo,remoteItem,parentReference"; url ~= "?select=id,name,eTag,cTag,deleted,file,folder,root,fileSystemInfo,remoteItem,parentReference";
if (statusToken) url ~= "&token=" ~ statusToken;
return get(url); return get(url);
} }

View file

@ -60,8 +60,6 @@ final class SyncEngine
private ItemDatabase itemdb; private ItemDatabase itemdb;
private UploadSession session; private UploadSession session;
private SelectiveSync selectiveSync; private SelectiveSync selectiveSync;
// token representing the last status correctly synced
private string statusToken;
// list of items to skip while applying the changes // list of items to skip while applying the changes
private string[] skippedItems; private string[] skippedItems;
// list of items to delete after the changes has been downloaded // list of items to delete after the changes has been downloaded
@ -79,12 +77,6 @@ final class SyncEngine
void init() void init()
{ {
// restore the previous status token
try {
statusToken = readText(cfg.statusTokenFilePath);
} catch (FileException e) {
// swallow exception
}
// check if there is an interrupted upload session // check if there is an interrupted upload session
if (session.restore()) { if (session.restore()) {
log.log("Continuing the upload session ..."); log.log("Continuing the upload session ...");
@ -96,33 +88,36 @@ final class SyncEngine
void applyDifferences() void applyDifferences()
{ {
log.vlog("Applying differences ..."); log.vlog("Applying differences ...");
// restore the last known state
string deltaLink;
try {
deltaLink = readText(cfg.deltaLinkFilePath);
} catch (FileException e) {
// swallow exception
}
try { try {
JSONValue changes; JSONValue changes;
do { do {
// get changes from the server // get changes from the server
try { try {
changes = onedrive.viewChangesByPath(".", statusToken); changes = onedrive.viewChangesByPath(".", deltaLink);
} catch (OneDriveException e) { } catch (OneDriveException e) {
if (e.httpStatusCode == 410) { if (e.httpStatusCode == 410) {
log.log("Status token expired, resyncing"); log.log("Delta link expired, resyncing");
statusToken = null; deltaLink = null;
continue; continue;
} } else {
else {
throw e; throw e;
} }
} }
foreach (item; changes["value"].array) { foreach (item; changes["value"].array) {
applyDifference(item); applyDifference(item);
} }
// hack to reuse old code if ("@odata.nextLink" in changes) deltaLink = changes["@odata.nextLink"].str;
string url; if ("@odata.deltaLink" in changes) deltaLink = changes["@odata.deltaLink"].str;
if ("@odata.nextLink" in changes) url = changes["@odata.nextLink"].str; std.file.write(cfg.deltaLinkFilePath, deltaLink);
if ("@odata.deltaLink" in changes) url = changes["@odata.deltaLink"].str;
auto c = matchFirst(url, r"(?:token=)([\w\d]+)");
c.popFront(); // skip the whole match
statusToken = c.front;
std.file.write(cfg.statusTokenFilePath, statusToken);
} while ("@odata.nextLink" in changes); } while ("@odata.nextLink" in changes);
} catch (ErrnoException e) { } catch (ErrnoException e) {
throw new SyncException(e.msg, e); throw new SyncException(e.msg, e);