2016-08-04 23:35:58 +02:00
|
|
|
import core.stdc.stdlib: EXIT_SUCCESS, EXIT_FAILURE;
|
2015-09-20 21:21:51 +02:00
|
|
|
import core.memory, core.time, core.thread;
|
2016-08-04 23:35:58 +02:00
|
|
|
import std.getopt, std.file, std.path, std.process;
|
2015-11-29 21:12:44 +01:00
|
|
|
import config, itemdb, monitor, onedrive, sync, util;
|
2016-08-04 23:35:58 +02:00
|
|
|
static import log;
|
2015-09-01 20:45:34 +02:00
|
|
|
|
2016-08-04 23:35:58 +02:00
|
|
|
int main(string[] args)
|
2015-09-01 20:45:34 +02:00
|
|
|
{
|
2016-08-04 23:35:58 +02:00
|
|
|
// configuration directory
|
|
|
|
string configDirName = expandTilde(environment.get("XDG_CONFIG_HOME", "~/.config")) ~ "/onedrive";
|
|
|
|
// enable monitor mode
|
|
|
|
bool monitor;
|
|
|
|
// force a full resync
|
|
|
|
bool resync;
|
2016-08-05 00:12:58 +02:00
|
|
|
// remove the current user and sync state
|
|
|
|
bool logout;
|
2016-08-04 23:35:58 +02:00
|
|
|
// enable verbose logging
|
|
|
|
bool verbose;
|
2015-10-18 10:12:10 +02:00
|
|
|
|
2015-09-14 19:21:06 +02:00
|
|
|
try {
|
|
|
|
auto opt = getopt(
|
|
|
|
args,
|
2016-08-04 23:35:58 +02:00
|
|
|
std.getopt.config.bundling,
|
2015-09-14 19:21:06 +02:00
|
|
|
"monitor|m", "Keep monitoring for local and remote changes.", &monitor,
|
2015-09-22 11:52:57 +02:00
|
|
|
"resync", "Forget the last saved state, perform a full sync.", &resync,
|
2016-08-05 00:12:58 +02:00
|
|
|
"logout", "Logout the current user.", &logout,
|
|
|
|
"confdir", "Set the directory to use to store the configuration files.", &configDirName,
|
2016-08-04 23:35:58 +02:00
|
|
|
"verbose|v", "Print more details, useful for debugging.", &log.verbose
|
2015-09-14 19:21:06 +02:00
|
|
|
);
|
|
|
|
if (opt.helpWanted) {
|
2015-09-22 11:20:54 +02:00
|
|
|
defaultGetoptPrinter(
|
|
|
|
"Usage: onedrive [OPTION]...\n\n" ~
|
|
|
|
"no option Sync and exit.",
|
|
|
|
opt.options
|
|
|
|
);
|
2016-08-04 23:35:58 +02:00
|
|
|
return EXIT_SUCCESS;
|
2015-09-14 19:21:06 +02:00
|
|
|
}
|
|
|
|
} catch (GetOptException e) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.log(e.msg);
|
|
|
|
log.log("Try 'onedrive -h' for more information.");
|
|
|
|
return EXIT_FAILURE;
|
2015-09-14 19:21:06 +02:00
|
|
|
}
|
|
|
|
|
2016-08-04 23:35:58 +02:00
|
|
|
log.vlog("Loading config ...");
|
2016-08-05 00:12:58 +02:00
|
|
|
configDirName = expandTilde(configDirName);
|
2015-09-22 15:26:45 +02:00
|
|
|
if (!exists(configDirName)) mkdir(configDirName);
|
2016-08-04 23:35:58 +02:00
|
|
|
auto cfg = new config.Config(configDirName);
|
|
|
|
cfg.init();
|
2016-08-05 00:12:58 +02:00
|
|
|
if (resync || logout) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.log("Deleting the saved status ...");
|
2016-08-05 00:12:58 +02:00
|
|
|
safeRemove(cfg.databaseFilePath);
|
|
|
|
safeRemove(cfg.statusTokenFilePath);
|
|
|
|
safeRemove(cfg.uploadStateFilePath);
|
|
|
|
if (logout) {
|
|
|
|
safeRemove(cfg.refreshTokenFilePath);
|
|
|
|
}
|
2015-09-14 19:21:06 +02:00
|
|
|
}
|
|
|
|
|
2016-08-04 23:35:58 +02:00
|
|
|
log.vlog("Initializing the OneDrive API ...");
|
2015-11-29 21:12:44 +01:00
|
|
|
bool online = testNetwork();
|
|
|
|
if (!online && !monitor) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.log("No network connection");
|
|
|
|
return EXIT_FAILURE;
|
2015-11-29 21:12:44 +01:00
|
|
|
}
|
2016-08-04 23:35:58 +02:00
|
|
|
auto onedrive = new OneDriveApi(cfg);
|
|
|
|
if (!onedrive.init()) {
|
|
|
|
log.log("Could not initialize the OneDrive API");
|
|
|
|
// workaround for segfault in std.net.curl.Curl.shutdown() on exit
|
|
|
|
onedrive.http.shutdown();
|
|
|
|
return EXIT_FAILURE;
|
2015-09-01 20:45:34 +02:00
|
|
|
}
|
|
|
|
|
2016-08-04 23:35:58 +02:00
|
|
|
log.vlog("Opening the item database ...");
|
|
|
|
auto itemdb = new ItemDatabase(cfg.databaseFilePath);
|
2015-09-16 10:29:20 +02:00
|
|
|
|
2016-08-04 23:35:58 +02:00
|
|
|
string syncDir = expandTilde(cfg.getValue("sync_dir"));
|
|
|
|
log.vlog("All operations will be performed in: ", syncDir);
|
2016-06-28 14:21:48 +02:00
|
|
|
if (!exists(syncDir)) mkdir(syncDir);
|
2015-09-27 18:47:41 +02:00
|
|
|
chdir(syncDir);
|
|
|
|
|
2016-08-04 23:35:58 +02:00
|
|
|
log.vlog("Initializing the Synchronization Engine ...");
|
|
|
|
auto sync = new SyncEngine(cfg, onedrive, itemdb);
|
|
|
|
sync.init();
|
2015-11-29 21:12:44 +01:00
|
|
|
if (online) performSync(sync);
|
2015-09-01 20:45:34 +02:00
|
|
|
|
2015-09-14 19:21:06 +02:00
|
|
|
if (monitor) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.vlog("Initializing monitor ...");
|
2015-09-14 19:21:06 +02:00
|
|
|
Monitor m;
|
|
|
|
m.onDirCreated = delegate(string path) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.vlog("[M] Directory created: ", path);
|
2015-09-20 21:21:51 +02:00
|
|
|
try {
|
|
|
|
sync.scanForDifferences(path);
|
|
|
|
} catch(SyncException e) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.log(e.msg);
|
2015-09-20 21:21:51 +02:00
|
|
|
}
|
2015-09-14 19:21:06 +02:00
|
|
|
};
|
|
|
|
m.onFileChanged = delegate(string path) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.vlog("[M] File changed: ", path);
|
2015-09-17 16:28:24 +02:00
|
|
|
try {
|
2015-09-18 21:42:27 +02:00
|
|
|
sync.scanForDifferences(path);
|
2015-09-17 16:28:24 +02:00
|
|
|
} catch(SyncException e) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.log(e.msg);
|
2015-09-17 16:28:24 +02:00
|
|
|
}
|
2015-09-14 19:21:06 +02:00
|
|
|
};
|
|
|
|
m.onDelete = delegate(string path) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.vlog("[M] Item deleted: ", path);
|
2015-09-20 21:21:51 +02:00
|
|
|
try {
|
|
|
|
sync.deleteByPath(path);
|
|
|
|
} catch(SyncException e) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.log(e.msg);
|
2015-09-20 21:21:51 +02:00
|
|
|
}
|
2015-09-14 19:21:06 +02:00
|
|
|
};
|
|
|
|
m.onMove = delegate(string from, string to) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.vlog("[M] Item moved: ", from, " -> ", to);
|
2015-09-20 21:21:51 +02:00
|
|
|
try {
|
|
|
|
sync.uploadMoveItem(from, to);
|
|
|
|
} catch(SyncException e) {
|
2016-08-04 23:35:58 +02:00
|
|
|
log.log(e.msg);
|
2015-09-20 21:21:51 +02:00
|
|
|
}
|
2015-09-14 19:21:06 +02:00
|
|
|
};
|
2015-09-17 17:34:58 +02:00
|
|
|
m.init(cfg, verbose);
|
2015-09-17 00:16:23 +02:00
|
|
|
// monitor loop
|
|
|
|
immutable auto checkInterval = dur!"seconds"(45);
|
|
|
|
auto lastCheckTime = MonoTime.currTime();
|
|
|
|
while (true) {
|
2015-11-29 21:12:44 +01:00
|
|
|
m.update(online);
|
2015-09-17 00:16:23 +02:00
|
|
|
auto currTime = MonoTime.currTime();
|
|
|
|
if (currTime - lastCheckTime > checkInterval) {
|
|
|
|
lastCheckTime = currTime;
|
2015-11-29 21:12:44 +01:00
|
|
|
online = testNetwork();
|
|
|
|
if (online) {
|
|
|
|
performSync(sync);
|
|
|
|
// discard all events that may have been generated by the sync
|
|
|
|
m.update(false);
|
|
|
|
}
|
2015-09-20 14:49:44 +02:00
|
|
|
GC.collect();
|
|
|
|
} else {
|
|
|
|
Thread.sleep(dur!"msecs"(100));
|
2015-09-17 00:16:23 +02:00
|
|
|
}
|
|
|
|
}
|
2015-09-14 19:21:06 +02:00
|
|
|
}
|
2016-02-24 17:07:59 +01:00
|
|
|
|
|
|
|
// workaround for segfault in std.net.curl.Curl.shutdown() on exit
|
|
|
|
onedrive.http.shutdown();
|
2016-08-04 23:35:58 +02:00
|
|
|
return EXIT_SUCCESS;
|
2015-09-01 20:45:34 +02:00
|
|
|
}
|
2015-09-20 21:21:51 +02:00
|
|
|
|
|
|
|
// try to synchronize the folder three times
|
|
|
|
void performSync(SyncEngine sync)
|
|
|
|
{
|
|
|
|
int count;
|
|
|
|
do {
|
|
|
|
try {
|
|
|
|
sync.applyDifferences();
|
|
|
|
sync.scanForDifferences(".");
|
|
|
|
count = -1;
|
|
|
|
} catch (SyncException e) {
|
|
|
|
if (++count == 3) throw e;
|
2016-08-04 23:35:58 +02:00
|
|
|
else log.log(e.msg);
|
2015-09-20 21:21:51 +02:00
|
|
|
}
|
|
|
|
} while (count != -1);
|
|
|
|
}
|