trajectories-sh 1.10.3 → 1.11.0
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/cli.js
CHANGED
|
@@ -81,7 +81,7 @@ async function uploadTrajectoryAction(directory, opts) {
|
|
|
81
81
|
Uploading trajectory ${directory} \u2192 ${chalk.cyan(slug)}
|
|
82
82
|
`));
|
|
83
83
|
try {
|
|
84
|
-
const { uploadJob } = await import("./upload-
|
|
84
|
+
const { uploadJob } = await import("./upload-YKSKGJET.js");
|
|
85
85
|
const result = await uploadJob(directory, {
|
|
86
86
|
slug,
|
|
87
87
|
name: opts.name,
|
|
@@ -10,8 +10,10 @@ import { tmpdir } from "os";
|
|
|
10
10
|
import { randomBytes, createHash } from "crypto";
|
|
11
11
|
var SKIP = /* @__PURE__ */ new Set(["__pycache__", ".DS_Store", ".git", "node_modules"]);
|
|
12
12
|
var MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
13
|
-
var CONCURRENCY = Number(process.env.TRAJECTORIES_CLI_CONCURRENCY ?? "
|
|
13
|
+
var CONCURRENCY = Number(process.env.TRAJECTORIES_CLI_CONCURRENCY ?? "32");
|
|
14
14
|
var BATCH_SIZE = 100;
|
|
15
|
+
var WEBP_CONCURRENCY = Number(process.env.TRAJECTORIES_CLI_WEBP_CONCURRENCY ?? "4");
|
|
16
|
+
var HASH_CONCURRENCY = Number(process.env.TRAJECTORIES_CLI_HASH_CONCURRENCY ?? "16");
|
|
15
17
|
function collectFiles(dir) {
|
|
16
18
|
const files = [];
|
|
17
19
|
function walk(current) {
|
|
@@ -85,26 +87,30 @@ async function convertToWebP(dir) {
|
|
|
85
87
|
sharp.cache({ memory: 0, files: 0, items: 0 });
|
|
86
88
|
let converted = 0;
|
|
87
89
|
let savedBytes = 0;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
} catch {
|
|
90
|
+
let processed = 0;
|
|
91
|
+
const total = pngs.length;
|
|
92
|
+
async function convertOne(f) {
|
|
93
|
+
const srcPath = join(tmpDir, f.relPath);
|
|
94
|
+
const webpPath = srcPath.replace(/\.png$/i, ".webp");
|
|
95
|
+
try {
|
|
96
|
+
await pngToWebp(srcPath, webpPath);
|
|
97
|
+
const origSize = statSync(srcPath).size;
|
|
98
|
+
const newSize = statSync(webpPath).size;
|
|
99
|
+
if (newSize < origSize) {
|
|
100
|
+
unlinkSync(srcPath);
|
|
101
|
+
savedBytes += origSize - newSize;
|
|
102
|
+
converted++;
|
|
103
|
+
} else {
|
|
104
|
+
unlinkSync(webpPath);
|
|
105
105
|
}
|
|
106
|
-
|
|
106
|
+
} catch {
|
|
107
|
+
} finally {
|
|
108
|
+
processed++;
|
|
109
|
+
process.stdout.write(` Converting: ${processed}/${total} PNGs\r`);
|
|
107
110
|
}
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
await runWithConcurrency(pngs, WEBP_CONCURRENCY, convertOne);
|
|
108
114
|
console.log("");
|
|
109
115
|
} finally {
|
|
110
116
|
try {
|
|
@@ -135,12 +141,34 @@ async function convertToWebP(dir) {
|
|
|
135
141
|
}
|
|
136
142
|
return { convertedDir: tmpDir, pngsConverted: converted, savedBytes };
|
|
137
143
|
}
|
|
138
|
-
function
|
|
139
|
-
|
|
144
|
+
async function runWithConcurrency(items, n, worker) {
|
|
145
|
+
if (items.length === 0) return;
|
|
146
|
+
let next = 0;
|
|
147
|
+
const runners = [];
|
|
148
|
+
for (let k = 0; k < Math.min(n, items.length); k++) {
|
|
149
|
+
runners.push(
|
|
150
|
+
(async () => {
|
|
151
|
+
while (true) {
|
|
152
|
+
const i = next++;
|
|
153
|
+
if (i >= items.length) return;
|
|
154
|
+
await worker(items[i], i);
|
|
155
|
+
}
|
|
156
|
+
})()
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
await Promise.all(runners);
|
|
160
|
+
}
|
|
161
|
+
async function computeContentHash(files) {
|
|
162
|
+
const { readFile } = await import("fs/promises");
|
|
140
163
|
const sorted = [...files].sort((a, b) => a.relPath.localeCompare(b.relPath));
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
164
|
+
const contents = new Array(sorted.length);
|
|
165
|
+
await runWithConcurrency(sorted, HASH_CONCURRENCY, async (f, i) => {
|
|
166
|
+
contents[i] = await readFile(f.absPath);
|
|
167
|
+
});
|
|
168
|
+
const hash = createHash("sha256");
|
|
169
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
170
|
+
hash.update(sorted[i].relPath);
|
|
171
|
+
hash.update(contents[i]);
|
|
144
172
|
}
|
|
145
173
|
return hash.digest("hex");
|
|
146
174
|
}
|
|
@@ -280,9 +308,11 @@ async function uploadJob(dir, opts) {
|
|
|
280
308
|
}
|
|
281
309
|
const files = collectFiles(convertedDir);
|
|
282
310
|
const totalSize = files.reduce((s, f) => s + f.size, 0);
|
|
283
|
-
const contentHash = computeContentHash(files);
|
|
284
311
|
console.log(` ${files.length} files, ${(totalSize / 1024 / 1024).toFixed(1)} MB`);
|
|
285
|
-
|
|
312
|
+
process.stdout.write(` Hashing...\r`);
|
|
313
|
+
const t0 = Date.now();
|
|
314
|
+
const contentHash = await computeContentHash(files);
|
|
315
|
+
console.log(` Hash: ${contentHash.slice(0, 16)}... (${((Date.now() - t0) / 1e3).toFixed(1)}s)`);
|
|
286
316
|
try {
|
|
287
317
|
const auth = await getAuthHeader();
|
|
288
318
|
const usageResp = await fetch(`${getApiUrl()}/api/cli/usage`, {
|
|
@@ -360,9 +390,16 @@ async function uploadDirect(jobId, files) {
|
|
|
360
390
|
const bar = new ProgressBar({ total: files.length, totalBytes, label: "\u2191" });
|
|
361
391
|
const failedFiles = [];
|
|
362
392
|
const failureReasons = [];
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
393
|
+
const batches = [];
|
|
394
|
+
for (let i = 0; i < files.length; i += BATCH_SIZE) {
|
|
395
|
+
batches.push(files.slice(i, i + BATCH_SIZE));
|
|
396
|
+
}
|
|
397
|
+
let nextUrlsPromise = batches.length > 0 ? fetchSignedUrlsForBatch(jobId, batches[0].map((f) => f.relPath)) : null;
|
|
398
|
+
const pending = /* @__PURE__ */ new Set();
|
|
399
|
+
for (let bi = 0; bi < batches.length; bi++) {
|
|
400
|
+
const batch = batches[bi];
|
|
401
|
+
const urlMap = await nextUrlsPromise;
|
|
402
|
+
nextUrlsPromise = bi + 1 < batches.length ? fetchSignedUrlsForBatch(jobId, batches[bi + 1].map((f) => f.relPath)) : null;
|
|
366
403
|
for (const file of batch) {
|
|
367
404
|
if (!urlMap.has(file.relPath)) {
|
|
368
405
|
failedFiles.push(file.relPath);
|
|
@@ -371,12 +408,9 @@ async function uploadDirect(jobId, files) {
|
|
|
371
408
|
reason: "no signed URL from server after retries"
|
|
372
409
|
});
|
|
373
410
|
bar.tick(0);
|
|
411
|
+
continue;
|
|
374
412
|
}
|
|
375
|
-
}
|
|
376
|
-
const pending = /* @__PURE__ */ new Set();
|
|
377
|
-
for (const file of batch) {
|
|
378
413
|
const signedUrl = urlMap.get(file.relPath);
|
|
379
|
-
if (!signedUrl) continue;
|
|
380
414
|
const task = (async () => {
|
|
381
415
|
const result = await uploadOneFileWithError(file, signedUrl);
|
|
382
416
|
if (result.ok) {
|
|
@@ -394,8 +428,8 @@ async function uploadDirect(jobId, files) {
|
|
|
394
428
|
await Promise.race(pending);
|
|
395
429
|
}
|
|
396
430
|
}
|
|
397
|
-
await Promise.all(pending);
|
|
398
431
|
}
|
|
432
|
+
await Promise.all(pending);
|
|
399
433
|
bar.done();
|
|
400
434
|
if (failedFiles.length > 0) {
|
|
401
435
|
const byReason = /* @__PURE__ */ new Map();
|