joplin/ReactNativeClient/lib/registry.js

177 lines
5.7 KiB
JavaScript
Raw Normal View History

2018-03-09 17:49:35 +00:00
const { Logger } = require("lib/logger.js");
const Setting = require("lib/models/Setting.js");
const { shim } = require("lib/shim.js");
const SyncTargetRegistry = require("lib/SyncTargetRegistry.js");
const { _ } = require("lib/locale.js");
2017-07-06 19:48:17 +00:00
const reg = {};
reg.syncTargets_ = {};
2017-07-31 18:32:51 +00:00
2017-07-06 19:48:17 +00:00
reg.logger = () => {
2017-07-14 23:12:32 +00:00
if (!reg.logger_) {
2017-08-22 17:57:35 +00:00
//console.warn('Calling logger before it is initialized');
2017-07-14 23:12:32 +00:00
return new Logger();
}
2017-07-06 19:48:17 +00:00
return reg.logger_;
2018-03-09 17:49:35 +00:00
};
2017-07-06 19:48:17 +00:00
2018-03-09 17:49:35 +00:00
reg.setLogger = l => {
reg.logger_ = l;
2018-03-09 17:49:35 +00:00
};
2018-03-09 17:49:35 +00:00
reg.setShowErrorMessageBoxHandler = v => {
reg.showErrorMessageBoxHandler_ = v;
2018-03-09 17:49:35 +00:00
};
2018-03-09 17:49:35 +00:00
reg.showErrorMessageBox = message => {
if (!reg.showErrorMessageBoxHandler_) return;
reg.showErrorMessageBoxHandler_(message);
2018-03-09 17:49:35 +00:00
};
reg.syncTarget = (syncTargetId = null) => {
2018-03-09 17:49:35 +00:00
if (syncTargetId === null) syncTargetId = Setting.value("sync.target");
if (reg.syncTargets_[syncTargetId]) return reg.syncTargets_[syncTargetId];
2017-07-06 19:48:17 +00:00
const SyncTargetClass = SyncTargetRegistry.classById(syncTargetId);
2018-03-09 17:49:35 +00:00
if (!reg.db()) throw new Error("Cannot initialize sync without a db");
2017-07-06 19:48:17 +00:00
const target = new SyncTargetClass(reg.db());
target.setLogger(reg.logger());
reg.syncTargets_[syncTargetId] = target;
return target;
2018-03-09 17:49:35 +00:00
};
2017-07-06 19:48:17 +00:00
reg.scheduleSync = async (delay = null, syncOptions = null) => {
if (delay === null) delay = 1000 * 10;
if (syncOptions === null) syncOptions = {};
2017-07-19 19:15:55 +00:00
let promiseResolve = null;
const promise = new Promise((resolve, reject) => {
promiseResolve = resolve;
});
2017-07-17 20:22:05 +00:00
if (reg.scheduleSyncId_) {
clearTimeout(reg.scheduleSyncId_);
reg.scheduleSyncId_ = null;
}
2017-07-16 21:17:22 +00:00
2018-03-09 17:49:35 +00:00
reg.logger().info("Scheduling sync operation...");
2017-07-16 21:17:22 +00:00
// if (Setting.value("env") === "dev" && delay !== 0) {
// reg.logger().info("Schedule sync DISABLED!!!");
// return;
// }
2017-11-03 18:51:13 +00:00
2017-07-24 20:36:49 +00:00
const timeoutCallback = async () => {
2017-07-16 21:17:22 +00:00
reg.scheduleSyncId_ = null;
2018-03-09 17:49:35 +00:00
reg.logger().info("Preparing scheduled sync");
2017-07-16 21:17:22 +00:00
2018-03-09 17:49:35 +00:00
const syncTargetId = Setting.value("sync.target");
if (!reg.syncTarget(syncTargetId).isAuthenticated()) {
2018-03-09 17:49:35 +00:00
reg.logger().info("Synchroniser is missing credentials - manual sync required to authenticate.");
promiseResolve();
2017-07-16 21:17:22 +00:00
return;
}
2017-07-24 19:47:01 +00:00
try {
const sync = await reg.syncTarget(syncTargetId).synchronizer();
2017-07-30 20:22:57 +00:00
2018-03-09 17:49:35 +00:00
const contextKey = "sync." + syncTargetId + ".context";
2017-08-19 20:56:28 +00:00
let context = Setting.value(contextKey);
try {
context = context ? JSON.parse(context) : {};
} catch (error) {
// Clearing the context is inefficient since it means all items are going to be re-downloaded
// however it won't result in duplicate items since the synchroniser is going to compare each
// item to the current state.
2018-03-09 17:49:35 +00:00
reg.logger().warn("Could not parse JSON sync context " + contextKey + ":", context);
reg.logger().info("Clearing context and starting from scratch");
context = null;
}
2017-07-30 20:22:57 +00:00
try {
2018-03-09 17:49:35 +00:00
reg.logger().info("Starting scheduled sync");
const options = Object.assign({}, syncOptions, { context: context });
const newContext = await sync.start(options);
2017-08-19 20:56:28 +00:00
Setting.setValue(contextKey, JSON.stringify(newContext));
2017-07-30 20:22:57 +00:00
} catch (error) {
2018-03-09 17:49:35 +00:00
if (error.code == "alreadyStarted") {
2017-07-30 20:22:57 +00:00
reg.logger().info(error.message);
} else {
promiseResolve();
2017-07-30 20:22:57 +00:00
throw error;
}
2017-07-24 19:47:01 +00:00
}
2017-07-30 20:22:57 +00:00
} catch (error) {
2018-03-09 17:49:35 +00:00
reg.logger().info("Could not run background sync:");
2017-07-30 20:22:57 +00:00
reg.logger().info(error);
// Special case to display OneDrive Business error. This is the full error that's received when trying to use a OneDrive Business account:
//
// {"error":"invalid_client","error_description":"AADSTS50011: The reply address 'http://localhost:1917' does not match the reply addresses configured for
// the application: 'cbabb902-d276-4ea4-aa88-062a5889d6dc'. More details: not specified\r\nTrace ID: 6e63dac6-8b37-47e2-bd1b-4768f8713400\r\nCorrelation
// ID: acfd6503-8d97-4349-ae2e-e7a19dd7b6bc\r\nTimestamp: 2017-12-01 13:35:55Z","error_codes":[50011],"timestamp":"2017-12-01 13:35:55Z","trace_id":
// "6e63dac6-8b37-47e2-bd1b-4768f8713400","correlation_id":"acfd6503-8d97-4349-ae2e-e7a19dd7b6bc"}: TOKEN: null Error: {"error":"invalid_client",
// "error_description":"AADSTS50011: The reply address 'http://localhost:1917' does not match the reply addresses configured for the application:
// 'cbabb902-d276-4ea4-aa88-062a5889d6dc'. More details: not specified\r\nTrace ID: 6e63dac6-8b37-47e2-bd1b-4768f8713400\r\nCorrelation ID
// acfd6503-8d97-4349-ae2e-e7a19dd7b6bc\r\nTimestamp: 2017-12-01 13:35:55Z","error_codes":[50011],"timestamp":"2017-12-01 13:35:55Z","trace_id":
// "6e63dac6-8b37-47e2-bd1b-4768f8713400","correlation_id":"acfd6503-8d97-4349-ae2e-e7a19dd7b6bc"}
if (error && error.message && error.message.indexOf('"invalid_client"') >= 0) {
2018-03-09 17:49:35 +00:00
reg.showErrorMessageBox(
_(
"Could not synchronize with OneDrive.\n\nThis error often happens when using OneDrive for Business, which unfortunately cannot be supported.\n\nPlease consider using a regular OneDrive account."
)
);
}
2017-07-24 19:47:01 +00:00
}
reg.setupRecurrentSync();
promiseResolve();
2017-07-24 20:36:49 +00:00
};
if (delay === 0) {
timeoutCallback();
} else {
reg.scheduleSyncId_ = setTimeout(timeoutCallback, delay);
}
return promise;
2018-03-09 17:49:35 +00:00
};
2017-07-16 21:17:22 +00:00
reg.setupRecurrentSync = () => {
if (reg.recurrentSyncId_) {
2017-10-18 22:13:53 +00:00
shim.clearInterval(reg.recurrentSyncId_);
reg.recurrentSyncId_ = null;
}
2018-03-09 17:49:35 +00:00
if (!Setting.value("sync.interval")) {
reg.logger().debug("Recurrent sync is disabled");
2017-08-20 14:29:18 +00:00
} else {
2018-03-09 17:49:35 +00:00
reg.logger().debug("Setting up recurrent sync with interval " + Setting.value("sync.interval"));
2018-03-09 17:49:35 +00:00
if (Setting.value("env") === "dev") {
reg.logger().info("Recurrent sync operation DISABLED!!!");
2018-02-21 19:58:28 +00:00
return;
}
2017-10-18 22:13:53 +00:00
reg.recurrentSyncId_ = shim.setInterval(() => {
2018-03-09 17:49:35 +00:00
reg.logger().info("Running background sync on timer...");
2017-08-20 14:29:18 +00:00
reg.scheduleSync(0);
2018-03-09 17:49:35 +00:00
}, 1000 * Setting.value("sync.interval"));
2017-08-20 14:29:18 +00:00
}
2018-03-09 17:49:35 +00:00
};
2018-03-09 17:49:35 +00:00
reg.setDb = v => {
2017-07-06 19:48:17 +00:00
reg.db_ = v;
2018-03-09 17:49:35 +00:00
};
2017-07-06 19:48:17 +00:00
reg.db = () => {
return reg.db_;
2018-03-09 17:49:35 +00:00
};
2017-07-06 19:48:17 +00:00
2018-03-09 17:49:35 +00:00
module.exports = { reg };