@ubercode/dcmtk 0.8.2 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dicom.cjs +18 -4
- package/dist/dicom.cjs.map +1 -1
- package/dist/dicom.js +18 -4
- package/dist/dicom.js.map +1 -1
- package/dist/{index-B13DmBRs.d.cts → index-Bq947ilN.d.cts} +1 -0
- package/dist/{index-CCgNgve7.d.ts → index-C9oo35ZO.d.ts} +1 -0
- package/dist/index.cjs +363 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +230 -3
- package/dist/index.d.ts +230 -3
- package/dist/index.js +362 -11
- package/dist/index.js.map +1 -1
- package/dist/servers.cjs +20 -5
- package/dist/servers.cjs.map +1 -1
- package/dist/servers.d.cts +1 -1
- package/dist/servers.d.ts +1 -1
- package/dist/servers.js +22 -6
- package/dist/servers.js.map +1 -1
- package/dist/tools.cjs +18 -3
- package/dist/tools.cjs.map +1 -1
- package/dist/tools.js +18 -3
- package/dist/tools.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,12 +6,13 @@ import { spawn, execSync } from 'child_process';
|
|
|
6
6
|
import kill from 'tree-kill';
|
|
7
7
|
import { EventEmitter } from 'events';
|
|
8
8
|
import { stderr, tryCatch } from 'stderr-lib';
|
|
9
|
-
import { XMLParser } from 'fast-xml-parser';
|
|
10
9
|
import * as fs from 'fs/promises';
|
|
11
|
-
import {
|
|
12
|
-
import * as net from 'net';
|
|
10
|
+
import { mkdir, stat, rm, copyFile, unlink, mkdtemp, readdir } from 'fs/promises';
|
|
13
11
|
import * as os from 'os';
|
|
14
12
|
import { tmpdir } from 'os';
|
|
13
|
+
import { XMLParser } from 'fast-xml-parser';
|
|
14
|
+
import * as net from 'net';
|
|
15
|
+
import { randomUUID } from 'crypto';
|
|
15
16
|
|
|
16
17
|
var __defProp = Object.defineProperty;
|
|
17
18
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
@@ -31476,13 +31477,26 @@ async function tryDirectPath(inputPath, timeoutMs, signal, verbosity) {
|
|
|
31476
31477
|
if (!jsonBinary.ok) {
|
|
31477
31478
|
return err(jsonBinary.error);
|
|
31478
31479
|
}
|
|
31479
|
-
const
|
|
31480
|
-
const
|
|
31480
|
+
const bulkDir = await createBulkTempDir();
|
|
31481
|
+
const directArgs = [...buildVerbosityArgs(verbosity), "+b", "+bd", bulkDir, inputPath];
|
|
31482
|
+
try {
|
|
31483
|
+
const execOpts = signal !== void 0 ? { timeoutMs, signal } : { timeoutMs };
|
|
31484
|
+
return await execAndParse(jsonBinary.value, directArgs, inputPath, execOpts);
|
|
31485
|
+
} finally {
|
|
31486
|
+
rm(bulkDir, { recursive: true, force: true }).catch(() => {
|
|
31487
|
+
});
|
|
31488
|
+
}
|
|
31489
|
+
}
|
|
31490
|
+
async function createBulkTempDir() {
|
|
31491
|
+
return mkdtemp(join(tmpdir(), "dcm2json-bulk-"));
|
|
31492
|
+
}
|
|
31493
|
+
async function execAndParse(binary, args, inputPath, execOpts) {
|
|
31494
|
+
const result = await execCommand(binary, args, execOpts);
|
|
31481
31495
|
if (!result.ok) {
|
|
31482
31496
|
return err(result.error);
|
|
31483
31497
|
}
|
|
31484
31498
|
if (result.value.exitCode !== 0) {
|
|
31485
|
-
return err(createToolError("dcm2json",
|
|
31499
|
+
return err(createToolError("dcm2json", args, result.value.exitCode, result.value.stderr));
|
|
31486
31500
|
}
|
|
31487
31501
|
try {
|
|
31488
31502
|
const repaired = repairJson(result.value.stdout);
|
|
@@ -36576,7 +36590,7 @@ var DicomReceiver = class _DicomReceiver extends EventEmitter {
|
|
|
36576
36590
|
acseTimeout: this.options.acseTimeout,
|
|
36577
36591
|
dimseTimeout: this.options.dimseTimeout,
|
|
36578
36592
|
maxPdu: this.options.maxPdu,
|
|
36579
|
-
filenameMode: this.options.filenameMode,
|
|
36593
|
+
filenameMode: this.options.filenameMode ?? "unique",
|
|
36580
36594
|
filenameExtension: this.options.filenameExtension,
|
|
36581
36595
|
storageMode: this.options.storageMode
|
|
36582
36596
|
});
|
|
@@ -36691,8 +36705,9 @@ var DicomReceiver = class _DicomReceiver extends EventEmitter {
|
|
|
36691
36705
|
const assocDir = worker.associationDir;
|
|
36692
36706
|
const moveResult = await moveFile(srcPath, destPath);
|
|
36693
36707
|
const finalPath = moveResult.ok ? destPath : srcPath;
|
|
36708
|
+
const fileSize = await statFileSafe(finalPath);
|
|
36694
36709
|
worker.files.push(finalPath);
|
|
36695
|
-
worker.fileSizes.push(
|
|
36710
|
+
worker.fileSizes.push(fileSize);
|
|
36696
36711
|
const openResult = await DicomInstance.open(finalPath);
|
|
36697
36712
|
if (!openResult.ok) {
|
|
36698
36713
|
this.emit("error", {
|
|
@@ -36708,6 +36723,7 @@ var DicomReceiver = class _DicomReceiver extends EventEmitter {
|
|
|
36708
36723
|
}
|
|
36709
36724
|
this.emit("FILE_RECEIVED", {
|
|
36710
36725
|
filePath: finalPath,
|
|
36726
|
+
fileSize,
|
|
36711
36727
|
associationId: assocId,
|
|
36712
36728
|
associationDir: assocDir,
|
|
36713
36729
|
callingAE: data.callingAE,
|
|
@@ -36856,8 +36872,8 @@ async function moveFile(src, dest) {
|
|
|
36856
36872
|
}
|
|
36857
36873
|
async function statFileSafe(filePath) {
|
|
36858
36874
|
try {
|
|
36859
|
-
const
|
|
36860
|
-
return
|
|
36875
|
+
const stat4 = await fs.stat(filePath);
|
|
36876
|
+
return stat4.size;
|
|
36861
36877
|
} catch {
|
|
36862
36878
|
return 0;
|
|
36863
36879
|
}
|
|
@@ -38268,6 +38284,341 @@ async function batch(items, operation, options) {
|
|
|
38268
38284
|
return { results: state.results, succeeded: state.succeeded, failed: state.failed };
|
|
38269
38285
|
}
|
|
38270
38286
|
|
|
38287
|
+
// src/testing/types.ts
|
|
38288
|
+
var HammerPhase = {
|
|
38289
|
+
/** File generation phase (copy + modify). */
|
|
38290
|
+
GENERATE: "generate",
|
|
38291
|
+
/** File sending phase (dcmsend). */
|
|
38292
|
+
SEND: "send"
|
|
38293
|
+
};
|
|
38294
|
+
|
|
38295
|
+
// src/testing/DicomHammer.ts
|
|
38296
|
+
var DEFAULT_FILE_COUNT = 100;
|
|
38297
|
+
var MAX_FILE_COUNT = 1e5;
|
|
38298
|
+
var DEFAULT_CONCURRENCY2 = 4;
|
|
38299
|
+
var MAX_CONCURRENCY2 = 64;
|
|
38300
|
+
var DEFAULT_CALLING_AE = "HAMMER";
|
|
38301
|
+
var DEFAULT_CALLED_AE = "ANY-SCP";
|
|
38302
|
+
var DICOM_UID_ROOT = "2.25.";
|
|
38303
|
+
var DicomHammerOptionsSchema = z.object({
|
|
38304
|
+
sourceFile: z.string().min(1),
|
|
38305
|
+
host: z.string().min(1),
|
|
38306
|
+
port: z.number().int().min(1).max(65535),
|
|
38307
|
+
callingAETitle: z.string().min(1).max(16).refine(isValidAETitle, { message: "AE Title contains invalid characters" }).optional(),
|
|
38308
|
+
calledAETitle: z.string().min(1).max(16).refine(isValidAETitle, { message: "AE Title contains invalid characters" }).optional(),
|
|
38309
|
+
fileCount: z.number().int().min(1).max(MAX_FILE_COUNT).optional(),
|
|
38310
|
+
concurrency: z.number().int().min(1).max(MAX_CONCURRENCY2).optional(),
|
|
38311
|
+
delayMs: z.number().int().min(0).optional(),
|
|
38312
|
+
institution: z.string().min(1).optional(),
|
|
38313
|
+
erasePrivateTags: z.boolean().optional(),
|
|
38314
|
+
modifications: z.array(z.object({ tag: z.string().min(1), value: z.string() })).optional(),
|
|
38315
|
+
timeoutMs: z.number().int().positive().optional(),
|
|
38316
|
+
signal: z.instanceof(AbortSignal).optional(),
|
|
38317
|
+
outputDir: z.string().min(1).optional(),
|
|
38318
|
+
noHalt: z.boolean().optional()
|
|
38319
|
+
}).strict();
|
|
38320
|
+
function resolveNetworkOptions(options) {
|
|
38321
|
+
return {
|
|
38322
|
+
host: options.host,
|
|
38323
|
+
port: options.port,
|
|
38324
|
+
callingAETitle: options.callingAETitle ?? DEFAULT_CALLING_AE,
|
|
38325
|
+
calledAETitle: options.calledAETitle ?? DEFAULT_CALLED_AE,
|
|
38326
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
38327
|
+
noHalt: options.noHalt ?? true
|
|
38328
|
+
};
|
|
38329
|
+
}
|
|
38330
|
+
function resolveOptions(options) {
|
|
38331
|
+
return {
|
|
38332
|
+
sourceFile: options.sourceFile,
|
|
38333
|
+
...resolveNetworkOptions(options),
|
|
38334
|
+
fileCount: options.fileCount ?? DEFAULT_FILE_COUNT,
|
|
38335
|
+
concurrency: options.concurrency ?? DEFAULT_CONCURRENCY2,
|
|
38336
|
+
delayMs: options.delayMs ?? 0,
|
|
38337
|
+
institution: options.institution,
|
|
38338
|
+
erasePrivateTags: options.erasePrivateTags ?? false,
|
|
38339
|
+
modifications: options.modifications ?? [],
|
|
38340
|
+
signal: options.signal,
|
|
38341
|
+
outputDir: options.outputDir ?? tmpdir()
|
|
38342
|
+
};
|
|
38343
|
+
}
|
|
38344
|
+
function generateUid() {
|
|
38345
|
+
const hex = randomUUID().replace(/-/g, "");
|
|
38346
|
+
const decimal = BigInt("0x" + hex).toString(10);
|
|
38347
|
+
return DICOM_UID_ROOT + decimal;
|
|
38348
|
+
}
|
|
38349
|
+
function formatDate() {
|
|
38350
|
+
const d = /* @__PURE__ */ new Date();
|
|
38351
|
+
const yyyy = String(d.getFullYear());
|
|
38352
|
+
const mm = String(d.getMonth() + 1).padStart(2, "0");
|
|
38353
|
+
const dd = String(d.getDate()).padStart(2, "0");
|
|
38354
|
+
return yyyy + mm + dd;
|
|
38355
|
+
}
|
|
38356
|
+
function buildModifications(index, opts) {
|
|
38357
|
+
const mods = [
|
|
38358
|
+
{ tag: "(0020,000D)", value: generateUid() },
|
|
38359
|
+
{ tag: "(0020,000E)", value: generateUid() },
|
|
38360
|
+
{ tag: "(0008,0018)", value: generateUid() },
|
|
38361
|
+
{ tag: "(0008,0020)", value: formatDate() },
|
|
38362
|
+
{ tag: "(0008,0050)", value: `HAMMER-${String(index + 1).padStart(6, "0")}` }
|
|
38363
|
+
];
|
|
38364
|
+
if (opts.institution !== void 0) {
|
|
38365
|
+
mods.push({ tag: "(0008,0080)", value: opts.institution });
|
|
38366
|
+
}
|
|
38367
|
+
for (const mod of opts.modifications) {
|
|
38368
|
+
mods.push({ tag: mod.tag, value: mod.value });
|
|
38369
|
+
}
|
|
38370
|
+
return mods;
|
|
38371
|
+
}
|
|
38372
|
+
function computeThroughput(succeeded, totalBytes, durationMs) {
|
|
38373
|
+
const durationSec = durationMs / 1e3;
|
|
38374
|
+
return {
|
|
38375
|
+
filesPerSec: durationSec > 0 ? succeeded / durationSec : 0,
|
|
38376
|
+
bytesPerSec: durationSec > 0 ? totalBytes / durationSec : 0
|
|
38377
|
+
};
|
|
38378
|
+
}
|
|
38379
|
+
function delay3(ms) {
|
|
38380
|
+
return new Promise((resolve) => {
|
|
38381
|
+
setTimeout(resolve, ms);
|
|
38382
|
+
});
|
|
38383
|
+
}
|
|
38384
|
+
var DicomHammer = class _DicomHammer extends EventEmitter {
|
|
38385
|
+
constructor(options) {
|
|
38386
|
+
super();
|
|
38387
|
+
__publicField(this, "opts");
|
|
38388
|
+
__publicField(this, "generatedDir");
|
|
38389
|
+
__publicField(this, "generatedFiles", []);
|
|
38390
|
+
this.opts = options;
|
|
38391
|
+
this.setMaxListeners(20);
|
|
38392
|
+
}
|
|
38393
|
+
// -----------------------------------------------------------------------
|
|
38394
|
+
// Factory
|
|
38395
|
+
// -----------------------------------------------------------------------
|
|
38396
|
+
/**
|
|
38397
|
+
* Creates a DicomHammer instance.
|
|
38398
|
+
*
|
|
38399
|
+
* @param options - Configuration for file generation and sending
|
|
38400
|
+
* @returns A Result containing the DicomHammer or a validation error
|
|
38401
|
+
*/
|
|
38402
|
+
static create(options) {
|
|
38403
|
+
const validation = DicomHammerOptionsSchema.safeParse(options);
|
|
38404
|
+
if (!validation.success) {
|
|
38405
|
+
return err(createValidationError("DicomHammer", validation.error));
|
|
38406
|
+
}
|
|
38407
|
+
return ok(new _DicomHammer(resolveOptions(options)));
|
|
38408
|
+
}
|
|
38409
|
+
// -----------------------------------------------------------------------
|
|
38410
|
+
// Generate phase
|
|
38411
|
+
// -----------------------------------------------------------------------
|
|
38412
|
+
/**
|
|
38413
|
+
* Generates modified copies of the source DICOM file.
|
|
38414
|
+
*
|
|
38415
|
+
* Each copy receives unique Study/Series/SOP Instance UIDs, a unique
|
|
38416
|
+
* accession number, and any custom modifications.
|
|
38417
|
+
*/
|
|
38418
|
+
async generate() {
|
|
38419
|
+
const start = Date.now();
|
|
38420
|
+
const dir = join(this.opts.outputDir, `dcmtk-hammer-${Date.now()}`);
|
|
38421
|
+
try {
|
|
38422
|
+
await mkdir(dir, { recursive: true });
|
|
38423
|
+
} catch {
|
|
38424
|
+
return err(new Error(`Failed to create output directory: ${dir}`));
|
|
38425
|
+
}
|
|
38426
|
+
this.generatedDir = dir;
|
|
38427
|
+
const indices = Array.from({ length: this.opts.fileCount }, (_, i) => i);
|
|
38428
|
+
const total = this.opts.fileCount;
|
|
38429
|
+
let completedCount = 0;
|
|
38430
|
+
const result = await batch(
|
|
38431
|
+
indices,
|
|
38432
|
+
async (index) => {
|
|
38433
|
+
return this.generateOneFile(index, dir);
|
|
38434
|
+
},
|
|
38435
|
+
{
|
|
38436
|
+
concurrency: this.opts.concurrency,
|
|
38437
|
+
signal: this.opts.signal,
|
|
38438
|
+
onProgress: (_completed, _total, fileResult) => {
|
|
38439
|
+
completedCount++;
|
|
38440
|
+
if (fileResult.ok) {
|
|
38441
|
+
this.emit("FILE_GENERATED", { index: completedCount - 1, total, filePath: fileResult.value });
|
|
38442
|
+
}
|
|
38443
|
+
this.emitProgress(HammerPhase.GENERATE, completedCount, total);
|
|
38444
|
+
}
|
|
38445
|
+
}
|
|
38446
|
+
);
|
|
38447
|
+
const files = result.results.filter((r) => r.ok).map((r) => r.value);
|
|
38448
|
+
this.generatedFiles = files;
|
|
38449
|
+
if (files.length === 0) {
|
|
38450
|
+
return err(new Error(`All ${total} file generations failed`));
|
|
38451
|
+
}
|
|
38452
|
+
return ok({ files, durationMs: Date.now() - start, outputDir: dir });
|
|
38453
|
+
}
|
|
38454
|
+
/** Generates a single modified copy. Extracted for function size compliance. */
|
|
38455
|
+
async generateOneFile(index, dir) {
|
|
38456
|
+
const padded = String(index + 1).padStart(6, "0");
|
|
38457
|
+
const dest = join(dir, `hammer_${padded}.dcm`);
|
|
38458
|
+
const copyResult = await copyFileSafe(this.opts.sourceFile, dest);
|
|
38459
|
+
if (!copyResult.ok) return err(copyResult.error);
|
|
38460
|
+
const modResult = await dcmodify(dest, {
|
|
38461
|
+
modifications: buildModifications(index, this.opts),
|
|
38462
|
+
erasePrivateTags: this.opts.erasePrivateTags || void 0,
|
|
38463
|
+
insertIfMissing: true,
|
|
38464
|
+
noBackup: true,
|
|
38465
|
+
timeoutMs: this.opts.timeoutMs,
|
|
38466
|
+
signal: this.opts.signal
|
|
38467
|
+
});
|
|
38468
|
+
if (!modResult.ok) return err(modResult.error);
|
|
38469
|
+
return ok(dest);
|
|
38470
|
+
}
|
|
38471
|
+
// -----------------------------------------------------------------------
|
|
38472
|
+
// Send phase
|
|
38473
|
+
// -----------------------------------------------------------------------
|
|
38474
|
+
/**
|
|
38475
|
+
* Sends files to the target SCP.
|
|
38476
|
+
*
|
|
38477
|
+
* @param files - Files to send. Defaults to previously generated files.
|
|
38478
|
+
*/
|
|
38479
|
+
async send(files) {
|
|
38480
|
+
const filesToSend = files ?? this.generatedFiles;
|
|
38481
|
+
if (filesToSend.length === 0) {
|
|
38482
|
+
return err(new Error("No files to send. Call generate() first or provide files."));
|
|
38483
|
+
}
|
|
38484
|
+
const fileSize = await this.getFileSize(filesToSend[0]);
|
|
38485
|
+
const start = Date.now();
|
|
38486
|
+
const total = filesToSend.length;
|
|
38487
|
+
const tracker = { errors: [], completedCount: 0, succeeded: 0 };
|
|
38488
|
+
await batch([...filesToSend], async (file) => this.sendOneFile(file), {
|
|
38489
|
+
concurrency: this.opts.concurrency,
|
|
38490
|
+
signal: this.opts.signal,
|
|
38491
|
+
onProgress: (_c, _t, sendResult) => this.trackSendProgress(sendResult, filesToSend, total, tracker)
|
|
38492
|
+
});
|
|
38493
|
+
return ok(this.buildSendResult(tracker, total, fileSize, Date.now() - start));
|
|
38494
|
+
}
|
|
38495
|
+
/** Tracks a single send result for progress reporting. */
|
|
38496
|
+
trackSendProgress(sendResult, files, total, tracker) {
|
|
38497
|
+
tracker.completedCount++;
|
|
38498
|
+
const file = files[tracker.completedCount - 1];
|
|
38499
|
+
if (sendResult.ok) {
|
|
38500
|
+
tracker.succeeded++;
|
|
38501
|
+
this.emit("SEND_COMPLETE", { index: tracker.completedCount - 1, total, file, durationMs: 0 });
|
|
38502
|
+
} else {
|
|
38503
|
+
tracker.errors.push({ file, error: sendResult.error });
|
|
38504
|
+
this.emit("SEND_FAILED", { index: tracker.completedCount - 1, total, file, error: sendResult.error });
|
|
38505
|
+
}
|
|
38506
|
+
this.emitProgress(HammerPhase.SEND, tracker.completedCount, total);
|
|
38507
|
+
}
|
|
38508
|
+
/** Assembles the final HammerSendResult. */
|
|
38509
|
+
buildSendResult(tracker, total, fileSize, durationMs) {
|
|
38510
|
+
const totalBytes = tracker.succeeded * fileSize;
|
|
38511
|
+
const throughput = computeThroughput(tracker.succeeded, totalBytes, durationMs);
|
|
38512
|
+
return {
|
|
38513
|
+
succeeded: tracker.succeeded,
|
|
38514
|
+
failed: tracker.errors.length,
|
|
38515
|
+
totalFiles: total,
|
|
38516
|
+
durationMs,
|
|
38517
|
+
filesPerSec: throughput.filesPerSec,
|
|
38518
|
+
bytesPerSec: throughput.bytesPerSec,
|
|
38519
|
+
totalBytes,
|
|
38520
|
+
errors: tracker.errors
|
|
38521
|
+
};
|
|
38522
|
+
}
|
|
38523
|
+
/** Sends a single file, with optional delay. */
|
|
38524
|
+
async sendOneFile(file) {
|
|
38525
|
+
if (this.opts.delayMs > 0) {
|
|
38526
|
+
await delay3(this.opts.delayMs);
|
|
38527
|
+
}
|
|
38528
|
+
const result = await dcmsend({
|
|
38529
|
+
host: this.opts.host,
|
|
38530
|
+
port: this.opts.port,
|
|
38531
|
+
files: [file],
|
|
38532
|
+
callingAETitle: this.opts.callingAETitle,
|
|
38533
|
+
calledAETitle: this.opts.calledAETitle,
|
|
38534
|
+
noHalt: this.opts.noHalt || void 0,
|
|
38535
|
+
timeoutMs: this.opts.timeoutMs,
|
|
38536
|
+
signal: this.opts.signal
|
|
38537
|
+
});
|
|
38538
|
+
if (!result.ok) return err(result.error);
|
|
38539
|
+
return ok(void 0);
|
|
38540
|
+
}
|
|
38541
|
+
/** Gets the file size in bytes, returning 0 on error. */
|
|
38542
|
+
async getFileSize(filePath) {
|
|
38543
|
+
try {
|
|
38544
|
+
const s = await stat(filePath);
|
|
38545
|
+
return s.size;
|
|
38546
|
+
} catch {
|
|
38547
|
+
return 0;
|
|
38548
|
+
}
|
|
38549
|
+
}
|
|
38550
|
+
// -----------------------------------------------------------------------
|
|
38551
|
+
// Combined run
|
|
38552
|
+
// -----------------------------------------------------------------------
|
|
38553
|
+
/**
|
|
38554
|
+
* Generates files and sends them in one call.
|
|
38555
|
+
*
|
|
38556
|
+
* @returns Combined result with timing for both phases
|
|
38557
|
+
*/
|
|
38558
|
+
async run() {
|
|
38559
|
+
const genResult = await this.generate();
|
|
38560
|
+
if (!genResult.ok) return err(genResult.error);
|
|
38561
|
+
const sendResult = await this.send(genResult.value.files);
|
|
38562
|
+
if (!sendResult.ok) return err(sendResult.error);
|
|
38563
|
+
const result = {
|
|
38564
|
+
succeeded: sendResult.value.succeeded,
|
|
38565
|
+
failed: sendResult.value.failed,
|
|
38566
|
+
totalFiles: sendResult.value.totalFiles,
|
|
38567
|
+
durationMs: genResult.value.durationMs + sendResult.value.durationMs,
|
|
38568
|
+
generateDurationMs: genResult.value.durationMs,
|
|
38569
|
+
sendDurationMs: sendResult.value.durationMs,
|
|
38570
|
+
filesPerSec: sendResult.value.filesPerSec,
|
|
38571
|
+
bytesPerSec: sendResult.value.bytesPerSec,
|
|
38572
|
+
totalBytes: sendResult.value.totalBytes,
|
|
38573
|
+
errors: sendResult.value.errors
|
|
38574
|
+
};
|
|
38575
|
+
this.emit("RUN_COMPLETE", result);
|
|
38576
|
+
return ok(result);
|
|
38577
|
+
}
|
|
38578
|
+
// -----------------------------------------------------------------------
|
|
38579
|
+
// Cleanup
|
|
38580
|
+
// -----------------------------------------------------------------------
|
|
38581
|
+
/** Removes all generated files and the output directory. */
|
|
38582
|
+
async cleanup() {
|
|
38583
|
+
if (this.generatedDir === void 0) return ok(void 0);
|
|
38584
|
+
try {
|
|
38585
|
+
await rm(this.generatedDir, { recursive: true, force: true });
|
|
38586
|
+
this.generatedDir = void 0;
|
|
38587
|
+
this.generatedFiles = [];
|
|
38588
|
+
return ok(void 0);
|
|
38589
|
+
} catch {
|
|
38590
|
+
return err(new Error(`Failed to cleanup: ${this.generatedDir}`));
|
|
38591
|
+
}
|
|
38592
|
+
}
|
|
38593
|
+
// -----------------------------------------------------------------------
|
|
38594
|
+
// Event helpers
|
|
38595
|
+
// -----------------------------------------------------------------------
|
|
38596
|
+
/** Emits a PROGRESS event. */
|
|
38597
|
+
emitProgress(phase, completed, total) {
|
|
38598
|
+
this.emit("PROGRESS", { phase, completed, total, percent: Math.round(completed / total * 100) });
|
|
38599
|
+
}
|
|
38600
|
+
/** Registers a listener for FILE_GENERATED events. */
|
|
38601
|
+
onFileGenerated(listener) {
|
|
38602
|
+
return this.on("FILE_GENERATED", listener);
|
|
38603
|
+
}
|
|
38604
|
+
/** Registers a listener for SEND_COMPLETE events. */
|
|
38605
|
+
onSendComplete(listener) {
|
|
38606
|
+
return this.on("SEND_COMPLETE", listener);
|
|
38607
|
+
}
|
|
38608
|
+
/** Registers a listener for SEND_FAILED events. */
|
|
38609
|
+
onSendFailed(listener) {
|
|
38610
|
+
return this.on("SEND_FAILED", listener);
|
|
38611
|
+
}
|
|
38612
|
+
/** Registers a listener for PROGRESS events. */
|
|
38613
|
+
onProgress(listener) {
|
|
38614
|
+
return this.on("PROGRESS", listener);
|
|
38615
|
+
}
|
|
38616
|
+
/** Registers a listener for RUN_COMPLETE events. */
|
|
38617
|
+
onRunComplete(listener) {
|
|
38618
|
+
return this.on("RUN_COMPLETE", listener);
|
|
38619
|
+
}
|
|
38620
|
+
};
|
|
38621
|
+
|
|
38271
38622
|
// src/utils/retry.ts
|
|
38272
38623
|
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
38273
38624
|
var DEFAULT_INITIAL_DELAY_MS = 1e3;
|
|
@@ -38342,6 +38693,6 @@ async function retry(operation, options) {
|
|
|
38342
38693
|
return lastResult;
|
|
38343
38694
|
}
|
|
38344
38695
|
|
|
38345
|
-
export { AETitleSchema, AssociationTracker, ChangeSet, ColorConversion, DCMPRSCP_FATAL_EVENTS, DCMPRSCP_PATTERNS, DCMPSRCV_FATAL_EVENTS, DCMPSRCV_PATTERNS, DCMQRSCP_FATAL_EVENTS, DCMQRSCP_PATTERNS, DCMRECV_FATAL_EVENTS, DCMRECV_PATTERNS, DEFAULT_BLOCK_TIMEOUT_MS, DEFAULT_DICOM_PORT, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_PARSE_CONCURRENCY, DEFAULT_START_TIMEOUT_MS, DEFAULT_TIMEOUT_MS, Dcm2pnmOutputFormat, Dcm2xmlCharset, DcmQRSCP, DcmdumpFormat, Dcmj2pnmOutputFormat, DcmprsCP, DcmprscpEvent, Dcmpsrcv, DcmpsrcvEvent, DcmqrscpEvent, Dcmrecv, DcmrecvEvent, DcmtkProcess, DicomDataset, DicomInstance, DicomReceiver, DicomSend, DicomSender, DicomTagPathSchema, DicomTagSchema, FilenameMode, GetQueryModel, Img2dcmInputFormat, JplsColorConversion, LineParser, LutType, MAX_BLOCK_LINES, MAX_CHANGESET_OPERATIONS, MAX_EVENT_PATTERNS, MAX_TRAVERSAL_DEPTH, MoveQueryModel, PDU_SIZE, PacsClient, PortSchema, PreferredTransferSyntax, ProcessState, ProposedTransferSyntax, QueryLevel, QueryModel, REQUIRED_BINARIES, RetrieveMode, SOP_CLASSES, STORESCP_FATAL_EVENTS, STORESCP_PATTERNS, SenderHealth, SenderMode, StorageMode, StoreSCP, StoreSCPPreset, StorescpEvent, SubdirectoryMode, TransferSyntax, UIDSchema, UNIX_SEARCH_PATHS, VR, VR_CATEGORY, VR_CATEGORY_NAME, VR_META, WINDOWS_SEARCH_PATHS, WLMSCPFS_FATAL_EVENTS, WLMSCPFS_PATTERNS, Wlmscpfs, WlmscpfsEvent, assertUnreachable, batch, cda2dcm, clearDcmtkPathCache, createAETitle, createDicomFilePath, createDicomTag, createDicomTagPath, createPort, createSOPClassUID, createTransferSyntaxUID, dcm2cda, dcm2json, dcm2pdf, dcm2pnm, dcm2xml, dcmcjpeg, dcmcjpls, dcmconv, dcmcrle, dcmdecap, dcmdjpeg, dcmdjpls, dcmdrle, dcmdspfn, dcmdump, dcmencap, dcmftest, dcmgpdir, dcmj2pnm, dcmmkcrv, dcmmkdir, dcmmklut, dcmodify, dcmp2pgm, dcmprscu, dcmpschk, dcmpsmk, dcmpsprt, dcmqridx, dcmquant, dcmscale, dcmsend, dcod2lum, dconvlum, drtdump, dsr2xml, dsrdump, dump2dcm, echoscu, err, execCommand, findDcmtkPath, findscu, getVRCategory, getscu, img2dcm, isBinaryVR, isNumericVR, isStringVR, json2dcm, lookupTag, lookupTagByKeyword, lookupTagByName, mapResult, movescu, ok, parseAETitle, parseDicomTag, parseDicomTagPath, parsePort, parseSOPClassUID, parseTransferSyntaxUID, pdf2dcm, retry, segmentsToModifyPath, segmentsToString, sopClassNameFromUID, spawnCommand, stl2dcm, storescu, tag, tagPathToSegments, termscu, walkTags, xml2dcm, xml2dsr, xmlToJson };
|
|
38696
|
+
export { AETitleSchema, AssociationTracker, ChangeSet, ColorConversion, DCMPRSCP_FATAL_EVENTS, DCMPRSCP_PATTERNS, DCMPSRCV_FATAL_EVENTS, DCMPSRCV_PATTERNS, DCMQRSCP_FATAL_EVENTS, DCMQRSCP_PATTERNS, DCMRECV_FATAL_EVENTS, DCMRECV_PATTERNS, DEFAULT_BLOCK_TIMEOUT_MS, DEFAULT_DICOM_PORT, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_PARSE_CONCURRENCY, DEFAULT_START_TIMEOUT_MS, DEFAULT_TIMEOUT_MS, Dcm2pnmOutputFormat, Dcm2xmlCharset, DcmQRSCP, DcmdumpFormat, Dcmj2pnmOutputFormat, DcmprsCP, DcmprscpEvent, Dcmpsrcv, DcmpsrcvEvent, DcmqrscpEvent, Dcmrecv, DcmrecvEvent, DcmtkProcess, DicomDataset, DicomHammer, DicomInstance, DicomReceiver, DicomSend, DicomSender, DicomTagPathSchema, DicomTagSchema, FilenameMode, GetQueryModel, HammerPhase, Img2dcmInputFormat, JplsColorConversion, LineParser, LutType, MAX_BLOCK_LINES, MAX_CHANGESET_OPERATIONS, MAX_EVENT_PATTERNS, MAX_TRAVERSAL_DEPTH, MoveQueryModel, PDU_SIZE, PacsClient, PortSchema, PreferredTransferSyntax, ProcessState, ProposedTransferSyntax, QueryLevel, QueryModel, REQUIRED_BINARIES, RetrieveMode, SOP_CLASSES, STORESCP_FATAL_EVENTS, STORESCP_PATTERNS, SenderHealth, SenderMode, StorageMode, StoreSCP, StoreSCPPreset, StorescpEvent, SubdirectoryMode, TransferSyntax, UIDSchema, UNIX_SEARCH_PATHS, VR, VR_CATEGORY, VR_CATEGORY_NAME, VR_META, WINDOWS_SEARCH_PATHS, WLMSCPFS_FATAL_EVENTS, WLMSCPFS_PATTERNS, Wlmscpfs, WlmscpfsEvent, assertUnreachable, batch, cda2dcm, clearDcmtkPathCache, createAETitle, createDicomFilePath, createDicomTag, createDicomTagPath, createPort, createSOPClassUID, createTransferSyntaxUID, dcm2cda, dcm2json, dcm2pdf, dcm2pnm, dcm2xml, dcmcjpeg, dcmcjpls, dcmconv, dcmcrle, dcmdecap, dcmdjpeg, dcmdjpls, dcmdrle, dcmdspfn, dcmdump, dcmencap, dcmftest, dcmgpdir, dcmj2pnm, dcmmkcrv, dcmmkdir, dcmmklut, dcmodify, dcmp2pgm, dcmprscu, dcmpschk, dcmpsmk, dcmpsprt, dcmqridx, dcmquant, dcmscale, dcmsend, dcod2lum, dconvlum, drtdump, dsr2xml, dsrdump, dump2dcm, echoscu, err, execCommand, findDcmtkPath, findscu, getVRCategory, getscu, img2dcm, isBinaryVR, isNumericVR, isStringVR, json2dcm, lookupTag, lookupTagByKeyword, lookupTagByName, mapResult, movescu, ok, parseAETitle, parseDicomTag, parseDicomTagPath, parsePort, parseSOPClassUID, parseTransferSyntaxUID, pdf2dcm, retry, segmentsToModifyPath, segmentsToString, sopClassNameFromUID, spawnCommand, stl2dcm, storescu, tag, tagPathToSegments, termscu, walkTags, xml2dcm, xml2dsr, xmlToJson };
|
|
38346
38697
|
//# sourceMappingURL=index.js.map
|
|
38347
38698
|
//# sourceMappingURL=index.js.map
|