1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-11-23 22:36:32 +02:00

All: Fixes 12810: Ensure the sync shows an error when the server is down, when using a local WebDAV server (#13301)

This commit is contained in:
mrjo118
2025-10-09 21:59:58 +01:00
committed by GitHub
parent 820acdc1f0
commit 53ea51b758
3 changed files with 39 additions and 4 deletions

View File

@@ -20,7 +20,7 @@ import JoplinError from './JoplinError';
import ShareService from './services/share/ShareService'; import ShareService from './services/share/ShareService';
import TaskQueue from './TaskQueue'; import TaskQueue from './TaskQueue';
import ItemUploader from './services/synchronizer/ItemUploader'; import ItemUploader from './services/synchronizer/ItemUploader';
import { FileApi, getSupportsDeltaWithItems, PaginatedList, RemoteItem } from './file-api'; import { FileApi, getSupportsDeltaWithItems, isLocalServer, PaginatedList, RemoteItem } from './file-api';
import JoplinDatabase from './JoplinDatabase'; import JoplinDatabase from './JoplinDatabase';
import { checkIfCanSync, fetchSyncInfo, checkSyncTargetIsValid, getActiveMasterKey, localSyncInfo, mergeSyncInfos, saveLocalSyncInfo, setMasterKeyHasBeenUsed, SyncInfo, syncInfoEquals, uploadSyncInfo } from './services/synchronizer/syncInfoUtils'; import { checkIfCanSync, fetchSyncInfo, checkSyncTargetIsValid, getActiveMasterKey, localSyncInfo, mergeSyncInfos, saveLocalSyncInfo, setMasterKeyHasBeenUsed, SyncInfo, syncInfoEquals, uploadSyncInfo } from './services/synchronizer/syncInfoUtils';
import { getMasterPassword, setupAndDisableEncryption, setupAndEnableEncryption } from './services/e2ee/utils'; import { getMasterPassword, setupAndDisableEncryption, setupAndEnableEncryption } from './services/e2ee/utils';
@@ -32,6 +32,7 @@ import syncDeleteStep from './services/synchronizer/utils/syncDeleteStep';
import { ErrorCode } from './errors'; import { ErrorCode } from './errors';
import { SyncAction } from './services/synchronizer/utils/types'; import { SyncAction } from './services/synchronizer/utils/types';
import checkDisabledSyncItemsNotification from './services/synchronizer/utils/checkDisabledSyncItemsNotification'; import checkDisabledSyncItemsNotification from './services/synchronizer/utils/checkDisabledSyncItemsNotification';
import SyncTargetRegistry from './SyncTargetRegistry';
const { sprintf } = require('sprintf-js'); const { sprintf } = require('sprintf-js');
const { Dirnames } = require('./services/synchronizer/utils/types'); const { Dirnames } = require('./services/synchronizer/utils/types');
@@ -1164,8 +1165,13 @@ export default class Synchronizer {
logger.error(error); logger.error(error);
if (error.details) logger.error('Details:', error.details); if (error.details) logger.error('Details:', error.details);
// Don't save to the report errors that are due to things like temporary network errors or timeout. const isLocalWebDavServer = Setting.value('sync.target') === SyncTargetRegistry.nameToId('webdav') && isLocalServer(Setting.value('sync.6.path'));
if (!shim.fetchRequestCanBeRetried(error)) {
// Don't save to the report errors that are due to things like temporary network errors or timeout, except if using a local WebDAV server, in which
// case timeout errors can occur when the server is actually down. Those type of errors happen consistently when a local server is down when using
// the Android app in particular, but they can also happen on the desktop app in some circumstances. The usage of a local WebDAV server is most useful
// on Android, as it can be used as an alternative to file system sync, in order to work around performance issues related to SAF
if (!shim.fetchRequestCanBeRetried(error) || isLocalWebDavServer) {
this.progressReport_.errors.push(error); this.progressReport_.errors.push(error);
this.logLastRequests(); this.logLastRequests();
} }

View File

@@ -1,4 +1,4 @@
import { PaginatedList, RemoteItem, getSupportsDeltaWithItems } from './file-api'; import { PaginatedList, RemoteItem, getSupportsDeltaWithItems, isLocalServer } from './file-api';
const defaultPaginatedList = (): PaginatedList => { const defaultPaginatedList = (): PaginatedList => {
return { return {
@@ -70,4 +70,28 @@ describe('file-api', () => {
expect(actual).toBe(expected); expect(actual).toBe(expected);
}); });
it.each([
'http://localhost',
'http://localhost/',
'https://localhost:8080',
'http://127.0.0.1',
'https://127.100.50.25:3000/test',
'http://[::1]',
'http://localhost/api/v1',
])('should detect a local server url', (url: string) => {
const result = isLocalServer(url);
expect(result).toBe(true);
});
it.each([
'http://localhostXYZ',
'http://127.0.0.1foobar',
'http://192.168.1.1',
'http://example.com',
'https://my-localhost.com',
])('should detect a non local server url', (url: string) => {
const result = isLocalServer(url);
expect(result).toBe(false);
});
}); });

View File

@@ -53,6 +53,11 @@ export const getSupportsDeltaWithItems = (deltaResponse: PaginatedList) => {
return 'jopItem' in deltaResponse.items[0]; return 'jopItem' in deltaResponse.items[0];
}; };
export const isLocalServer = (url: string) => {
const regex = /^(https?:\/\/)?(localhost|127(?:\.\d{1,3}){3}|\[::1\])(?::\d{1,5})?(\/.*)?$/i;
return regex.test(url);
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
function requestCanBeRepeated(error: any) { function requestCanBeRepeated(error: any) {
const errorCode = typeof error === 'object' && error.code ? error.code : null; const errorCode = typeof error === 'object' && error.code ? error.code : null;