fix mtime for webdav
This commit is contained in:
parent
1f4737bfb8
commit
5df06bbed5
@ -185,6 +185,11 @@ export interface Entity {
|
||||
etag?: string;
|
||||
}
|
||||
|
||||
export interface UploadedType {
|
||||
entity: Entity;
|
||||
mtimeCli?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* A replacement of FileOrFolderMixedState
|
||||
*/
|
||||
|
||||
@ -6,6 +6,7 @@ import type {
|
||||
S3Config,
|
||||
SUPPORTED_SERVICES_TYPE,
|
||||
WebdavConfig,
|
||||
UploadedType,
|
||||
} from "./baseTypes";
|
||||
import * as dropbox from "./remoteForDropbox";
|
||||
import * as onedrive from "./remoteForOnedrive";
|
||||
@ -112,7 +113,7 @@ export class RemoteClient {
|
||||
foldersCreatedBefore: Set<string> | undefined = undefined,
|
||||
uploadRaw: boolean = false,
|
||||
rawContent: string | ArrayBuffer = ""
|
||||
) => {
|
||||
): Promise<UploadedType> => {
|
||||
if (this.serviceType === "s3") {
|
||||
return await s3.uploadToRemote(
|
||||
s3.getS3Client(this.s3Config!),
|
||||
|
||||
@ -8,6 +8,7 @@ import {
|
||||
Entity,
|
||||
COMMAND_CALLBACK_DROPBOX,
|
||||
OAUTH2_FORCE_EXPIRE_MILLISECONDS,
|
||||
UploadedType,
|
||||
} from "./baseTypes";
|
||||
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
||||
import {
|
||||
@ -460,7 +461,7 @@ export const uploadToRemote = async (
|
||||
rawContent: string | ArrayBuffer = "",
|
||||
rawContentMTime: number = 0,
|
||||
rawContentCTime: number = 0
|
||||
) => {
|
||||
): Promise<UploadedType> => {
|
||||
await client.init();
|
||||
|
||||
let uploadFile = fileOrFolderPath;
|
||||
@ -526,7 +527,10 @@ export const uploadToRemote = async (
|
||||
}
|
||||
}
|
||||
const res = await getRemoteMeta(client, uploadFile);
|
||||
return res;
|
||||
return {
|
||||
entity: res,
|
||||
mtimeCli: mtime,
|
||||
};
|
||||
} else {
|
||||
// if encrypted, upload a fake file with the encrypted file name
|
||||
await retryReq(
|
||||
@ -538,7 +542,10 @@ export const uploadToRemote = async (
|
||||
}),
|
||||
fileOrFolderPath
|
||||
);
|
||||
return await getRemoteMeta(client, uploadFile);
|
||||
return {
|
||||
entity: await getRemoteMeta(client, uploadFile),
|
||||
mtimeCli: mtime,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// file
|
||||
@ -587,7 +594,10 @@ export const uploadToRemote = async (
|
||||
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,
|
||||
OnedriveConfig,
|
||||
Entity,
|
||||
UploadedType,
|
||||
} from "./baseTypes";
|
||||
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
||||
import {
|
||||
@ -701,7 +702,7 @@ export const uploadToRemote = async (
|
||||
foldersCreatedBefore: Set<string> | undefined = undefined,
|
||||
uploadRaw: boolean = false,
|
||||
rawContent: string | ArrayBuffer = ""
|
||||
) => {
|
||||
): Promise<UploadedType> => {
|
||||
await client.init();
|
||||
|
||||
let uploadFile = fileOrFolderPath;
|
||||
@ -759,7 +760,10 @@ export const uploadToRemote = async (
|
||||
await client.patchJson(uploadFile, k);
|
||||
}
|
||||
const res = await getRemoteMeta(client, uploadFile);
|
||||
return res;
|
||||
return {
|
||||
entity: res,
|
||||
mtimeCli: mtime,
|
||||
};
|
||||
} else {
|
||||
// if encrypted,
|
||||
// upload a fake, random-size file
|
||||
@ -790,7 +794,10 @@ export const uploadToRemote = async (
|
||||
}
|
||||
// log.info(uploadResult)
|
||||
const res = await getRemoteMeta(client, uploadFile);
|
||||
return res;
|
||||
return {
|
||||
entity: res,
|
||||
mtimeCli: mtime,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
// file
|
||||
@ -889,7 +896,10 @@ export const uploadToRemote = async (
|
||||
}
|
||||
|
||||
const res = await getRemoteMeta(client, uploadFile);
|
||||
return res;
|
||||
return {
|
||||
entity: res,
|
||||
mtimeCli: mtime,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -30,6 +30,7 @@ import {
|
||||
DEFAULT_CONTENT_TYPE,
|
||||
Entity,
|
||||
S3Config,
|
||||
UploadedType,
|
||||
VALID_REQURL,
|
||||
} from "./baseTypes";
|
||||
import { decryptArrayBuffer, encryptArrayBuffer } from "./encrypt";
|
||||
@ -365,7 +366,7 @@ export const uploadToRemote = async (
|
||||
rawContent: string | ArrayBuffer = "",
|
||||
rawContentMTime: number = 0,
|
||||
rawContentCTime: number = 0
|
||||
) => {
|
||||
): Promise<UploadedType> => {
|
||||
log.debug(`uploading ${fileOrFolderPath}`);
|
||||
let uploadFile = fileOrFolderPath;
|
||||
if (password !== "") {
|
||||
@ -408,7 +409,10 @@ export const uploadToRemote = async (
|
||||
})
|
||||
);
|
||||
const res = await getRemoteMeta(s3Client, s3Config, uploadFile);
|
||||
return res;
|
||||
return {
|
||||
entity: res,
|
||||
mtimeCli: mtime,
|
||||
};
|
||||
} else {
|
||||
// file
|
||||
// we ignore isRecursively parameter here
|
||||
@ -476,7 +480,10 @@ export const uploadToRemote = async (
|
||||
// log.debug(
|
||||
// `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 flatten from "lodash/flatten";
|
||||
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 { bufferToArrayBuffer, getPathFolder, mkdirpInVault } from "./misc";
|
||||
|
||||
@ -340,7 +340,7 @@ export const uploadToRemote = async (
|
||||
remoteEncryptedKey: string = "",
|
||||
uploadRaw: boolean = false,
|
||||
rawContent: string | ArrayBuffer = ""
|
||||
) => {
|
||||
): Promise<UploadedType> => {
|
||||
await client.init();
|
||||
let uploadFile = fileOrFolderPath;
|
||||
if (password !== "") {
|
||||
@ -368,7 +368,9 @@ export const uploadToRemote = async (
|
||||
recursive: true,
|
||||
});
|
||||
const res = await getRemoteMeta(client, uploadFile);
|
||||
return res;
|
||||
return {
|
||||
entity: res,
|
||||
};
|
||||
} else {
|
||||
// if encrypted, upload a fake file with the encrypted file name
|
||||
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 {
|
||||
// file
|
||||
// we ignore isRecursively parameter here
|
||||
let localContent = undefined;
|
||||
let localContent: ArrayBuffer | undefined = undefined;
|
||||
let mtimeCli: number | undefined = undefined;
|
||||
if (uploadRaw) {
|
||||
if (typeof rawContent === "string") {
|
||||
localContent = new TextEncoder().encode(rawContent).buffer;
|
||||
@ -397,6 +402,7 @@ export const uploadToRemote = async (
|
||||
);
|
||||
}
|
||||
localContent = await vault.adapter.readBinary(fileOrFolderPath);
|
||||
mtimeCli = (await vault.adapter.stat(fileOrFolderPath))?.mtime;
|
||||
}
|
||||
let remoteContent = localContent;
|
||||
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;
|
||||
};
|
||||
|
||||
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.
|
||||
* 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
|
||||
local.sizeEnc = getSizeFromOrigToEnc(local.size);
|
||||
}
|
||||
|
||||
|
||||
if (local.keyEnc === undefined || local.keyEnc === "") {
|
||||
if (
|
||||
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.
|
||||
} else {
|
||||
// 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,
|
||||
vault,
|
||||
false,
|
||||
password,
|
||||
r.local!.keyEnc
|
||||
);
|
||||
await decryptRemoteEntityInplace(remoteObjMeta, password);
|
||||
await upsertPrevSyncRecordByVault(db, vaultRandomID, remoteObjMeta);
|
||||
await decryptRemoteEntityInplace(entity, password);
|
||||
await fullfillMTimeOfRemoteEntityInplace(entity, mtimeCli);
|
||||
await upsertPrevSyncRecordByVault(db, vaultRandomID, entity);
|
||||
}
|
||||
} else if (
|
||||
r.decision === "modified_remote" ||
|
||||
@ -936,7 +955,7 @@ const dispatchOperationToActualV3 = async (
|
||||
throw Error(`${r.decision} not implemented yet: ${JSON.stringify(r)}`);
|
||||
} else if (r.decision === "folder_to_be_created") {
|
||||
await mkdirpInVault(r.key, vault);
|
||||
const remoteObjMeta = await client.uploadToRemote(
|
||||
const { entity, mtimeCli } = await client.uploadToRemote(
|
||||
r.key,
|
||||
vault,
|
||||
false,
|
||||
@ -944,8 +963,9 @@ const dispatchOperationToActualV3 = async (
|
||||
r.local!.keyEnc
|
||||
);
|
||||
// we need to decrypt the key!!!
|
||||
await decryptRemoteEntityInplace(remoteObjMeta, password);
|
||||
await upsertPrevSyncRecordByVault(db, vaultRandomID, remoteObjMeta);
|
||||
await decryptRemoteEntityInplace(entity, password);
|
||||
await fullfillMTimeOfRemoteEntityInplace(entity, mtimeCli);
|
||||
await upsertPrevSyncRecordByVault(db, vaultRandomID, entity);
|
||||
} else if (r.decision === "folder_to_be_deleted") {
|
||||
await localDeleteFunc(r.key);
|
||||
await client.deleteFromRemote(r.key, password, r.remote!.keyEnc);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user