2015-09-17 00:16:23 +02:00
|
|
|
import core.time, core.thread;
|
2015-09-14 19:21:06 +02:00
|
|
|
import std.getopt, std.file, std.process, std.stdio;
|
2015-09-16 10:29:20 +02:00
|
|
|
import config, itemdb, monitor, onedrive, sync;
|
2015-09-01 20:45:34 +02:00
|
|
|
|
2015-09-14 19:21:06 +02:00
|
|
|
string ver = "1.0";
|
2015-09-01 20:45:34 +02:00
|
|
|
|
2015-09-14 19:21:06 +02:00
|
|
|
void main(string[] args)
|
2015-09-01 20:45:34 +02:00
|
|
|
{
|
2015-09-16 10:29:20 +02:00
|
|
|
bool monitor, resync, verbose;
|
2015-09-14 19:21:06 +02:00
|
|
|
try {
|
|
|
|
writeln("OneDrive Client for Linux v", ver);
|
|
|
|
auto opt = getopt(
|
|
|
|
args,
|
|
|
|
"monitor|m", "Keep monitoring for local and remote changes.", &monitor,
|
|
|
|
"resync", "Perform a full synchronization.", &resync,
|
|
|
|
"verbose|v", "Print more details, useful for debugging.", &verbose
|
|
|
|
);
|
|
|
|
if (opt.helpWanted) {
|
|
|
|
defaultGetoptPrinter("Available options:", opt.options);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
} catch (GetOptException e) {
|
|
|
|
writeln(e.msg);
|
|
|
|
writeln("Try 'onedrive -h' for more information.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
string homeDirName = environment["HOME"];
|
|
|
|
string configDirName = environment.get("XDG_CONFIG_HOME", homeDirName ~ "/.config") ~ "/onedrive";
|
|
|
|
string configFilePath = configDirName ~ "/config";
|
|
|
|
string refreshTokenFilePath = configDirName ~ "/refresh_token";
|
|
|
|
string statusTokenFilePath = configDirName ~ "/status_token";
|
2015-09-16 10:29:20 +02:00
|
|
|
string databaseFilePath = configDirName ~ "/items.db";
|
2015-09-14 19:21:06 +02:00
|
|
|
|
2015-09-16 10:29:20 +02:00
|
|
|
if (resync) {
|
|
|
|
if (verbose) writeln("Deleting the saved status ...");
|
2015-09-14 19:21:06 +02:00
|
|
|
if (exists(databaseFilePath)) remove(databaseFilePath);
|
|
|
|
if (exists(statusTokenFilePath)) remove(statusTokenFilePath);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (verbose) writeln("Loading config ...");
|
|
|
|
auto cfg = config.Config(configFilePath);
|
|
|
|
cfg.load();
|
2015-09-01 20:45:34 +02:00
|
|
|
|
2015-09-14 19:21:06 +02:00
|
|
|
if (verbose) writeln("Initializing the OneDrive API ...");
|
|
|
|
auto onedrive = new OneDriveApi(cfg, verbose);
|
|
|
|
onedrive.onRefreshToken = (string refreshToken) {
|
|
|
|
std.file.write(refreshTokenFilePath, refreshToken);
|
|
|
|
};
|
2015-09-01 20:45:34 +02:00
|
|
|
try {
|
2015-09-14 19:21:06 +02:00
|
|
|
string refreshToken = readText(refreshTokenFilePath);
|
2015-09-01 20:45:34 +02:00
|
|
|
onedrive.setRefreshToken(refreshToken);
|
|
|
|
} catch (FileException e) {
|
|
|
|
onedrive.authorize();
|
|
|
|
}
|
2015-09-14 19:21:06 +02:00
|
|
|
// TODO check if the token is valid
|
2015-09-01 20:45:34 +02:00
|
|
|
|
2015-09-16 10:29:20 +02:00
|
|
|
if (verbose) writeln("Opening the item database ...");
|
|
|
|
auto itemdb = new ItemDatabase(databaseFilePath);
|
|
|
|
|
2015-09-14 19:21:06 +02:00
|
|
|
if (verbose) writeln("Initializing the Synchronization Engine ...");
|
2015-09-16 10:29:20 +02:00
|
|
|
auto sync = new SyncEngine(cfg, onedrive, itemdb, verbose);
|
|
|
|
sync.onStatusToken = (string statusToken) {
|
|
|
|
std.file.write(statusTokenFilePath, statusToken);
|
|
|
|
};
|
|
|
|
try {
|
|
|
|
string statusToken = readText(statusTokenFilePath);
|
|
|
|
sync.setStatusToken(statusToken);
|
|
|
|
} catch (FileException e) {
|
|
|
|
// swallow exception
|
|
|
|
}
|
|
|
|
|
|
|
|
string syncDir = cfg.get("sync_dir");
|
|
|
|
chdir(syncDir);
|
2015-09-01 20:45:34 +02:00
|
|
|
sync.applyDifferences();
|
2015-09-18 21:42:27 +02:00
|
|
|
sync.scanForDifferences(".");
|
2015-09-01 20:45:34 +02:00
|
|
|
|
2015-09-14 19:21:06 +02:00
|
|
|
if (monitor) {
|
2015-09-17 00:16:23 +02:00
|
|
|
if (verbose) writeln("Initializing monitor ...");
|
2015-09-14 19:21:06 +02:00
|
|
|
Monitor m;
|
|
|
|
m.onDirCreated = delegate(string path) {
|
|
|
|
if (verbose) writeln("[M] Directory created: ", path);
|
2015-09-18 21:42:27 +02:00
|
|
|
sync.scanForDifferences(path);
|
2015-09-14 19:21:06 +02:00
|
|
|
};
|
|
|
|
m.onFileChanged = delegate(string path) {
|
|
|
|
if (verbose) writeln("[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) {
|
|
|
|
writeln(e.msg);
|
|
|
|
}
|
2015-09-14 19:21:06 +02:00
|
|
|
};
|
|
|
|
m.onDelete = delegate(string path) {
|
|
|
|
if (verbose) writeln("[M] Item deleted: ", path);
|
|
|
|
sync.deleteByPath(path);
|
|
|
|
};
|
|
|
|
m.onMove = delegate(string from, string to) {
|
|
|
|
if (verbose) writeln("[M] Item moved: ", from, " -> ", to);
|
2015-09-17 00:16:23 +02:00
|
|
|
sync.uploadMoveItem(from, to);
|
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) {
|
|
|
|
m.update();
|
|
|
|
auto currTime = MonoTime.currTime();
|
|
|
|
if (currTime - lastCheckTime > checkInterval) {
|
|
|
|
lastCheckTime = currTime;
|
|
|
|
m.shutdown();
|
|
|
|
sync.applyDifferences();
|
2015-09-18 21:42:27 +02:00
|
|
|
sync.scanForDifferences(".");
|
2015-09-17 17:34:58 +02:00
|
|
|
m.init(cfg, verbose);
|
2015-09-17 00:16:23 +02:00
|
|
|
}
|
|
|
|
Thread.sleep(dur!"msecs"(100));
|
|
|
|
}
|
2015-09-14 19:21:06 +02:00
|
|
|
}
|
2015-09-01 20:45:34 +02:00
|
|
|
}
|