119 lines
3.1 KiB
TypeScript
119 lines
3.1 KiB
TypeScript
import path from "node:path";
|
|
import fs from "node:fs";
|
|
import { uploadDicomFile } from "../../core/pacs";
|
|
|
|
/**
|
|
* 检查文件是否为 DICOM 文件(通过 Magic Number 判断)
|
|
* @param filePath 文件路径
|
|
* @returns 是否为 DICOM 文件
|
|
*/
|
|
const isDICOMFile = async (filePath: string) => {
|
|
try {
|
|
// 打开文件以进行读取
|
|
const fileHandle = await fs.promises.open(filePath, "r");
|
|
const buffer = Buffer.alloc(132); // 创建一个 132 字节的缓冲区
|
|
|
|
// 从文件中读取前 132 个字节
|
|
await fileHandle.read(buffer, 0, 132, 0);
|
|
await fileHandle.close(); // 关闭文件
|
|
|
|
// 检查 "DICM" 标识 (偏移 128-131 字节)
|
|
const magicNumber = buffer.toString("utf-8", 128, 132);
|
|
return magicNumber === "DICM";
|
|
} catch (error) {
|
|
console.error(`Error reading file ${filePath}:`, error);
|
|
return false;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* 定义一个异步函数来递归地查找.dcm文件
|
|
* @param dir
|
|
* @param fileList
|
|
* @returns
|
|
*/
|
|
export const filterDicoms = async (
|
|
dir: string,
|
|
fileList: string[] = []
|
|
): Promise<string[]> => {
|
|
const files = await fs.promises.readdir(dir, { withFileTypes: true });
|
|
await Promise.all(
|
|
files.map(async (file) => {
|
|
const filePath = path.join(dir, file.name);
|
|
if (file.isDirectory()) {
|
|
await filterDicoms(filePath, fileList); // 递归调用以遍历子目录
|
|
} else if (await isDICOMFile(filePath)) {
|
|
fileList.push(filePath);
|
|
}
|
|
})
|
|
);
|
|
return fileList;
|
|
};
|
|
|
|
interface UploadFilesInBatchesParams {
|
|
filePaths: string[];
|
|
batchSize: number;
|
|
orthancUrl?: string;
|
|
feedback?: (detail: {
|
|
progress: number;
|
|
totalSuccess: number;
|
|
totalFailed: number;
|
|
}) => void;
|
|
}
|
|
|
|
/**
|
|
* 批量上传文件,并提供进度更新。
|
|
* @param filePaths 文件路径数组。
|
|
* @param batchSize 每批上传的文件数量。
|
|
* @param orthancUrl Orthanc 服务器的 URL。
|
|
* @param feedback 每批处理完成后调用的回调函数。
|
|
*/
|
|
export const uploadFilesInBatches = async ({
|
|
filePaths,
|
|
batchSize,
|
|
feedback,
|
|
}: UploadFilesInBatchesParams) => {
|
|
const totalStartTime = Date.now();
|
|
let totalSuccess = 0;
|
|
let totalFailed = 0;
|
|
const totalFiles = filePaths.length;
|
|
|
|
for (let i = 0; i < totalFiles; i += batchSize) {
|
|
const batch = filePaths.slice(i, i + batchSize);
|
|
const batchResults = await Promise.allSettled(
|
|
batch.map((filePath) => uploadDicomFile(filePath))
|
|
);
|
|
|
|
batchResults.forEach((result) => {
|
|
if (result.status === "fulfilled" && result.value) {
|
|
totalSuccess++;
|
|
} else {
|
|
totalFailed++;
|
|
}
|
|
});
|
|
|
|
const actualProcessed = i + batch.length;
|
|
const progress = Math.round((actualProcessed / totalFiles) * 100);
|
|
const detail = {
|
|
progress: Math.min(progress, 100),
|
|
totalSuccess,
|
|
totalFailed,
|
|
};
|
|
if (feedback) feedback(detail);
|
|
}
|
|
|
|
const totalEndTime = Date.now();
|
|
console.log(
|
|
`[上传序列] Success: ${totalSuccess}, Failed: ${totalFailed}, Total upload time: ${
|
|
totalEndTime - totalStartTime
|
|
} ms`
|
|
);
|
|
|
|
return {
|
|
totalSuccess,
|
|
totalFailed,
|
|
totalTime: totalEndTime - totalStartTime,
|
|
progress: 100,
|
|
};
|
|
};
|