diff --git a/src/common/ipc-actions/download.ts b/src/common/ipc-actions/download.ts index 321ee589..29a42a1a 100644 --- a/src/common/ipc-actions/download.ts +++ b/src/common/ipc-actions/download.ts @@ -1,5 +1,5 @@ import {NatureLanguage} from "kodo-s3-adapter-sdk/dist/uplog"; -import {Domain} from "kodo-s3-adapter-sdk/dist/adapter"; +import {Domain, UrlStyle} from "kodo-s3-adapter-sdk/dist/adapter"; import {ClientOptionsSerialized} from "@common/qiniu"; import {Status} from "@common/models/job/types"; @@ -24,6 +24,7 @@ export interface DownloadOptions { bucket: string, domain?: Domain, + urlStyle?: UrlStyle, isOverwrite: boolean, storageClasses: StorageClass[], diff --git a/src/common/models/job/download-job.ts b/src/common/models/job/download-job.ts index 1ef32552..be5b2b70 100644 --- a/src/common/models/job/download-job.ts +++ b/src/common/models/job/download-job.ts @@ -3,7 +3,7 @@ import fs, {constants as fsConstants, promises as fsPromises} from "fs"; import lodash from "lodash"; import {Downloader} from "kodo-s3-adapter-sdk"; -import {Adapter, Domain, ObjectHeader, StorageClass} from "kodo-s3-adapter-sdk/dist/adapter"; +import {Adapter, Domain, ObjectHeader, StorageClass, UrlStyle} from "kodo-s3-adapter-sdk/dist/adapter"; import {NatureLanguage} from "kodo-s3-adapter-sdk/dist/uplog"; import {ClientOptions, createQiniuClient} from "@common/qiniu"; @@ -36,7 +36,8 @@ interface DownloadOptions { interface OptionalOptions extends DownloadOptions { id: string, - domain?: Domain, + domain: Domain | undefined, + urlStyle: UrlStyle | undefined, status: Status, message: string, @@ -58,6 +59,8 @@ type Options = RequiredOptions & Partial const DEFAULT_OPTIONS: OptionalOptions = { id: "", + domain: undefined, + urlStyle: undefined, multipartDownloadThreshold: 100, multipartDownloadSize: 8, @@ -86,6 +89,7 @@ type PersistInfo = { from: RequiredOptions["from"], backendMode: RequiredOptions["clientOptions"]["backendMode"], domain: OptionalOptions["domain"], + urlStyle: OptionalOptions["urlStyle"], prog: OptionalOptions["prog"], status: Exclude, message: OptionalOptions["message"], @@ -112,6 +116,8 @@ export default class DownloadJob extends TransferJob { ): DownloadJob { return new DownloadJob({ id, + domain: persistInfo.domain, + urlStyle: persistInfo.urlStyle, status: persistInfo.status, message: persistInfo.message, @@ -213,6 +219,7 @@ export default class DownloadJob extends TransferJob { to: this.options.to, from: this.options.from, domain: this.options.domain, + urlStyle: this.options.urlStyle, storageClasses: this.options.storageClasses, backendMode: this.options.clientOptions.backendMode, @@ -297,6 +304,7 @@ export default class DownloadJob extends TransferJob { this.tempFilePath, this.options.domain, { + urlStyle: this.options.urlStyle, recoveredFrom: this.prog.resumable ? this.prog.loaded : 0, diff --git a/src/main/transfer-managers/download-manager.ts b/src/main/transfer-managers/download-manager.ts index 7bf67f86..f0c0e355 100644 --- a/src/main/transfer-managers/download-manager.ts +++ b/src/main/transfer-managers/download-manager.ts @@ -293,6 +293,7 @@ export default class DownloadManager extends TransferManager = ({ }) => { const {translate} = useI18n(); const {currentUser} = useAuth(); + const {bucketPreferBackendMode: preferBackendMode} = useFileOperation(); // code mirror editor const editorRef = useRef(); @@ -76,13 +78,19 @@ const CodeContent: React.FC = ({ endpointType: currentUser.endpointType, preferS3Adapter: domain.apiScope === BackendMode.S3, }; + const domainToGet = domain?.name === NON_OWNED_DOMAIN.name + ? undefined + : domain; getContent( regionId, bucketName, filePath, - domain.name === NON_OWNED_DOMAIN.name - ? undefined - : domain, + domainToGet, + getStyleForSignature({ + domain: domainToGet, + preferBackendMode, + currentEndpointType: currentUser.endpointType, + }), opt, ) .then(contentBuffer => { diff --git a/src/renderer/modules/qiniu-client/common.test.ts b/src/renderer/modules/qiniu-client/common.test.ts index 73701682..411e1cb6 100644 --- a/src/renderer/modules/qiniu-client/common.test.ts +++ b/src/renderer/modules/qiniu-client/common.test.ts @@ -3,10 +3,16 @@ import * as MockAuth from "@common/qiniu/_mock-helpers_/auth"; import { RegionService } from "kodo-s3-adapter-sdk/dist/region_service"; -jest.mock("kodo-s3-adapter-sdk/dist/region_service", () => ({ +jest.mock("kodo-s3-adapter-sdk/dist/region_service", () => { + class MockedRegionService extends jest.fn() { + static clearCache = jest.fn(); + clearCache = jest.fn(); + } + return { __esModule: true, - RegionService: jest.fn().mockReturnValue({ clearCache: () => {} }), -})); + RegionService: MockedRegionService, + } +}); import { Kodo as KodoAdapter } from "kodo-s3-adapter-sdk/dist/kodo"; import { S3 as S3Adapter } from "kodo-s3-adapter-sdk/dist/s3"; diff --git a/src/renderer/modules/qiniu-client/files.test.ts b/src/renderer/modules/qiniu-client/files.test.ts index 29373922..8f6eee1f 100644 --- a/src/renderer/modules/qiniu-client/files.test.ts +++ b/src/renderer/modules/qiniu-client/files.test.ts @@ -25,7 +25,8 @@ import { ObjectInfo, PartialObjectError, StorageClass, - StorageObject + StorageObject, + UrlStyle, } from "kodo-s3-adapter-sdk/dist/adapter"; import Duration from "@common/const/duration"; @@ -443,6 +444,7 @@ describe("test qiniu-client/files.ts", () => { "bucket-kodo-browser-Kodo-getContent", qiniuPathConvertor.fromQiniuPath("qiniu-client/file-to-get"), mockDomain, + undefined, mockOpt, ); expect(QiniuClientCommon.getDefaultClient).toBeCalledTimes(1); @@ -607,7 +609,7 @@ describe("test qiniu-client/files.ts", () => { mockDataKey, undefined, 10, - name === "S3" ? "path" : "bucketEndpoint", + name === "S3" ? UrlStyle.Path : UrlStyle.BucketEndpoint, mockOpt, ); expect(QiniuClientCommon.getDefaultClient).toBeCalledTimes(1); diff --git a/src/renderer/modules/qiniu-client/files.ts b/src/renderer/modules/qiniu-client/files.ts index c70ac10b..d0bb31c4 100644 --- a/src/renderer/modules/qiniu-client/files.ts +++ b/src/renderer/modules/qiniu-client/files.ts @@ -1,6 +1,15 @@ import * as qiniuPathConvertor from "qiniu-path/dist/src/convert"; import { Path as QiniuPath } from "qiniu-path/dist/src/path"; -import { Adapter, Domain, FrozenInfo, ObjectInfo, PartialObjectError, StorageClass, TransferObject } from 'kodo-s3-adapter-sdk/dist/adapter' +import { + Adapter, + Domain, + FrozenInfo, + ObjectInfo, + PartialObjectError, + StorageClass, + TransferObject, + UrlStyle, +} from 'kodo-s3-adapter-sdk/dist/adapter' import {BackendMode} from "@common/qiniu"; import Duration from "@common/const/duration"; @@ -213,6 +222,7 @@ export async function getContent( bucket: string, key: QiniuPath | string, domain: Domain | undefined, + style: UrlStyle | undefined, opt: GetAdapterOptionParam, ):Promise { return await getDefaultClient(opt).enter("getContent", async client => { @@ -223,6 +233,7 @@ export async function getContent( key: key.toString(), }, domain, + style, ); return obj.data; }, { @@ -333,14 +344,16 @@ export function getStyleForSignature({ domain: Domain | undefined, preferBackendMode: BackendMode | undefined, currentEndpointType: EndpointType, -}): "path" | "virtualHost" | "bucketEndpoint" { +}): UrlStyle { if (domain?.apiScope === BackendMode.S3) { - return "bucketEndpoint"; + return UrlStyle.BucketEndpoint; } else if (!domain || preferBackendMode === BackendMode.S3) { // some private cloud not support wildcard domain name resolving - return currentEndpointType === EndpointType.Public ? "virtualHost" : "path"; + return currentEndpointType === EndpointType.Public + ? UrlStyle.VirtualHost + : UrlStyle.Path; } else { - return "bucketEndpoint"; + return UrlStyle.BucketEndpoint; } } @@ -350,7 +363,7 @@ export async function signatureUrl( key: QiniuPath | string, domain: Domain | undefined, expires: number, // seconds - style: "path" | "virtualHost" | "bucketEndpoint", + style: UrlStyle, opt: GetAdapterOptionParam, ): Promise { const deadline = new Date(); @@ -909,7 +922,7 @@ export async function signatureUrls( items: FileItem.Item[], domain: Domain | undefined, expires: number, - style: "path" | "virtualHost" | "bucketEndpoint", + style: UrlStyle, progressFn: (progress: Progress) => void, onEachSuccess: (file: FileItem.File, url: URL) => void, onError: (err: any) => void, @@ -969,4 +982,3 @@ export async function signatureUrls( return results; } } - diff --git a/src/renderer/pages/browse/files/index.tsx b/src/renderer/pages/browse/files/index.tsx index 6295965b..58cfe190 100644 --- a/src/renderer/pages/browse/files/index.tsx +++ b/src/renderer/pages/browse/files/index.tsx @@ -14,8 +14,8 @@ import {useAuth} from "@renderer/modules/auth"; import {KodoNavigator, useKodoNavigator} from "@renderer/modules/kodo-address"; import {ContentViewStyle, appPreferences, useEndpointConfig} from "@renderer/modules/user-config-store"; -import {BucketItem, FileItem, isAccelerateUploadingAvailable} from "@renderer/modules/qiniu-client"; -import {DomainAdapter, useLoadDomains, useLoadFiles} from "@renderer/modules/qiniu-client-hooks"; +import {BucketItem, FileItem, getStyleForSignature, isAccelerateUploadingAvailable} from "@renderer/modules/qiniu-client"; +import {DomainAdapter, NON_OWNED_DOMAIN, useLoadDomains, useLoadFiles} from "@renderer/modules/qiniu-client-hooks"; import ipcDownloadManager from "@renderer/modules/electron-ipc-manages/ipc-download-manager"; import * as AuditLog from "@renderer/modules/audit-log"; import {useFileOperation} from "@renderer/modules/file-operation"; @@ -38,7 +38,10 @@ interface FilesProps { const Files: React.FC = (props) => { const {currentLanguage, translate} = useI18n(); const {currentUser, shareSession} = useAuth(); - const {bucketGrantedPermission} = useFileOperation(); + const { + bucketPreferBackendMode: preferBackendMode, + bucketGrantedPermission, + } = useFileOperation(); const { state: appPreferencesState, @@ -350,13 +353,21 @@ const Files: React.FC = (props) => { to: destDirectoryPath, from: remoteObjects.map(i => i.key), }); + const domain = selectedDomain.name === NON_OWNED_DOMAIN.name + ? undefined + : selectedDomain; ipcDownloadManager.addJobs({ remoteObjects, destPath: destDirectoryPath, downloadOptions: { region: currentRegion.s3Id, bucket: currentBucket.name, - domain: selectedDomain, + domain: domain, + urlStyle: getStyleForSignature({ + domain: domain, + preferBackendMode, + currentEndpointType: currentUser.endpointType, + }), isOverwrite: appPreferencesData.overwriteDownloadEnabled, storageClasses: currentRegion.storageClasses, // userNatureLanguage needs mid-dash but i18n using lo_dash