From a290c179b2da030b199993303117d1d52c1b3403 Mon Sep 17 00:00:00 2001 From: PauI Ostrovckij Date: Thu, 7 Aug 2025 19:06:33 +0300 Subject: [PATCH] [fix] azure command options --- .github/workflows/azureStorageTests.yml | 13 ++++++++ Common/sources/storage/storage-az.js | 43 +++++++++++-------------- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/.github/workflows/azureStorageTests.yml b/.github/workflows/azureStorageTests.yml index ad58f41b..ae54a493 100644 --- a/.github/workflows/azureStorageTests.yml +++ b/.github/workflows/azureStorageTests.yml @@ -7,6 +7,7 @@ on: - 'tests/integration/withServerInstance/storage.tests.js' - 'Common/sources/storage/**' - 'DocService/sources/routes/static.js' + - '.github/workflows/azureStorageTests.yml' jobs: azure-storage-tests: @@ -62,6 +63,18 @@ jobs: }, "persistentStorage": { "storageFolderName": "files/persistent" + }, + "commandOptions": { + "az": { + "uploadData": {}, + "uploadStream": {}, + "download": {}, + "syncCopyFromURL": {}, + "listBlobsFlat": { + "maxPageSize": 1000 + }, + "deleteBlob": {} + } } } EOF diff --git a/Common/sources/storage/storage-az.js b/Common/sources/storage/storage-az.js index d4bf9708..2ab31972 100644 --- a/Common/sources/storage/storage-az.js +++ b/Common/sources/storage/storage-az.js @@ -74,16 +74,19 @@ function getFilePath(storageCfg, strPath) { } /** - * @param {Object} input - Azure Blob command options + * @param {Object} baseOptions - Base options object * @param {Object} storageCfg - Storage configuration * @param {string} commandType - uploadData, uploadStream, download, etc. + * @returns {Object|undefined} Merged options or undefined if empty */ -function applyCommandOptions(input, storageCfg, commandType) { - if (!storageCfg.commandOptions) return; - +function applyCommandOptions(baseOptions, storageCfg, commandType) { if (storageCfg.commandOptions.az && storageCfg.commandOptions.az[commandType]) { - Object.assign(input, storageCfg.commandOptions.az[commandType]); + const configOptions = storageCfg.commandOptions.az[commandType]; + if (configOptions && Object.keys(configOptions).length > 0) { + return {...baseOptions, ...configOptions}; + } } + return Object.keys(baseOptions).length > 0 ? baseOptions : undefined; } async function listObjectsExec(storageCfg, prefix, output = []) { @@ -91,8 +94,8 @@ async function listObjectsExec(storageCfg, prefix, output = []) { const storageFolderName = storageCfg.storageFolderName; const prefixWithFolder = storageFolderName ? `${storageFolderName}/${prefix}` : prefix; - const listOptions = {prefix: prefixWithFolder}; - applyCommandOptions(listOptions, storageCfg, 'listBlobsFlat'); + const baseOptions = {prefix: prefixWithFolder}; + const listOptions = applyCommandOptions(baseOptions, storageCfg, 'listBlobsFlat'); for await (const blob of containerClient.listBlobsFlat(listOptions)) { const relativePath = storageFolderName ? @@ -104,8 +107,7 @@ async function listObjectsExec(storageCfg, prefix, output = []) { async function deleteObjectsHelp(storageCfg, aKeys) { const containerClient = getContainerClient(storageCfg); - const deleteOptions = {}; - applyCommandOptions(deleteOptions, storageCfg, 'deleteBlob'); + const deleteOptions = applyCommandOptions({}, storageCfg, 'deleteBlob'); await Promise.all( aKeys.map(key => { return containerClient.deleteBlob(key.Key, deleteOptions); @@ -121,16 +123,14 @@ async function headObject(storageCfg, strPath) { async function getObject(storageCfg, strPath) { const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath)); - const options = {}; - applyCommandOptions(options, storageCfg, 'download'); + const options = applyCommandOptions({}, storageCfg, 'download'); const response = await blobClient.download(options); return await utils.stream2Buffer(response.readableStreamBody); } async function createReadStream(storageCfg, strPath) { const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath)); - const options = {}; - applyCommandOptions(options, storageCfg, 'download'); + const options = applyCommandOptions({}, storageCfg, 'download'); const response = await blobClient.download(options); return { contentLength: response.contentLength, @@ -141,20 +141,17 @@ async function createReadStream(storageCfg, strPath) { async function putObject(storageCfg, strPath, buffer, contentLength) { const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath)); - const uploadOptions = { + const baseOptions = { blobHTTPHeaders: { contentType: mime.getType(strPath), contentDisposition: utils.getContentDisposition(path.basename(strPath)) } }; + const uploadOptions = applyCommandOptions(baseOptions, storageCfg, 'uploadData'); if (buffer instanceof Buffer) { - // Handle Buffer upload - applyCommandOptions(uploadOptions, storageCfg, 'uploadData'); await blobClient.uploadData(buffer, uploadOptions); } else if (typeof buffer.pipe === 'function') { - // Handle Stream upload - applyCommandOptions(uploadOptions, storageCfg, 'uploadStream'); await blobClient.uploadStream(buffer, undefined, undefined, uploadOptions); } else { throw new TypeError('Input must be Buffer or Readable stream'); @@ -171,13 +168,13 @@ async function uploadObject(storageCfg, strPath, filePath) { contentDisposition: utils.getContentDisposition(path.basename(strPath)) } }; - applyCommandOptions(uploadOptions, storageCfg, 'uploadStream'); + const finalOptions = applyCommandOptions(uploadOptions, storageCfg, 'uploadStream'); await blockBlobClient.uploadStream( uploadStream, undefined, undefined, - uploadOptions + finalOptions ); } @@ -192,8 +189,7 @@ async function copyObject(storageCfgSrc, storageCfgDst, sourceKey, destinationKe expiresOn: new Date(Date.now() + 3600 * 1000) }, new StorageSharedKeyCredential(storageCfgSrc.accessKeyId, storageCfgSrc.secretAccessKey)).toString(); - const copyOptions = {}; - applyCommandOptions(copyOptions, storageCfgDst, 'syncCopyFromURL'); + const copyOptions = applyCommandOptions({}, storageCfgDst, 'syncCopyFromURL'); await destBlobClient.syncCopyFromURL(`${sourceBlobClient.url}?${sasToken}`, copyOptions); } @@ -203,8 +199,7 @@ async function listObjects(storageCfg, strPath) { async function deleteObject(storageCfg, strPath) { const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath)); - const options = {}; - applyCommandOptions(options, storageCfg, 'deleteBlob'); + const options = applyCommandOptions({}, storageCfg, 'deleteBlob'); await blobClient.delete(options); }