fix mtime for webdav
This commit is contained in:
parent
1f4737bfb8
commit
5df06bbed5
@ -185,6 +185,11 @@ export interface Entity {
|
|||||||
etag?: string;
|
etag?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UploadedType {
|
||||||
|
entity: Entity;
|
||||||
|
mtimeCli?: number;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A replacement of FileOrFolderMixedState
|
* A replacement of FileOrFolderMixedState
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import type {
|
|||||||
S3Config,
|
S3Config,
|
||||||
SUPPORTED_SERVICES_TYPE,
|
SUPPORTED_SERVICES_TYPE,
|
||||||
WebdavConfig,
|
WebdavConfig,
|
||||||
|
UploadedType,
|
||||||
} from "./baseTypes";
|
} from "./baseTypes";
|
||||||
import * as dropbox from "./remoteForDropbox";
|
import * as dropbox from "./remoteForDropbox";
|
||||||
import * as onedrive from "./remoteForOnedrive";
|
import * as onedrive from "./remoteForOnedrive";
|
||||||
@ -112,7 +113,7 @@ export class RemoteClient {
|
|||||||
foldersCreatedBefore: Set<string> | undefined = undefined,
|
foldersCreatedBefore: Set<string> | undefined = undefined,
|
||||||
uploadRaw: boolean = false,
|
uploadRaw: boolean = false,
|
||||||
rawContent: string | ArrayBuffer = ""
|
rawContent: string | ArrayBuffer = ""
|
||||||
) => {
|
): Promise<UploadedType> => {
|
||||||
if (this.serviceType === "s3") {
|
if (this.serviceType === "s3") {
|
||||||
return await s3.uploadToRemote(
|
return await s3.uploadToRemote(
|
||||||
s3.getS3Client(this.s3Config!),
|
s3.getS3Client(this.s3Config!),
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import {
|
|||||||
Entity,
|
Entity,
|
||||||
COMMAND_CALLBACK_DROPBOX,
|
COMMAND_CALLBACK_DROPBOX,
|
||||||
OAUTH2_FORCE_EXPIRE_MILLISECONDS,
|
OAUTH2_FORCE_EXPIRE_MILLISECONDS,
|
||||||
|
UploadedType,
|
||||||
} from "./baseTypes";
|
} from "./baseTypes";
|
||||||
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
||||||
import {
|
import {
|
||||||
@ -460,7 +461,7 @@ export const uploadToRemote = async (
|
|||||||
rawContent: string | ArrayBuffer = "",
|
rawContent: string | ArrayBuffer = "",
|
||||||
rawContentMTime: number = 0,
|
rawContentMTime: number = 0,
|
||||||
rawContentCTime: number = 0
|
rawContentCTime: number = 0
|
||||||
) => {
|
): Promise<UploadedType> => {
|
||||||
await client.init();
|
await client.init();
|
||||||
|
|
||||||
let uploadFile = fileOrFolderPath;
|
let uploadFile = fileOrFolderPath;
|
||||||
@ -526,7 +527,10 @@ export const uploadToRemote = async (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const res = await getRemoteMeta(client, uploadFile);
|
const res = await getRemoteMeta(client, uploadFile);
|
||||||
return res;
|
return {
|
||||||
|
entity: res,
|
||||||
|
mtimeCli: mtime,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
// if encrypted, upload a fake file with the encrypted file name
|
// if encrypted, upload a fake file with the encrypted file name
|
||||||
await retryReq(
|
await retryReq(
|
||||||
@ -538,7 +542,10 @@ export const uploadToRemote = async (
|
|||||||
}),
|
}),
|
||||||
fileOrFolderPath
|
fileOrFolderPath
|
||||||
);
|
);
|
||||||
return await getRemoteMeta(client, uploadFile);
|
return {
|
||||||
|
entity: await getRemoteMeta(client, uploadFile),
|
||||||
|
mtimeCli: mtime,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// file
|
// file
|
||||||
@ -587,7 +594,10 @@ export const uploadToRemote = async (
|
|||||||
foldersCreatedBefore?.add(dir);
|
foldersCreatedBefore?.add(dir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return await getRemoteMeta(client, uploadFile);
|
return {
|
||||||
|
entity: await getRemoteMeta(client, uploadFile),
|
||||||
|
mtimeCli: mtime,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import {
|
|||||||
OAUTH2_FORCE_EXPIRE_MILLISECONDS,
|
OAUTH2_FORCE_EXPIRE_MILLISECONDS,
|
||||||
OnedriveConfig,
|
OnedriveConfig,
|
||||||
Entity,
|
Entity,
|
||||||
|
UploadedType,
|
||||||
} from "./baseTypes";
|
} from "./baseTypes";
|
||||||
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
||||||
import {
|
import {
|
||||||
@ -701,7 +702,7 @@ export const uploadToRemote = async (
|
|||||||
foldersCreatedBefore: Set<string> | undefined = undefined,
|
foldersCreatedBefore: Set<string> | undefined = undefined,
|
||||||
uploadRaw: boolean = false,
|
uploadRaw: boolean = false,
|
||||||
rawContent: string | ArrayBuffer = ""
|
rawContent: string | ArrayBuffer = ""
|
||||||
) => {
|
): Promise<UploadedType> => {
|
||||||
await client.init();
|
await client.init();
|
||||||
|
|
||||||
let uploadFile = fileOrFolderPath;
|
let uploadFile = fileOrFolderPath;
|
||||||
@ -759,7 +760,10 @@ export const uploadToRemote = async (
|
|||||||
await client.patchJson(uploadFile, k);
|
await client.patchJson(uploadFile, k);
|
||||||
}
|
}
|
||||||
const res = await getRemoteMeta(client, uploadFile);
|
const res = await getRemoteMeta(client, uploadFile);
|
||||||
return res;
|
return {
|
||||||
|
entity: res,
|
||||||
|
mtimeCli: mtime,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
// if encrypted,
|
// if encrypted,
|
||||||
// upload a fake, random-size file
|
// upload a fake, random-size file
|
||||||
@ -790,7 +794,10 @@ export const uploadToRemote = async (
|
|||||||
}
|
}
|
||||||
// log.info(uploadResult)
|
// log.info(uploadResult)
|
||||||
const res = await getRemoteMeta(client, uploadFile);
|
const res = await getRemoteMeta(client, uploadFile);
|
||||||
return res;
|
return {
|
||||||
|
entity: res,
|
||||||
|
mtimeCli: mtime,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// file
|
// file
|
||||||
@ -889,7 +896,10 @@ export const uploadToRemote = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
const res = await getRemoteMeta(client, uploadFile);
|
const res = await getRemoteMeta(client, uploadFile);
|
||||||
return res;
|
return {
|
||||||
|
entity: res,
|
||||||
|
mtimeCli: mtime,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,7 @@ import {
|
|||||||
DEFAULT_CONTENT_TYPE,
|
DEFAULT_CONTENT_TYPE,
|
||||||
Entity,
|
Entity,
|
||||||
S3Config,
|
S3Config,
|
||||||
|
UploadedType,
|
||||||
VALID_REQURL,
|
VALID_REQURL,
|
||||||
} from "./baseTypes";
|
} from "./baseTypes";
|
||||||
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
||||||
@ -365,7 +366,7 @@ export const uploadToRemote = async (
|
|||||||
rawContent: string | ArrayBuffer = "",
|
rawContent: string | ArrayBuffer = "",
|
||||||
rawContentMTime: number = 0,
|
rawContentMTime: number = 0,
|
||||||
rawContentCTime: number = 0
|
rawContentCTime: number = 0
|
||||||
) => {
|
): Promise<UploadedType> => {
|
||||||
log.debug(`uploading ${fileOrFolderPath}`);
|
log.debug(`uploading ${fileOrFolderPath}`);
|
||||||
let uploadFile = fileOrFolderPath;
|
let uploadFile = fileOrFolderPath;
|
||||||
if (password !== "") {
|
if (password !== "") {
|
||||||
@ -408,7 +409,10 @@ export const uploadToRemote = async (
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
const res = await getRemoteMeta(s3Client, s3Config, uploadFile);
|
const res = await getRemoteMeta(s3Client, s3Config, uploadFile);
|
||||||
return res;
|
return {
|
||||||
|
entity: res,
|
||||||
|
mtimeCli: mtime,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
// file
|
// file
|
||||||
// we ignore isRecursively parameter here
|
// we ignore isRecursively parameter here
|
||||||
@ -476,7 +480,10 @@ export const uploadToRemote = async (
|
|||||||
// log.debug(
|
// log.debug(
|
||||||
// `uploaded ${uploadFile} with res=${JSON.stringify(res, null, 2)}`
|
// `uploaded ${uploadFile} with res=${JSON.stringify(res, null, 2)}`
|
||||||
// );
|
// );
|
||||||
return res;
|
return {
|
||||||
|
entity: res,
|
||||||
|
mtimeCli: mtime,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { Queue } from "@fyears/tsqueue";
|
|||||||
import chunk from "lodash/chunk";
|
import chunk from "lodash/chunk";
|
||||||
import flatten from "lodash/flatten";
|
import flatten from "lodash/flatten";
|
||||||
import { getReasonPhrase } from "http-status-codes";
|
import { getReasonPhrase } from "http-status-codes";
|
||||||
import { Entity, VALID_REQURL, WebdavConfig } from "./baseTypes";
|
import { Entity, UploadedType, VALID_REQURL, WebdavConfig } from "./baseTypes";
|
||||||
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
||||||
import { bufferToArrayBuffer, getPathFolder, mkdirpInVault } from "./misc";
|
import { bufferToArrayBuffer, getPathFolder, mkdirpInVault } from "./misc";
|
||||||
|
|
||||||
@ -340,7 +340,7 @@ export const uploadToRemote = async (
|
|||||||
remoteEncryptedKey: string = "",
|
remoteEncryptedKey: string = "",
|
||||||
uploadRaw: boolean = false,
|
uploadRaw: boolean = false,
|
||||||
rawContent: string | ArrayBuffer = ""
|
rawContent: string | ArrayBuffer = ""
|
||||||
) => {
|
): Promise<UploadedType> => {
|
||||||
await client.init();
|
await client.init();
|
||||||
let uploadFile = fileOrFolderPath;
|
let uploadFile = fileOrFolderPath;
|
||||||
if (password !== "") {
|
if (password !== "") {
|
||||||
@ -368,7 +368,9 @@ export const uploadToRemote = async (
|
|||||||
recursive: true,
|
recursive: true,
|
||||||
});
|
});
|
||||||
const res = await getRemoteMeta(client, uploadFile);
|
const res = await getRemoteMeta(client, uploadFile);
|
||||||
return res;
|
return {
|
||||||
|
entity: res,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
// if encrypted, upload a fake file with the encrypted file name
|
// if encrypted, upload a fake file with the encrypted file name
|
||||||
await client.client.putFileContents(uploadFile, "", {
|
await client.client.putFileContents(uploadFile, "", {
|
||||||
@ -378,12 +380,15 @@ export const uploadToRemote = async (
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return await getRemoteMeta(client, uploadFile);
|
return {
|
||||||
|
entity: await getRemoteMeta(client, uploadFile),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// file
|
// file
|
||||||
// we ignore isRecursively parameter here
|
// we ignore isRecursively parameter here
|
||||||
let localContent = undefined;
|
let localContent: ArrayBuffer | undefined = undefined;
|
||||||
|
let mtimeCli: number | undefined = undefined;
|
||||||
if (uploadRaw) {
|
if (uploadRaw) {
|
||||||
if (typeof rawContent === "string") {
|
if (typeof rawContent === "string") {
|
||||||
localContent = new TextEncoder().encode(rawContent).buffer;
|
localContent = new TextEncoder().encode(rawContent).buffer;
|
||||||
@ -397,6 +402,7 @@ export const uploadToRemote = async (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
||||||
|
mtimeCli = (await vault.adapter.stat(fileOrFolderPath))?.mtime;
|
||||||
}
|
}
|
||||||
let remoteContent = localContent;
|
let remoteContent = localContent;
|
||||||
if (password !== "") {
|
if (password !== "") {
|
||||||
@ -415,7 +421,10 @@ export const uploadToRemote = async (
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
return await getRemoteMeta(client, uploadFile);
|
return {
|
||||||
|
entity: await getRemoteMeta(client, uploadFile),
|
||||||
|
mtimeCli: mtimeCli,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
34
src/sync.ts
34
src/sync.ts
@ -249,6 +249,24 @@ const decryptRemoteEntityInplace = async (remote: Entity, password: string) => {
|
|||||||
return remote;
|
return remote;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const fullfillMTimeOfRemoteEntityInplace = (
|
||||||
|
remote: Entity,
|
||||||
|
mtimeCli?: number
|
||||||
|
) => {
|
||||||
|
if (
|
||||||
|
mtimeCli !== undefined &&
|
||||||
|
mtimeCli > 0 &&
|
||||||
|
(remote.mtimeCli === undefined ||
|
||||||
|
remote.mtimeCli <= 0 ||
|
||||||
|
(remote.mtimeSvr !== undefined &&
|
||||||
|
remote.mtimeSvr > 0 &&
|
||||||
|
remote.mtimeCli >= remote.mtimeSvr))
|
||||||
|
) {
|
||||||
|
remote.mtimeCli = mtimeCli;
|
||||||
|
}
|
||||||
|
return remote;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Directly throw error here.
|
* Directly throw error here.
|
||||||
* We can only defer the checking now, because before decryption we don't know whether it's a file or folder.
|
* We can only defer the checking now, because before decryption we don't know whether it's a file or folder.
|
||||||
@ -312,7 +330,7 @@ const encryptLocalEntityInplace = async (
|
|||||||
// but local.key should always have value
|
// but local.key should always have value
|
||||||
local.sizeEnc = getSizeFromOrigToEnc(local.size);
|
local.sizeEnc = getSizeFromOrigToEnc(local.size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local.keyEnc === undefined || local.keyEnc === "") {
|
if (local.keyEnc === undefined || local.keyEnc === "") {
|
||||||
if (
|
if (
|
||||||
remoteKeyEnc !== undefined &&
|
remoteKeyEnc !== undefined &&
|
||||||
@ -895,15 +913,16 @@ const dispatchOperationToActualV3 = async (
|
|||||||
// if it's empty folder, or it's encrypted file/folder, it continues to be uploaded.
|
// if it's empty folder, or it's encrypted file/folder, it continues to be uploaded.
|
||||||
} else {
|
} else {
|
||||||
// log.debug(`before upload in sync, r=${JSON.stringify(r, null, 2)}`);
|
// log.debug(`before upload in sync, r=${JSON.stringify(r, null, 2)}`);
|
||||||
const remoteObjMeta = await client.uploadToRemote(
|
const { entity, mtimeCli } = await client.uploadToRemote(
|
||||||
r.key,
|
r.key,
|
||||||
vault,
|
vault,
|
||||||
false,
|
false,
|
||||||
password,
|
password,
|
||||||
r.local!.keyEnc
|
r.local!.keyEnc
|
||||||
);
|
);
|
||||||
await decryptRemoteEntityInplace(remoteObjMeta, password);
|
await decryptRemoteEntityInplace(entity, password);
|
||||||
await upsertPrevSyncRecordByVault(db, vaultRandomID, remoteObjMeta);
|
await fullfillMTimeOfRemoteEntityInplace(entity, mtimeCli);
|
||||||
|
await upsertPrevSyncRecordByVault(db, vaultRandomID, entity);
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
r.decision === "modified_remote" ||
|
r.decision === "modified_remote" ||
|
||||||
@ -936,7 +955,7 @@ const dispatchOperationToActualV3 = async (
|
|||||||
throw Error(`${r.decision} not implemented yet: ${JSON.stringify(r)}`);
|
throw Error(`${r.decision} not implemented yet: ${JSON.stringify(r)}`);
|
||||||
} else if (r.decision === "folder_to_be_created") {
|
} else if (r.decision === "folder_to_be_created") {
|
||||||
await mkdirpInVault(r.key, vault);
|
await mkdirpInVault(r.key, vault);
|
||||||
const remoteObjMeta = await client.uploadToRemote(
|
const { entity, mtimeCli } = await client.uploadToRemote(
|
||||||
r.key,
|
r.key,
|
||||||
vault,
|
vault,
|
||||||
false,
|
false,
|
||||||
@ -944,8 +963,9 @@ const dispatchOperationToActualV3 = async (
|
|||||||
r.local!.keyEnc
|
r.local!.keyEnc
|
||||||
);
|
);
|
||||||
// we need to decrypt the key!!!
|
// we need to decrypt the key!!!
|
||||||
await decryptRemoteEntityInplace(remoteObjMeta, password);
|
await decryptRemoteEntityInplace(entity, password);
|
||||||
await upsertPrevSyncRecordByVault(db, vaultRandomID, remoteObjMeta);
|
await fullfillMTimeOfRemoteEntityInplace(entity, mtimeCli);
|
||||||
|
await upsertPrevSyncRecordByVault(db, vaultRandomID, entity);
|
||||||
} else if (r.decision === "folder_to_be_deleted") {
|
} else if (r.decision === "folder_to_be_deleted") {
|
||||||
await localDeleteFunc(r.key);
|
await localDeleteFunc(r.key);
|
||||||
await client.deleteFromRemote(r.key, password, r.remote!.keyEnc);
|
await client.deleteFromRemote(r.key, password, r.remote!.keyEnc);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user