[fix] azure command options

This commit is contained in:
PauI Ostrovckij
2025-08-07 19:06:33 +03:00
parent 45b9a09b95
commit a290c179b2
2 changed files with 32 additions and 24 deletions

View File

@ -7,6 +7,7 @@ on:
- 'tests/integration/withServerInstance/storage.tests.js' - 'tests/integration/withServerInstance/storage.tests.js'
- 'Common/sources/storage/**' - 'Common/sources/storage/**'
- 'DocService/sources/routes/static.js' - 'DocService/sources/routes/static.js'
- '.github/workflows/azureStorageTests.yml'
jobs: jobs:
azure-storage-tests: azure-storage-tests:
@ -62,6 +63,18 @@ jobs:
}, },
"persistentStorage": { "persistentStorage": {
"storageFolderName": "files/persistent" "storageFolderName": "files/persistent"
},
"commandOptions": {
"az": {
"uploadData": {},
"uploadStream": {},
"download": {},
"syncCopyFromURL": {},
"listBlobsFlat": {
"maxPageSize": 1000
},
"deleteBlob": {}
}
} }
} }
EOF EOF

View File

@ -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 {Object} storageCfg - Storage configuration
* @param {string} commandType - uploadData, uploadStream, download, etc. * @param {string} commandType - uploadData, uploadStream, download, etc.
* @returns {Object|undefined} Merged options or undefined if empty
*/ */
function applyCommandOptions(input, storageCfg, commandType) { function applyCommandOptions(baseOptions, storageCfg, commandType) {
if (!storageCfg.commandOptions) return;
if (storageCfg.commandOptions.az && storageCfg.commandOptions.az[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 = []) { async function listObjectsExec(storageCfg, prefix, output = []) {
@ -91,8 +94,8 @@ async function listObjectsExec(storageCfg, prefix, output = []) {
const storageFolderName = storageCfg.storageFolderName; const storageFolderName = storageCfg.storageFolderName;
const prefixWithFolder = storageFolderName ? `${storageFolderName}/${prefix}` : prefix; const prefixWithFolder = storageFolderName ? `${storageFolderName}/${prefix}` : prefix;
const listOptions = {prefix: prefixWithFolder}; const baseOptions = {prefix: prefixWithFolder};
applyCommandOptions(listOptions, storageCfg, 'listBlobsFlat'); const listOptions = applyCommandOptions(baseOptions, storageCfg, 'listBlobsFlat');
for await (const blob of containerClient.listBlobsFlat(listOptions)) { for await (const blob of containerClient.listBlobsFlat(listOptions)) {
const relativePath = storageFolderName ? const relativePath = storageFolderName ?
@ -104,8 +107,7 @@ async function listObjectsExec(storageCfg, prefix, output = []) {
async function deleteObjectsHelp(storageCfg, aKeys) { async function deleteObjectsHelp(storageCfg, aKeys) {
const containerClient = getContainerClient(storageCfg); const containerClient = getContainerClient(storageCfg);
const deleteOptions = {}; const deleteOptions = applyCommandOptions({}, storageCfg, 'deleteBlob');
applyCommandOptions(deleteOptions, storageCfg, 'deleteBlob');
await Promise.all( await Promise.all(
aKeys.map(key => { aKeys.map(key => {
return containerClient.deleteBlob(key.Key, deleteOptions); return containerClient.deleteBlob(key.Key, deleteOptions);
@ -121,16 +123,14 @@ async function headObject(storageCfg, strPath) {
async function getObject(storageCfg, strPath) { async function getObject(storageCfg, strPath) {
const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath)); const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath));
const options = {}; const options = applyCommandOptions({}, storageCfg, 'download');
applyCommandOptions(options, storageCfg, 'download');
const response = await blobClient.download(options); const response = await blobClient.download(options);
return await utils.stream2Buffer(response.readableStreamBody); return await utils.stream2Buffer(response.readableStreamBody);
} }
async function createReadStream(storageCfg, strPath) { async function createReadStream(storageCfg, strPath) {
const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath)); const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath));
const options = {}; const options = applyCommandOptions({}, storageCfg, 'download');
applyCommandOptions(options, storageCfg, 'download');
const response = await blobClient.download(options); const response = await blobClient.download(options);
return { return {
contentLength: response.contentLength, contentLength: response.contentLength,
@ -141,20 +141,17 @@ async function createReadStream(storageCfg, strPath) {
async function putObject(storageCfg, strPath, buffer, contentLength) { async function putObject(storageCfg, strPath, buffer, contentLength) {
const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath)); const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath));
const uploadOptions = { const baseOptions = {
blobHTTPHeaders: { blobHTTPHeaders: {
contentType: mime.getType(strPath), contentType: mime.getType(strPath),
contentDisposition: utils.getContentDisposition(path.basename(strPath)) contentDisposition: utils.getContentDisposition(path.basename(strPath))
} }
}; };
const uploadOptions = applyCommandOptions(baseOptions, storageCfg, 'uploadData');
if (buffer instanceof Buffer) { if (buffer instanceof Buffer) {
// Handle Buffer upload
applyCommandOptions(uploadOptions, storageCfg, 'uploadData');
await blobClient.uploadData(buffer, uploadOptions); await blobClient.uploadData(buffer, uploadOptions);
} else if (typeof buffer.pipe === 'function') { } else if (typeof buffer.pipe === 'function') {
// Handle Stream upload
applyCommandOptions(uploadOptions, storageCfg, 'uploadStream');
await blobClient.uploadStream(buffer, undefined, undefined, uploadOptions); await blobClient.uploadStream(buffer, undefined, undefined, uploadOptions);
} else { } else {
throw new TypeError('Input must be Buffer or Readable stream'); 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)) contentDisposition: utils.getContentDisposition(path.basename(strPath))
} }
}; };
applyCommandOptions(uploadOptions, storageCfg, 'uploadStream'); const finalOptions = applyCommandOptions(uploadOptions, storageCfg, 'uploadStream');
await blockBlobClient.uploadStream( await blockBlobClient.uploadStream(
uploadStream, uploadStream,
undefined, undefined,
undefined, undefined,
uploadOptions finalOptions
); );
} }
@ -192,8 +189,7 @@ async function copyObject(storageCfgSrc, storageCfgDst, sourceKey, destinationKe
expiresOn: new Date(Date.now() + 3600 * 1000) expiresOn: new Date(Date.now() + 3600 * 1000)
}, new StorageSharedKeyCredential(storageCfgSrc.accessKeyId, storageCfgSrc.secretAccessKey)).toString(); }, new StorageSharedKeyCredential(storageCfgSrc.accessKeyId, storageCfgSrc.secretAccessKey)).toString();
const copyOptions = {}; const copyOptions = applyCommandOptions({}, storageCfgDst, 'syncCopyFromURL');
applyCommandOptions(copyOptions, storageCfgDst, 'syncCopyFromURL');
await destBlobClient.syncCopyFromURL(`${sourceBlobClient.url}?${sasToken}`, copyOptions); await destBlobClient.syncCopyFromURL(`${sourceBlobClient.url}?${sasToken}`, copyOptions);
} }
@ -203,8 +199,7 @@ async function listObjects(storageCfg, strPath) {
async function deleteObject(storageCfg, strPath) { async function deleteObject(storageCfg, strPath) {
const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath)); const blobClient = getBlobClient(storageCfg, getFilePath(storageCfg, strPath));
const options = {}; const options = applyCommandOptions({}, storageCfg, 'deleteBlob');
applyCommandOptions(options, storageCfg, 'deleteBlob');
await blobClient.delete(options); await blobClient.delete(options);
} }