From e7460ca3a92ceda2e28f97f8d8171efbc94c40da Mon Sep 17 00:00:00 2001 From: azivner Date: Sun, 22 Jul 2018 22:21:16 +0200 Subject: [PATCH] #98, sync is now configured in the options --- config-sample.ini | 6 ---- db/migrations/0101__add_sync_options.sql | 8 +++++ package.json | 1 + src/public/javascripts/dialogs/options.js | 41 ++++++++++++++++++----- src/routes/api/options.js | 26 ++++++++++++-- src/routes/routes.js | 1 + src/services/app_info.js | 2 +- src/services/messaging.js | 2 +- src/services/migration.js | 2 +- src/services/options_init.js | 4 +++ src/services/sql_init.js | 4 +-- src/services/sync.js | 29 ++++++---------- src/services/sync_setup.js | 10 +++--- src/services/sync_table.js | 2 +- src/views/index.ejs | 23 +++++++++++++ 15 files changed, 115 insertions(+), 46 deletions(-) create mode 100644 db/migrations/0101__add_sync_options.sql diff --git a/config-sample.ini b/config-sample.ini index 634a704da..c7f5f2df2 100644 --- a/config-sample.ini +++ b/config-sample.ini @@ -9,9 +9,3 @@ https=false # path to certificate (run "bash generate-cert.sh" to generate self-signed certificate). Relevant only if https=true certPath= keyPath= - -[Sync] -syncServerHost= -syncServerTimeout=10000 -syncProxy= -syncServerCertificate= \ No newline at end of file diff --git a/db/migrations/0101__add_sync_options.sql b/db/migrations/0101__add_sync_options.sql new file mode 100644 index 000000000..62dc9a5e2 --- /dev/null +++ b/db/migrations/0101__add_sync_options.sql @@ -0,0 +1,8 @@ +INSERT INTO options (name, value, dateCreated, dateModified, isSynced) +VALUES ('syncServerHost', '', '2018-06-01T03:35:55.041Z', '2018-06-01T03:35:55.041Z', 0); + +INSERT INTO options (name, value, dateCreated, dateModified, isSynced) +VALUES ('syncServerTimeout', '5000', '2018-06-01T03:35:55.041Z', '2018-06-01T03:35:55.041Z', 0); + +INSERT INTO options (name, value, dateCreated, dateModified, isSynced) +VALUES ('syncProxy', '', '2018-06-01T03:35:55.041Z', '2018-06-01T03:35:55.041Z', 0); \ No newline at end of file diff --git a/package.json b/package.json index 1e8640463..1aa92c01d 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "simple-node-logger": "^0.93.37", "sqlite": "^2.9.2", "tar-stream": "^1.6.1", + "tmp-promise": "^1.0.5", "unescape": "^1.0.1", "ws": "^5.2.1", "xml2js": "^0.4.19" diff --git a/src/public/javascripts/dialogs/options.js b/src/public/javascripts/dialogs/options.js index 7a1020e81..e106cbf0e 100644 --- a/src/public/javascripts/dialogs/options.js +++ b/src/public/javascripts/dialogs/options.js @@ -34,8 +34,8 @@ async function showDialog() { } } -async function saveOptions(optionName, optionValue) { - await server.put('options/' + encodeURIComponent(optionName) + '/' + encodeURIComponent(optionValue)); +async function saveOptions(options) { + await server.put('options', options); infoService.showMessage("Options change have been saved."); } @@ -129,16 +129,15 @@ addTabHandler((function() { addTabHandler((function() { const $form = $("#protected-session-timeout-form"); const $protectedSessionTimeout = $("#protected-session-timeout-in-seconds"); - const optionName = 'protectedSessionTimeout'; function optionsLoaded(options) { - $protectedSessionTimeout.val(options[optionName]); + $protectedSessionTimeout.val(options['protectedSessionTimeout']); } $form.submit(() => { const protectedSessionTimeout = $protectedSessionTimeout.val(); - saveOptions(optionName, protectedSessionTimeout).then(() => { + saveOptions({ 'protectedSessionTimeout': protectedSessionTimeout }).then(() => { protectedSessionHolder.setProtectedSessionTimeout(protectedSessionTimeout); }); @@ -153,14 +152,13 @@ addTabHandler((function() { addTabHandler((function () { const $form = $("#note-revision-snapshot-time-interval-form"); const $timeInterval = $("#note-revision-snapshot-time-interval-in-seconds"); - const optionName = 'noteRevisionSnapshotTimeInterval'; function optionsLoaded(options) { - $timeInterval.val(options[optionName]); + $timeInterval.val(options['noteRevisionSnapshotTimeInterval']); } $form.submit(() => { - saveOptions(optionName, $timeInterval.val()); + saveOptions({ 'noteRevisionSnapshotTimeInterval': $timeInterval.val() }); return false; }); @@ -189,6 +187,33 @@ addTabHandler((async function () { return {}; })()); +addTabHandler((function() { + const $form = $("#sync-setup-form"); + const $syncServerHost = $("#sync-server-host"); + const $syncServerTimeout = $("#sync-server-timeout"); + const $syncProxy = $("#sync-proxy"); + + function optionsLoaded(options) { + $syncServerHost.val(options['syncServerHost']); + $syncServerTimeout.val(options['syncServerTimeout']); + $syncProxy.val(options['syncProxy']); + } + + $form.submit(() => { + saveOptions({ + 'syncServerHost': $syncServerHost.val(), + 'syncServerTimeout': $syncServerTimeout.val(), + 'syncProxy': $syncProxy.val() + }); + + return false; + }); + + return { + optionsLoaded + }; +})()); + addTabHandler((async function () { const $forceFullSyncButton = $("#force-full-sync-button"); const $fillSyncRowsButton = $("#fill-sync-rows-button"); diff --git a/src/routes/api/options.js b/src/routes/api/options.js index bde6d3e5d..9f1c1ad7e 100644 --- a/src/routes/api/options.js +++ b/src/routes/api/options.js @@ -5,7 +5,8 @@ const optionService = require('../../services/options'); const log = require('../../services/log'); // options allowed to be updated directly in options dialog -const ALLOWED_OPTIONS = ['protectedSessionTimeout', 'noteRevisionSnapshotTimeInterval', 'zoomFactor', 'theme']; +const ALLOWED_OPTIONS = ['protectedSessionTimeout', 'noteRevisionSnapshotTimeInterval', + 'zoomFactor', 'theme', 'syncServerHost', 'syncServerTimeout', 'syncProxy']; async function getOptions() { const options = await sql.getMap("SELECT name, value FROM options WHERE name IN (" @@ -17,16 +18,35 @@ async function getOptions() { async function updateOption(req) { const {name, value} = req.params; + if (!update(name, value)) { + return [400, "not allowed option to change"]; + } +} + +async function updateOptions(req) { + for (const optionName in req.body) { + if (!update(optionName, req.body[optionName])) { + // this should be improved + // it should return 400 instead of current 500, but at least it now rollbacks transaction + throw new Error(`${optionName} is not allowed to change`); + } + } +} + +async function update(name, value) { if (!ALLOWED_OPTIONS.includes(name)) { - return [400, "not allowed option to set"]; + return false; } log.info(`Updating option ${name} to ${value}`); await optionService.setOption(name, value); + + return true; } module.exports = { getOptions, - updateOption + updateOption, + updateOptions }; \ No newline at end of file diff --git a/src/routes/routes.js b/src/routes/routes.js index 8b184a442..fdc894aa8 100644 --- a/src/routes/routes.js +++ b/src/routes/routes.js @@ -144,6 +144,7 @@ function register(app) { apiRoute(GET, '/api/options', optionsApiRoute.getOptions); apiRoute(PUT, '/api/options/:name/:value', optionsApiRoute.updateOption); + apiRoute(PUT, '/api/options', optionsApiRoute.updateOptions); apiRoute(POST, '/api/password/change', passwordApiRoute.changePassword); diff --git a/src/services/app_info.js b/src/services/app_info.js index 681414e3f..ef78a4a78 100644 --- a/src/services/app_info.js +++ b/src/services/app_info.js @@ -3,7 +3,7 @@ const build = require('./build'); const packageJson = require('../../package'); -const APP_DB_VERSION = 100; +const APP_DB_VERSION = 101; const SYNC_VERSION = 1; module.exports = { diff --git a/src/services/messaging.js b/src/services/messaging.js index 839440f28..f24157e4d 100644 --- a/src/services/messaging.js +++ b/src/services/messaging.js @@ -73,7 +73,7 @@ async function sendPing(client, lastSentSyncId) { await sendMessage(client, { type: 'sync', data: syncData, - changesToPushCount: syncSetup.isSyncSetup ? changesToPushCount : 0 + changesToPushCount: await syncSetup.isSyncSetup() ? changesToPushCount : 0 }); } diff --git a/src/services/migration.js b/src/services/migration.js index 232fdaf8c..006a66dc8 100644 --- a/src/services/migration.js +++ b/src/services/migration.js @@ -85,7 +85,7 @@ async function migrate() { } } - if (sqlInit.isDbUpToDate()) { + if (await sqlInit.isDbUpToDate()) { await sqlInit.initDbConnection(); } diff --git a/src/services/options_init.js b/src/services/options_init.js index 6ebc9fb88..72232080a 100644 --- a/src/services/options_init.js +++ b/src/services/options_init.js @@ -34,6 +34,10 @@ async function initOptions(startNotePath, username, password) { await optionService.createOption('encryptedDataKeyIv', ''); await passwordEncryptionService.setDataKey(password, utils.randomSecureToken(16)); + + await optionService.createOption('syncServerHost', '', false); + await optionService.createOption('syncServerTimeout', 5000, false); + await optionService.createOption('syncProxy', '', false); } module.exports = { diff --git a/src/services/sql_init.js b/src/services/sql_init.js index d1efff2b9..d16cf7cce 100644 --- a/src/services/sql_init.js +++ b/src/services/sql_init.js @@ -31,8 +31,8 @@ async function initDbConnection() { await sql.execute("PRAGMA foreign_keys = ON"); - if (isDbInitialized()) { - log.info("DB not found, please visit setup page to initialize Trilium."); + if (!await isDbInitialized()) { + log.info("DB not initialized, please visit setup page to initialize Trilium."); return; } diff --git a/src/services/sync.js b/src/services/sync.js index 8bc33e1ee..a0edd8349 100644 --- a/src/services/sync.js +++ b/src/services/sync.js @@ -17,7 +17,6 @@ const syncMutexService = require('./sync_mutex'); const cls = require('./cls'); let proxyToggle = true; -let syncServerCertificate = null; async function sync() { try { @@ -169,7 +168,7 @@ async function checkContentHash(syncContext) { } async function syncRequest(syncContext, method, uri, body) { - const fullUri = syncSetup.SYNC_SERVER + uri; + const fullUri = await syncSetup.getSyncServer() + uri; try { const options = { @@ -178,15 +177,13 @@ async function syncRequest(syncContext, method, uri, body) { jar: syncContext.cookieJar, json: true, body: body, - timeout: syncSetup.SYNC_TIMEOUT + timeout: await syncSetup.getSyncTimeout() }; - if (syncServerCertificate) { - options.ca = syncServerCertificate; - } + const syncProxy = await syncSetup.getSyncProxy(); - if (syncSetup.SYNC_PROXY && proxyToggle) { - options.proxy = syncSetup.SYNC_PROXY; + if (syncProxy && proxyToggle) { + options.proxy = syncProxy; } return await rp(options); @@ -270,18 +267,14 @@ async function setLastSyncedPush(lastSyncedPush) { await optionService.setOption('lastSyncedPush', lastSyncedPush); } -sqlInit.dbReady.then(() => { - if (syncSetup.isSyncSetup) { - log.info("Setting up sync to " + syncSetup.SYNC_SERVER + " with timeout " + syncSetup.SYNC_TIMEOUT); +sqlInit.dbReady.then(async () => { + if (await syncSetup.isSyncSetup()) { + log.info("Setting up sync to " + await syncSetup.getSyncServer() + " with timeout " + await syncSetup.getSyncTimeout()); - if (syncSetup.SYNC_PROXY) { - log.info("Sync proxy: " + syncSetup.SYNC_PROXY); - } + const syncProxy = await syncSetup.getSyncProxy(); - if (syncSetup.SYNC_CERT_PATH) { - log.info('Sync certificate: ' + syncSetup.SYNC_CERT_PATH); - - syncServerCertificate = fs.readFileSync(syncSetup.SYNC_CERT_PATH); + if (syncProxy) { + log.info("Sync proxy: " + syncProxy); } setInterval(cls.wrap(sync), 60000); diff --git a/src/services/sync_setup.js b/src/services/sync_setup.js index b51087ed1..a3b70bd16 100644 --- a/src/services/sync_setup.js +++ b/src/services/sync_setup.js @@ -1,11 +1,11 @@ "use strict"; const config = require('./config'); +const optionService = require('./options'); module.exports = { - SYNC_SERVER: config['Sync']['syncServerHost'], - isSyncSetup: !!config['Sync']['syncServerHost'], - SYNC_TIMEOUT: config['Sync']['syncServerTimeout'] || 5000, - SYNC_PROXY: config['Sync']['syncProxy'], - SYNC_CERT_PATH: config['Sync']['syncServerCertificate'] + getSyncServer: async () => await optionService.getOption('syncServerHost'), + isSyncSetup: async () => !!await optionService.getOption('syncServerHost'), + getSyncTimeout: async () => await optionService.getOption('syncServerTimeout'), + getSyncProxy: async () => await optionService.getOption('syncProxy') }; \ No newline at end of file diff --git a/src/services/sync_table.js b/src/services/sync_table.js index 056f85431..ee5636740 100644 --- a/src/services/sync_table.js +++ b/src/services/sync_table.js @@ -54,7 +54,7 @@ async function addEntitySync(entityName, entityId, sourceId) { sourceId: sourceId || cls.getSourceId() || sourceIdService.getCurrentSourceId() }); - if (!syncSetup.isSyncSetup) { + if (!await syncSetup.isSyncSetup()) { // this is because the "server" instances shouldn't have outstanding pushes // useful when you fork the DB for new "client" instance, it won't try to sync the whole DB await sql.execute("UPDATE options SET value = (SELECT MAX(id) FROM sync) WHERE name IN('lastSyncedPush', 'lastSyncedPull')"); diff --git a/src/views/index.ejs b/src/views/index.ejs index 5c255da55..f5a8e8f31 100644 --- a/src/views/index.ejs +++ b/src/views/index.ejs @@ -334,6 +334,7 @@
  • Change password
  • Protected session
  • Note revisions
  • +
  • Sync
  • Advanced
  • About Trilium
  • @@ -404,6 +405,28 @@ +
    +

    Sync

    + +
    +
    + + +
    + +
    + + +
    + +
    + + +
    + + +
    +

    Sync