Skip to content

Commit

Permalink
feat: enhance path structure in ZIP file
Browse files Browse the repository at this point in the history
- Add a `spawn` option to 7zip that allows us to set the working directory.
- Add the `#getZipFile` method to handle the creation of the zip file
- Modify the `getZipOfxxxDICOMFiles` method
to use the `#getZipFile` method and adjust the images path list
- Refactor the ZipFactory class to be an abstract class
- Create the `StudyZipFactory` class that extends ZipFactory and implement the compressToZipFile method
- Create the `SeriesZipFactory` class that extends ZipFactory and implement the compressToZipFile method
- Create the `InstanceZipFactory` class that extends ZipFactory and implement the compressToZipFile method
- Add the `#adjustImagesPathList` method to set relative path in image path
  • Loading branch information
Chinlinlee committed Feb 8, 2024
1 parent aef4820 commit d8b1e51
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 12 deletions.
79 changes: 69 additions & 10 deletions api/dicom-web/controller/WADO-RS/service/WADOZip.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class WADOZip {
this.seriesUID = this.requestParams.seriesUID;
this.instanceUID = this.requestParams.instanceUID;
this.res = iRes;

/** @type { ZipFactory } */
this.zipFactory = undefined;
}

setHeaders(uid) {
Expand All @@ -23,7 +26,10 @@ class WADOZip {
async getZipOfStudyDICOMFiles() {
let imagesPathList = await StudyModel.getPathGroupOfInstances(this.requestParams);
if (imagesPathList.length > 0) {
await this.#streamZipToResponse(imagesPathList);
this.zipFactory = StudyZipFactory;
await this.#adjustImagesPathList(imagesPathList);
let zipFile = await this.#getZipFile(imagesPathList);
await this.#streamZipToResponse(zipFile);

return {
status: true,
Expand All @@ -41,7 +47,10 @@ class WADOZip {
async getZipOfSeriesDICOMFiles() {
let imagesPathList = await SeriesModel.getPathGroupOfInstances(this.requestParams);
if (imagesPathList.length > 0) {
await this.#streamZipToResponse(imagesPathList);
this.zipFactory = SeriesZipFactory;
await this.#adjustImagesPathList(imagesPathList);
let zipFile = await this.#getZipFile(imagesPathList);
await this.#streamZipToResponse(zipFile);
return {
status: true,
code: 200,
Expand All @@ -58,7 +67,10 @@ class WADOZip {
async getZipOfInstanceDICOMFile() {
let imagePath = await InstanceModel.getPathOfInstance(this.requestParams);
if (imagePath) {
await this.#streamZipToResponse([imagePath]);
this.zipFactory = InstanceZipFactory;
await this.#adjustImagesPathList([imagePath]);
let zipFile = await this.#getZipFile([imagePath]);
await this.#streamZipToResponse(zipFile);
return {
status: true,
code: 200,
Expand All @@ -72,32 +84,79 @@ class WADOZip {
};
}

async #streamZipToResponse(imagesPathList) {
async #getZipFile(imagesPathList) {
let randomFilename = uuidV4();
this.setHeaders(randomFilename);

let zipFile = path.join(__dirname, `../../../../../tempUploadFiles/${randomFilename}.zip`);
await ZipFactory.compressToZipFile(zipFile, imagesPathList);
await this.zipFactory.compressToZipFile(zipFile, imagesPathList);

return zipFile;
}

/**
*
* @param {string} zipFile
*/
async #streamZipToResponse(zipFile) {
this.setHeaders(path.basename(zipFile, ".zip"));

fs.createReadStream(zipFile).pipe(this.res);

this.res.on("finish", () => {
fs.unlink(zipFile, () => { });
});
}

async #adjustImagesPathList(imagesPathList) {
for (let i = 0; i < imagesPathList.length; i++) {
let imagesPath = imagesPathList[i];
let instancePathSplit = imagesPath.instancePath.split(/[\/|\\]/gm);
let relativePath = instancePathSplit.slice(instancePathSplit.length - 3, instancePathSplit.length).join("/");
imagesPath.relativePath = relativePath;
}
}
}

class ZipFactory {
/**
*
* @param {string} zipFile
* @param {import("@root/utils/typeDef/dicomImage").ImagePathObj[]} imagePaths
*/
static async compressToZipFile(zipFile, imagePaths) {
let sevenZip = new SevenZip("zip", undefined, zipFile);
throw new Error("Not implement");
}
}

class StudyZipFactory extends ZipFactory {
static async compressToZipFile(zipFile, imagePaths) {
let sevenZip = new SevenZip("zip", undefined, zipFile);

for (let i = 0; i < imagePaths.length; i++) {
sevenZip.addCmd(imagePaths[i].instancePath);
sevenZip.addCmd(imagePaths[i].relativePath);
}

// prevent same filename
if (imagePaths.length >= 2)
sevenZip.useFullyQualifiedFilePaths();
sevenZip.overwrite("a");

let instancePathSplit = imagePaths[0].instancePath.split(/[\/|\\]/gm);
// Study Folder
let cwd = path.resolve(instancePathSplit.slice(0, instancePathSplit.length - 3).join("/"));
await sevenZip.pack({
cwd
});
}
}

class SeriesZipFactory extends ZipFactory {
static async compressToZipFile(zipFile, imagePaths) {
return StudyZipFactory.compressToZipFile(zipFile, imagePaths);
}
}

class InstanceZipFactory extends ZipFactory {
static async compressToZipFile(zipFile, imagePaths) {
let sevenZip = new SevenZip("zip", imagePaths[0].instancePath, zipFile);

sevenZip.overwrite("a");
await sevenZip.pack();
Expand Down
5 changes: 3 additions & 2 deletions utils/sevenZip.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,13 @@ class SevenZip {
}

/**
* @param { import('child_process').SpawnOptionsWithoutStdio } spawnOpts
* run 7zip command:
*
* 7z a -t{type} {dest} {source} {...additionalCmd}
* @returns
*/
async pack() {
async pack(spawnOpts) {
return new Promise((resolve, reject) => {
let cmd = ["a", `-t${this.#type}`, this.#dest, this.#source, ...this.cmd];
if (!this.#source) cmd = ["a", `-t${this.#type}`, this.#dest, ...this.cmd];
Expand All @@ -78,7 +79,7 @@ class SevenZip {
}

resolve();
});
}, spawnOpts);
});
}
}
Expand Down

0 comments on commit d8b1e51

Please sign in to comment.