You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-12-20 23:30:05 +02:00
Move sync target info handling to separate class
This commit is contained in:
@@ -1424,6 +1424,9 @@ packages/lib/services/synchronizer/LockHandler.js.map
|
||||
packages/lib/services/synchronizer/MigrationHandler.d.ts
|
||||
packages/lib/services/synchronizer/MigrationHandler.js
|
||||
packages/lib/services/synchronizer/MigrationHandler.js.map
|
||||
packages/lib/services/synchronizer/SyncTargetInfoHandler.d.ts
|
||||
packages/lib/services/synchronizer/SyncTargetInfoHandler.js
|
||||
packages/lib/services/synchronizer/SyncTargetInfoHandler.js.map
|
||||
packages/lib/services/synchronizer/Synchronizer.basics.test.d.ts
|
||||
packages/lib/services/synchronizer/Synchronizer.basics.test.js
|
||||
packages/lib/services/synchronizer/Synchronizer.basics.test.js.map
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1410,6 +1410,9 @@ packages/lib/services/synchronizer/LockHandler.js.map
|
||||
packages/lib/services/synchronizer/MigrationHandler.d.ts
|
||||
packages/lib/services/synchronizer/MigrationHandler.js
|
||||
packages/lib/services/synchronizer/MigrationHandler.js.map
|
||||
packages/lib/services/synchronizer/SyncTargetInfoHandler.d.ts
|
||||
packages/lib/services/synchronizer/SyncTargetInfoHandler.js
|
||||
packages/lib/services/synchronizer/SyncTargetInfoHandler.js.map
|
||||
packages/lib/services/synchronizer/Synchronizer.basics.test.d.ts
|
||||
packages/lib/services/synchronizer/Synchronizer.basics.test.js
|
||||
packages/lib/services/synchronizer/Synchronizer.basics.test.js.map
|
||||
|
||||
@@ -21,6 +21,7 @@ import ShareService from './services/share/ShareService';
|
||||
import TaskQueue from './TaskQueue';
|
||||
import ItemUploader from './services/synchronizer/ItemUploader';
|
||||
import { FileApi } from './file-api';
|
||||
import SyncTargetInfoHandler from './services/synchronizer/SyncTargetInfoHandler';
|
||||
const { sprintf } = require('sprintf-js');
|
||||
const { Dirnames } = require('./services/synchronizer/utils/types');
|
||||
|
||||
@@ -73,6 +74,7 @@ export default class Synchronizer {
|
||||
private clientId_: string;
|
||||
private lockHandler_: LockHandler;
|
||||
private migrationHandler_: MigrationHandler;
|
||||
private syncTargetInfoHandler_: SyncTargetInfoHandler;
|
||||
private encryptionService_: EncryptionService = null;
|
||||
private resourceService_: ResourceService = null;
|
||||
private syncTargetIsLocked_: boolean = false;
|
||||
@@ -125,18 +127,24 @@ export default class Synchronizer {
|
||||
return this.logger_;
|
||||
}
|
||||
|
||||
lockHandler() {
|
||||
public lockHandler() {
|
||||
if (this.lockHandler_) return this.lockHandler_;
|
||||
this.lockHandler_ = new LockHandler(this.api());
|
||||
return this.lockHandler_;
|
||||
}
|
||||
|
||||
migrationHandler() {
|
||||
private migrationHandler() {
|
||||
if (this.migrationHandler_) return this.migrationHandler_;
|
||||
this.migrationHandler_ = new MigrationHandler(this.api(), this.lockHandler(), this.appType_, this.clientId_);
|
||||
this.migrationHandler_ = new MigrationHandler(this.api(), this.syncTargetInfoHandler(), this.lockHandler(), this.appType_, this.clientId_);
|
||||
return this.migrationHandler_;
|
||||
}
|
||||
|
||||
public syncTargetInfoHandler() {
|
||||
if (this.syncTargetInfoHandler_) return this.syncTargetInfoHandler_;
|
||||
this.syncTargetInfoHandler_ = new SyncTargetInfoHandler(this.api());
|
||||
return this.syncTargetInfoHandler_;
|
||||
}
|
||||
|
||||
maxResourceSize() {
|
||||
if (this.maxResourceSize_ !== null) return this.maxResourceSize_;
|
||||
return this.appType_ === 'mobile' ? 100 * 1000 * 1000 : Infinity;
|
||||
@@ -415,7 +423,11 @@ export default class Synchronizer {
|
||||
this.api().setTempDirName(Dirnames.Temp);
|
||||
|
||||
try {
|
||||
const syncTargetInfo = await this.migrationHandler().checkCanSync();
|
||||
const syncTargetInfoService = new SyncTargetInfoHandler(this.api());
|
||||
|
||||
await this.migrationHandler().checkCanSync();
|
||||
|
||||
const syncTargetInfo = await syncTargetInfoService.info();
|
||||
|
||||
this.logger().info('Sync target info:', syncTargetInfo);
|
||||
|
||||
|
||||
@@ -16,50 +16,29 @@ const migrations = [
|
||||
import Setting from '../../models/Setting';
|
||||
const { sprintf } = require('sprintf-js');
|
||||
import JoplinError from '../../JoplinError';
|
||||
|
||||
interface SyncTargetInfo {
|
||||
version: number;
|
||||
}
|
||||
import SyncTargetInfoHandler from './SyncTargetInfoHandler';
|
||||
import { FileApi } from '../../file-api';
|
||||
|
||||
export default class MigrationHandler extends BaseService {
|
||||
|
||||
private api_: any = null;
|
||||
private api_: FileApi = null;
|
||||
private lockHandler_: LockHandler = null;
|
||||
private syncTargetInfoHandler_: SyncTargetInfoHandler = null;
|
||||
private clientType_: string;
|
||||
private clientId_: string;
|
||||
|
||||
constructor(api: any, lockHandler: LockHandler, clientType: string, clientId: string) {
|
||||
constructor(api: FileApi, syncTargetInfoHandler: SyncTargetInfoHandler, lockHandler: LockHandler, clientType: string, clientId: string) {
|
||||
super();
|
||||
this.api_ = api;
|
||||
this.syncTargetInfoHandler_ = syncTargetInfoHandler;
|
||||
this.lockHandler_ = lockHandler;
|
||||
this.clientType_ = clientType;
|
||||
this.clientId_ = clientId;
|
||||
}
|
||||
|
||||
public async fetchSyncTargetInfo(): Promise<SyncTargetInfo> {
|
||||
const syncTargetInfoText = await this.api_.get('info.json');
|
||||
|
||||
// Returns version 0 if the sync target is empty
|
||||
let output: SyncTargetInfo = { version: 0 };
|
||||
|
||||
if (syncTargetInfoText) {
|
||||
output = JSON.parse(syncTargetInfoText);
|
||||
if (!output.version) throw new Error('Missing "version" field in info.json');
|
||||
} else {
|
||||
const oldVersion = await this.api_.get('.sync/version.txt');
|
||||
if (oldVersion) output = { version: 1 };
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private serializeSyncTargetInfo(info: SyncTargetInfo) {
|
||||
return JSON.stringify(info);
|
||||
}
|
||||
|
||||
async checkCanSync(): Promise<SyncTargetInfo> {
|
||||
public async checkCanSync(): Promise<void> {
|
||||
const supportedSyncTargetVersion = Setting.value('syncVersion');
|
||||
const syncTargetInfo = await this.fetchSyncTargetInfo();
|
||||
const syncTargetInfo = await this.syncTargetInfoHandler_.info();
|
||||
|
||||
if (syncTargetInfo.version) {
|
||||
if (syncTargetInfo.version > supportedSyncTargetVersion) {
|
||||
@@ -68,13 +47,11 @@ export default class MigrationHandler extends BaseService {
|
||||
throw new JoplinError(sprintf('Sync version of the target (%d) is lower than the version supported by the client (%d). Please upgrade the sync target.', syncTargetInfo.version, supportedSyncTargetVersion), 'outdatedSyncTarget');
|
||||
}
|
||||
}
|
||||
|
||||
return syncTargetInfo;
|
||||
}
|
||||
|
||||
async upgrade(targetVersion: number = 0) {
|
||||
public async upgrade(targetVersion: number = 0) {
|
||||
const supportedSyncTargetVersion = Setting.value('syncVersion');
|
||||
const syncTargetInfo = await this.fetchSyncTargetInfo();
|
||||
const syncTargetInfo = await this.syncTargetInfoHandler_.info();
|
||||
|
||||
if (syncTargetInfo.version > supportedSyncTargetVersion) {
|
||||
throw new JoplinError(sprintf('Sync version of the target (%d) is greater than the version supported by the client (%d). Please upgrade your client.', syncTargetInfo.version, supportedSyncTargetVersion), 'outdatedClient');
|
||||
@@ -122,10 +99,10 @@ export default class MigrationHandler extends BaseService {
|
||||
await migration(this.api_);
|
||||
if (autoLockError) throw autoLockError;
|
||||
|
||||
await this.api_.put('info.json', this.serializeSyncTargetInfo({
|
||||
await this.syncTargetInfoHandler_.setInfo({
|
||||
...syncTargetInfo,
|
||||
version: newVersion,
|
||||
}));
|
||||
});
|
||||
|
||||
this.logger().info(`MigrationHandler: Done migrating from version ${fromVersion} to version ${newVersion}`);
|
||||
} catch (error) {
|
||||
|
||||
52
packages/lib/services/synchronizer/SyncTargetInfoHandler.ts
Normal file
52
packages/lib/services/synchronizer/SyncTargetInfoHandler.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { FileApi } from '../../file-api';
|
||||
|
||||
interface SyncTargetInfo {
|
||||
version: number;
|
||||
}
|
||||
|
||||
export default class SyncTargetInfoHandler {
|
||||
|
||||
private api_: FileApi = null;
|
||||
private info_: SyncTargetInfo = null;
|
||||
|
||||
public constructor(api: FileApi) {
|
||||
this.api_ = api;
|
||||
}
|
||||
|
||||
public async info(): Promise<SyncTargetInfo> {
|
||||
if (this.info_) return this.info_;
|
||||
this.info_ = await this.fetchSyncTargetInfo();
|
||||
return this.info_;
|
||||
}
|
||||
|
||||
private serializeSyncTargetInfo(info: SyncTargetInfo): string {
|
||||
return JSON.stringify(info);
|
||||
}
|
||||
|
||||
private unserializeSyncTargetInfo(info: string): SyncTargetInfo {
|
||||
return JSON.parse(info);
|
||||
}
|
||||
|
||||
public async setInfo(info: SyncTargetInfo): Promise<void> {
|
||||
this.info_ = info;
|
||||
await this.api_.put('info.json', this.serializeSyncTargetInfo(info));
|
||||
}
|
||||
|
||||
private async fetchSyncTargetInfo(): Promise<SyncTargetInfo> {
|
||||
const syncTargetInfoText = await this.api_.get('info.json');
|
||||
|
||||
// Returns version 0 if the sync target is empty
|
||||
let output: SyncTargetInfo = { version: 0 };
|
||||
|
||||
if (syncTargetInfoText) {
|
||||
output = this.unserializeSyncTargetInfo(syncTargetInfoText);
|
||||
if (!output.version) throw new Error('Missing "version" field in info.json');
|
||||
} else {
|
||||
const oldVersion = await this.api_.get('.sync/version.txt');
|
||||
if (oldVersion) output = { version: 1 };
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import MigrationHandler from '../MigrationHandler';
|
||||
const { useEffect, useState } = shim.react();
|
||||
import Setting from '../../../models/Setting';
|
||||
import { reg } from '../../../registry';
|
||||
import Synchronizer from '../../../Synchronizer';
|
||||
|
||||
export interface SyncTargetUpgradeResult {
|
||||
done: boolean;
|
||||
@@ -21,11 +22,12 @@ export default function useSyncTargetUpgrade(): SyncTargetUpgradeResult {
|
||||
let error = null;
|
||||
try {
|
||||
reg.logger().info('useSyncTargetUpgrade: Acquire synchronizer...');
|
||||
const synchronizer = await reg.syncTarget().synchronizer();
|
||||
const synchronizer: Synchronizer = await reg.syncTarget().synchronizer();
|
||||
|
||||
reg.logger().info('useSyncTargetUpgrade: Create migration handler...');
|
||||
const migrationHandler = new MigrationHandler(
|
||||
synchronizer.api(),
|
||||
synchronizer.syncTargetInfoHandler(),
|
||||
synchronizer.lockHandler(),
|
||||
Setting.value('appType'),
|
||||
Setting.value('clientId')
|
||||
|
||||
@@ -8,15 +8,23 @@ import { Dirnames } from '../../services/synchronizer/utils/types';
|
||||
// gulp buildTests -L && node tests-build/support/createSyncTargetSnapshot.js normal && node tests-build/support/createSyncTargetSnapshot.js e2ee
|
||||
|
||||
|
||||
const { setSyncTargetName, fileApi, synchronizer, decryptionWorker, encryptionService, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } = require('../../testing/test-utils.js');
|
||||
import { setSyncTargetName, fileApi, synchronizer, decryptionWorker, encryptionService, setupDatabaseAndSynchronizer, switchClient, expectThrow, expectNotThrow } from '../../testing/test-utils';
|
||||
const { deploySyncTargetSnapshot, testData, checkTestData } = require('../../testing/syncTargetUtils');
|
||||
import Setting from '../../models/Setting';
|
||||
import MasterKey from '../../models/MasterKey';
|
||||
import SyncTargetInfoHandler from './SyncTargetInfoHandler';
|
||||
|
||||
const specTimeout = 60000 * 10; // Nextcloud tests can be slow
|
||||
|
||||
let lockHandler_: LockHandler = null;
|
||||
let migrationHandler_: MigrationHandler = null;
|
||||
let syncTargetInfo_: SyncTargetInfoHandler = null;
|
||||
|
||||
function syncTargetInfoHandler(): SyncTargetInfoHandler {
|
||||
if (syncTargetInfo_) return syncTargetInfo_;
|
||||
syncTargetInfo_ = new SyncTargetInfoHandler(fileApi());
|
||||
return syncTargetInfo_;
|
||||
}
|
||||
|
||||
function lockHandler(): LockHandler {
|
||||
if (lockHandler_) return lockHandler_;
|
||||
@@ -26,7 +34,7 @@ function lockHandler(): LockHandler {
|
||||
|
||||
function migrationHandler(clientId: string = 'abcd'): MigrationHandler {
|
||||
if (migrationHandler_) return migrationHandler_;
|
||||
migrationHandler_ = new MigrationHandler(fileApi(), lockHandler(), 'desktop', clientId);
|
||||
migrationHandler_ = new MigrationHandler(fileApi(), syncTargetInfoHandler(), lockHandler(), 'desktop', clientId);
|
||||
return migrationHandler_;
|
||||
}
|
||||
|
||||
@@ -66,6 +74,7 @@ describe('synchronizer_MigrationHandler', function() {
|
||||
previousSyncTargetName = setSyncTargetName('filesystem');
|
||||
lockHandler_ = null;
|
||||
migrationHandler_ = null;
|
||||
syncTargetInfo_ = null;
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
await setupDatabaseAndSynchronizer(2);
|
||||
await switchClient(1);
|
||||
@@ -103,14 +112,14 @@ describe('synchronizer_MigrationHandler', function() {
|
||||
it(`should migrate (${migrationVersion})`, (async () => {
|
||||
await deploySyncTargetSnapshot('normal', migrationVersion - 1);
|
||||
|
||||
const info = await migrationHandler().fetchSyncTargetInfo();
|
||||
const info = await syncTargetInfoHandler().info();
|
||||
expect(info.version).toBe(migrationVersion - 1);
|
||||
|
||||
// Now, migrate to the new version
|
||||
await migrationHandler().upgrade(migrationVersion);
|
||||
|
||||
// Verify that it has been upgraded
|
||||
const newInfo = await migrationHandler().fetchSyncTargetInfo();
|
||||
const newInfo = await syncTargetInfoHandler().info();
|
||||
expect(newInfo.version).toBe(migrationVersion);
|
||||
await migrationTests[migrationVersion]();
|
||||
|
||||
@@ -137,7 +146,7 @@ describe('synchronizer_MigrationHandler', function() {
|
||||
await migrationHandler().upgrade(migrationVersion);
|
||||
|
||||
// Verify that it has been upgraded
|
||||
const newInfo = await migrationHandler().fetchSyncTargetInfo();
|
||||
const newInfo = await syncTargetInfoHandler().info();
|
||||
expect(newInfo.version).toBe(migrationVersion);
|
||||
await migrationTests[migrationVersion]();
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import NoteTag from '../models/NoteTag';
|
||||
import Revision from '../models/Revision';
|
||||
import MasterKey from '../models/MasterKey';
|
||||
import BaseItem from '../models/BaseItem';
|
||||
const { FileApi } = require('../file-api.js');
|
||||
const FileApiDriverMemory = require('../file-api-driver-memory').default;
|
||||
const { FileApiDriverLocal } = require('../file-api-driver-local.js');
|
||||
const { FileApiDriverWebDav } = require('../file-api-driver-webdav.js');
|
||||
@@ -52,6 +51,7 @@ import JoplinServerApi from '../JoplinServerApi';
|
||||
import { FolderEntity } from '../services/database/types';
|
||||
import { credentialFile, readCredentialFile } from '../utils/credentialFiles';
|
||||
import SyncTargetJoplinCloud from '../SyncTargetJoplinCloud';
|
||||
import { FileApi } from '../file-api';
|
||||
const { loadKeychainServiceAndSettings } = require('../services/SettingUtils');
|
||||
const md5 = require('md5');
|
||||
const S3 = require('aws-sdk/clients/s3');
|
||||
@@ -602,7 +602,7 @@ async function initFileApi() {
|
||||
fileApis_[syncTargetId_] = fileApi;
|
||||
}
|
||||
|
||||
function fileApi() {
|
||||
function fileApi(): FileApi {
|
||||
return fileApis_[syncTargetId_];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user