mirror of
				https://github.com/TriliumNext/Notes.git
				synced 2025-11-04 15:11:31 +08:00 
			
		
		
		
	#98, sync is now configured in the options
This commit is contained in:
		
							parent
							
								
									073300bbcd
								
							
						
					
					
						commit
						e7460ca3a9
					
				@ -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=
 | 
			
		||||
							
								
								
									
										8
									
								
								db/migrations/0101__add_sync_options.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								db/migrations/0101__add_sync_options.sql
									
									
									
									
									
										Normal file
									
								
							@ -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);
 | 
			
		||||
@ -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"
 | 
			
		||||
 | 
			
		||||
@ -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");
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
};
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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 = {
 | 
			
		||||
 | 
			
		||||
@ -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
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -85,7 +85,7 @@ async function migrate() {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (sqlInit.isDbUpToDate()) {
 | 
			
		||||
    if (await sqlInit.isDbUpToDate()) {
 | 
			
		||||
        await sqlInit.initDbConnection();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -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 = {
 | 
			
		||||
 | 
			
		||||
@ -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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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);
 | 
			
		||||
 | 
			
		||||
@ -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')
 | 
			
		||||
};
 | 
			
		||||
@ -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')");
 | 
			
		||||
 | 
			
		||||
@ -334,6 +334,7 @@
 | 
			
		||||
          <li><a href="#change-password">Change password</a></li>
 | 
			
		||||
          <li><a href="#protected-session-timeout">Protected session</a></li>
 | 
			
		||||
          <li><a href="#note-revision-snapshot-time-interval">Note revisions</a></li>
 | 
			
		||||
          <li><a href="#sync-setup">Sync</a></li>
 | 
			
		||||
          <li><a href="#advanced">Advanced</a></li>
 | 
			
		||||
          <li><a href="#about">About Trilium</a></li>
 | 
			
		||||
        </ul>
 | 
			
		||||
@ -404,6 +405,28 @@
 | 
			
		||||
            <button class="btn btn-sm">Save</button>
 | 
			
		||||
          </form>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div id="sync-setup">
 | 
			
		||||
          <h4 style="margin-top: 0px;">Sync</h4>
 | 
			
		||||
 | 
			
		||||
          <form id="sync-setup-form">
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
              <label for="sync-server-host">Sync server host</label>
 | 
			
		||||
              <input class="form-control" id="sync-server-host" placeholder="https://<host>:<port>">
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
              <label for="sync-server-timeout">Sync timeout (milliseconds)</label>
 | 
			
		||||
              <input class="form-control" id="sync-server-timeout" min="1" max="10000000" type="number">
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <div class="form-group">
 | 
			
		||||
              <label for="sync-proxy">Sync proxy server (optional)</label>
 | 
			
		||||
              <input class="form-control" id="sync-proxy" placeholder="https://<host>:<port>">
 | 
			
		||||
            </div>
 | 
			
		||||
 | 
			
		||||
            <button class="btn btn-sm">Save</button>
 | 
			
		||||
          </form>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div id="advanced">
 | 
			
		||||
          <h4 style="margin-top: 0px;">Sync</h4>
 | 
			
		||||
          <button id="force-full-sync-button" class="btn btn-sm">Force full sync</button>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user