pinme 1.1.1-alpha.1 → 1.1.1-alpha.3
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/index.js +282 -90
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1485,7 +1485,7 @@ var import_chalk6 = __toESM(require("chalk"));
|
|
|
1485
1485
|
var import_figlet3 = __toESM(require("figlet"));
|
|
1486
1486
|
|
|
1487
1487
|
// package.json
|
|
1488
|
-
var version = "1.1.1-alpha.
|
|
1488
|
+
var version = "1.1.1-alpha.3";
|
|
1489
1489
|
|
|
1490
1490
|
// bin/upload.ts
|
|
1491
1491
|
var import_path5 = __toESM(require("path"));
|
|
@@ -4525,7 +4525,9 @@ var ipfsApiUrl = "https://pinme.dev/api/v3";
|
|
|
4525
4525
|
var maxPollTime = parseInt(process.env.MAX_POLL_TIME_MINUTES || "5") * 60 * 1e3;
|
|
4526
4526
|
var pollInterval = parseInt(process.env.POLL_INTERVAL_SECONDS || "2") * 1e3;
|
|
4527
4527
|
var pollTimeout = parseInt(process.env.POLL_TIMEOUT_SECONDS || "10") * 1e3;
|
|
4528
|
-
async function pollUploadStatus(traceId, deviceId,
|
|
4528
|
+
async function pollUploadStatus(traceId, deviceId, smartProgress, startTime) {
|
|
4529
|
+
let consecutiveErrors = 0;
|
|
4530
|
+
let stopProgressUpdates = false;
|
|
4529
4531
|
while (Date.now() - startTime < maxPollTime) {
|
|
4530
4532
|
try {
|
|
4531
4533
|
const response = await axios_default.get(
|
|
@@ -4542,28 +4544,31 @@ async function pollUploadStatus(traceId, deviceId, spinner, startTime) {
|
|
|
4542
4544
|
);
|
|
4543
4545
|
const { code, msg, data } = response.data;
|
|
4544
4546
|
if (code === 200) {
|
|
4545
|
-
|
|
4547
|
+
consecutiveErrors = 0;
|
|
4548
|
+
stopProgressUpdates = false;
|
|
4546
4549
|
if (data.is_ready) {
|
|
4547
|
-
|
|
4548
|
-
const duration = formatDuration(elapsed);
|
|
4549
|
-
spinner.succeed(`Upload completed ${progressBar} ${duration} (request id: ${traceId})`);
|
|
4550
|
+
smartProgress.complete(traceId);
|
|
4550
4551
|
return data;
|
|
4551
4552
|
} else {
|
|
4552
|
-
|
|
4553
|
-
const progressBar = createProgressBar(estimatedProgress, 1);
|
|
4554
|
-
const duration = formatDuration(elapsed);
|
|
4555
|
-
spinner.text = `Uploading... ${progressBar} ${duration} (request id: ${traceId})`;
|
|
4553
|
+
smartProgress.updateDisplay();
|
|
4556
4554
|
}
|
|
4557
4555
|
} else {
|
|
4558
4556
|
console.log(import_chalk2.default.yellow(`Warning: ${msg}`));
|
|
4559
4557
|
}
|
|
4560
4558
|
} catch (error) {
|
|
4559
|
+
consecutiveErrors++;
|
|
4561
4560
|
console.log(import_chalk2.default.yellow(`Polling error: ${error.message}`));
|
|
4561
|
+
if (stopProgressUpdates) {
|
|
4562
|
+
smartProgress.updateTimeOnly();
|
|
4563
|
+
}
|
|
4562
4564
|
}
|
|
4563
4565
|
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
4564
4566
|
}
|
|
4565
4567
|
const maxPollTimeMinutes = Math.floor(maxPollTime / (60 * 1e3));
|
|
4566
|
-
|
|
4568
|
+
smartProgress.fail(
|
|
4569
|
+
`Upload timeout after ${maxPollTimeMinutes} minutes`,
|
|
4570
|
+
traceId
|
|
4571
|
+
);
|
|
4567
4572
|
return null;
|
|
4568
4573
|
}
|
|
4569
4574
|
function diagnoseDirectoryUploadError(directoryName, resData, expectedName) {
|
|
@@ -4608,10 +4613,13 @@ var ERROR_CODES = {
|
|
|
4608
4613
|
"30001": `File too large, single file max size: ${"20"}MB,single folder max size: ${"500"}MB`,
|
|
4609
4614
|
"30002": `Max storage quorum ${Number("1000") / 1e3} GB reached`
|
|
4610
4615
|
};
|
|
4611
|
-
function loadFilesToArrRecursively(directoryPath, dist) {
|
|
4616
|
+
function loadFilesToArrRecursively(directoryPath, dist, basePath) {
|
|
4612
4617
|
const filesArr = [];
|
|
4613
4618
|
const sep = import_path4.default.sep;
|
|
4614
|
-
|
|
4619
|
+
if (!basePath) {
|
|
4620
|
+
const parentDir = import_path4.default.dirname(directoryPath);
|
|
4621
|
+
basePath = parentDir.endsWith(sep) ? parentDir : parentDir + sep;
|
|
4622
|
+
}
|
|
4615
4623
|
if (import_fs_extra3.default.statSync(directoryPath).isDirectory()) {
|
|
4616
4624
|
const files = import_fs_extra3.default.readdirSync(directoryPath);
|
|
4617
4625
|
files.forEach((file) => {
|
|
@@ -4625,14 +4633,18 @@ function loadFilesToArrRecursively(directoryPath, dist) {
|
|
|
4625
4633
|
)} (size: ${formatSize(sizeCheck.size)})`
|
|
4626
4634
|
);
|
|
4627
4635
|
}
|
|
4628
|
-
const
|
|
4629
|
-
const
|
|
4636
|
+
const relativePath = filePath.replace(basePath, "");
|
|
4637
|
+
const encodedPath = relativePath.replaceAll(sep, "%2F");
|
|
4630
4638
|
filesArr.push({
|
|
4631
|
-
name:
|
|
4639
|
+
name: encodedPath,
|
|
4632
4640
|
path: filePath
|
|
4633
4641
|
});
|
|
4634
4642
|
} else if (import_fs_extra3.default.statSync(filePath).isDirectory()) {
|
|
4635
|
-
const recursiveFiles = loadFilesToArrRecursively(
|
|
4643
|
+
const recursiveFiles = loadFilesToArrRecursively(
|
|
4644
|
+
filePath,
|
|
4645
|
+
dist,
|
|
4646
|
+
basePath
|
|
4647
|
+
);
|
|
4636
4648
|
filesArr.push(...recursiveFiles);
|
|
4637
4649
|
}
|
|
4638
4650
|
});
|
|
@@ -4671,18 +4683,9 @@ async function uploadDirectory(directoryPath, deviceId) {
|
|
|
4671
4683
|
const files = loadFilesToArrRecursively(directoryPath, dist);
|
|
4672
4684
|
const totalFiles = files.length;
|
|
4673
4685
|
if (totalFiles === 0) {
|
|
4674
|
-
throw new Error(
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
\u{1F4C1} Directory upload details:`));
|
|
4678
|
-
console.log(import_chalk2.default.gray(` - Directory: ${dist}`));
|
|
4679
|
-
console.log(import_chalk2.default.gray(` - Total files: ${totalFiles}`));
|
|
4680
|
-
console.log(import_chalk2.default.gray(` - Files to upload:`));
|
|
4681
|
-
files.slice(0, 5).forEach((file, index) => {
|
|
4682
|
-
console.log(import_chalk2.default.gray(` ${index + 1}. ${file.name} (${file.path})`));
|
|
4683
|
-
});
|
|
4684
|
-
if (files.length > 5) {
|
|
4685
|
-
console.log(import_chalk2.default.gray(` ... and ${files.length - 5} more files`));
|
|
4686
|
+
throw new Error(
|
|
4687
|
+
`Directory ${directoryPath} is empty or contains no valid files`
|
|
4688
|
+
);
|
|
4686
4689
|
}
|
|
4687
4690
|
files.forEach((file) => {
|
|
4688
4691
|
if (!import_fs_extra3.default.existsSync(file.path)) {
|
|
@@ -4697,16 +4700,29 @@ async function uploadDirectory(directoryPath, deviceId) {
|
|
|
4697
4700
|
});
|
|
4698
4701
|
});
|
|
4699
4702
|
const startTime = Date.now();
|
|
4700
|
-
const spinner = (0, import_ora.default)(
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
+
const spinner = (0, import_ora.default)(`Preparing upload...`).start();
|
|
4704
|
+
let totalSize = 0;
|
|
4705
|
+
files.forEach((file) => {
|
|
4706
|
+
try {
|
|
4707
|
+
const stats = import_fs_extra3.default.statSync(file.path);
|
|
4708
|
+
totalSize += stats.size;
|
|
4709
|
+
} catch (error) {
|
|
4710
|
+
}
|
|
4711
|
+
});
|
|
4712
|
+
const smartProgress = new SmartProgressBar(
|
|
4713
|
+
dist,
|
|
4714
|
+
totalFiles,
|
|
4715
|
+
totalSize,
|
|
4716
|
+
spinner
|
|
4717
|
+
);
|
|
4703
4718
|
const timeInterval = setInterval(() => {
|
|
4704
|
-
|
|
4705
|
-
const progressBar = createProgressBar(elapsed, Math.max(elapsed + 1, 30));
|
|
4706
|
-
const duration = formatDuration(elapsed);
|
|
4707
|
-
spinner.text = `Uploading ${dist} (${totalFiles} files) ${progressBar} ${duration}`;
|
|
4719
|
+
smartProgress.updateTime();
|
|
4708
4720
|
}, 1e3);
|
|
4721
|
+
const progressInterval = setInterval(() => {
|
|
4722
|
+
smartProgress.updateProgress();
|
|
4723
|
+
}, 200);
|
|
4709
4724
|
try {
|
|
4725
|
+
smartProgress.startUpload();
|
|
4710
4726
|
const response = await axios_default.post(
|
|
4711
4727
|
`${ipfsApiUrl}/add?uid=${deviceId}&cidV=1`,
|
|
4712
4728
|
formData,
|
|
@@ -4718,22 +4734,23 @@ async function uploadDirectory(directoryPath, deviceId) {
|
|
|
4718
4734
|
// 30 minutes timeout
|
|
4719
4735
|
}
|
|
4720
4736
|
);
|
|
4721
|
-
clearInterval(
|
|
4737
|
+
clearInterval(progressInterval);
|
|
4738
|
+
smartProgress.startPolling();
|
|
4722
4739
|
const { trace_id } = response.data.data;
|
|
4723
4740
|
if (!trace_id) {
|
|
4724
|
-
|
|
4741
|
+
smartProgress.fail("No request id received from server");
|
|
4742
|
+
clearInterval(timeInterval);
|
|
4725
4743
|
return null;
|
|
4726
4744
|
}
|
|
4727
|
-
|
|
4728
|
-
console.log(import_chalk2.default.blue(`
|
|
4729
|
-
\u{1F50D} REQUEST ID: ${trace_id}`));
|
|
4745
|
+
smartProgress.updateDisplay();
|
|
4730
4746
|
const uploadResult = await pollUploadStatus(
|
|
4731
4747
|
trace_id,
|
|
4732
4748
|
deviceId,
|
|
4733
|
-
|
|
4749
|
+
smartProgress,
|
|
4734
4750
|
startTime
|
|
4735
4751
|
);
|
|
4736
4752
|
if (!uploadResult) {
|
|
4753
|
+
clearInterval(timeInterval);
|
|
4737
4754
|
return null;
|
|
4738
4755
|
}
|
|
4739
4756
|
const directoryItem = uploadResult.upload_rst;
|
|
@@ -4750,6 +4767,7 @@ async function uploadDirectory(directoryPath, deviceId) {
|
|
|
4750
4767
|
shortUrl: directoryItem.ShortUrl || null
|
|
4751
4768
|
};
|
|
4752
4769
|
saveUploadHistory(uploadData);
|
|
4770
|
+
clearInterval(timeInterval);
|
|
4753
4771
|
return {
|
|
4754
4772
|
hash: directoryItem.Hash,
|
|
4755
4773
|
shortUrl: directoryItem.ShortUrl
|
|
@@ -4760,7 +4778,7 @@ async function uploadDirectory(directoryPath, deviceId) {
|
|
|
4760
4778
|
uploadResult.upload_rst,
|
|
4761
4779
|
dist
|
|
4762
4780
|
);
|
|
4763
|
-
|
|
4781
|
+
smartProgress.fail("Directory hash not found in response");
|
|
4764
4782
|
console.log(
|
|
4765
4783
|
import_chalk2.default.red(
|
|
4766
4784
|
`
|
|
@@ -4773,19 +4791,23 @@ async function uploadDirectory(directoryPath, deviceId) {
|
|
|
4773
4791
|
console.log(import_chalk2.default.blue(`
|
|
4774
4792
|
\u{1F527} Solutions:`));
|
|
4775
4793
|
console.log(
|
|
4776
|
-
import_chalk2.default.gray(
|
|
4777
|
-
` 1. Ensure directory is not empty and contains valid files`
|
|
4778
|
-
)
|
|
4794
|
+
import_chalk2.default.gray(` 1. Ensure directory is not empty and contains valid files`)
|
|
4779
4795
|
);
|
|
4780
4796
|
console.log(import_chalk2.default.gray(` 2. Check network connection stability`));
|
|
4781
4797
|
console.log(
|
|
4782
4798
|
import_chalk2.default.gray(` 3. Try uploading a smaller directory for testing`)
|
|
4783
4799
|
);
|
|
4800
|
+
clearInterval(timeInterval);
|
|
4801
|
+
return null;
|
|
4784
4802
|
} catch (error) {
|
|
4803
|
+
clearInterval(progressInterval);
|
|
4785
4804
|
clearInterval(timeInterval);
|
|
4786
4805
|
if (error.message && error.message.includes("multipart")) {
|
|
4787
|
-
const errorMessage = handleMultipartError(
|
|
4788
|
-
|
|
4806
|
+
const errorMessage = handleMultipartError(
|
|
4807
|
+
error,
|
|
4808
|
+
`Directory upload: ${dist}`
|
|
4809
|
+
);
|
|
4810
|
+
smartProgress.fail(errorMessage);
|
|
4789
4811
|
console.log(import_chalk2.default.red(`
|
|
4790
4812
|
\u274C ${errorMessage}`));
|
|
4791
4813
|
return null;
|
|
@@ -4793,14 +4815,16 @@ async function uploadDirectory(directoryPath, deviceId) {
|
|
|
4793
4815
|
if (error.response && error.response.data && error.response.data.code) {
|
|
4794
4816
|
const errorCode = error.response.data.code.toString();
|
|
4795
4817
|
if (ERROR_CODES[errorCode]) {
|
|
4796
|
-
|
|
4818
|
+
smartProgress.fail(
|
|
4819
|
+
`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`
|
|
4820
|
+
);
|
|
4797
4821
|
console.log(
|
|
4798
4822
|
import_chalk2.default.red(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`)
|
|
4799
4823
|
);
|
|
4800
4824
|
return null;
|
|
4801
4825
|
}
|
|
4802
4826
|
}
|
|
4803
|
-
|
|
4827
|
+
smartProgress.fail(`Error: ${error.message}`);
|
|
4804
4828
|
console.log(import_chalk2.default.red(`Error: ${error.message}`));
|
|
4805
4829
|
return null;
|
|
4806
4830
|
}
|
|
@@ -4822,15 +4846,30 @@ async function uploadFile(filePath, deviceId) {
|
|
|
4822
4846
|
if (!fileStats.isFile()) {
|
|
4823
4847
|
throw new Error(`Path is not a file: ${filePath}`);
|
|
4824
4848
|
}
|
|
4849
|
+
console.log(import_chalk2.default.blue("\n\u{1F4C4} File Upload Analysis:"));
|
|
4850
|
+
console.log(import_chalk2.default.gray(` File path: ${filePath}`));
|
|
4851
|
+
console.log(import_chalk2.default.gray(` File name: ${fileName}`));
|
|
4852
|
+
console.log(import_chalk2.default.gray(` File size: ${formatSize(fileStats.size)}`));
|
|
4853
|
+
console.log(import_chalk2.default.gray(` File exists: ${import_fs_extra3.default.existsSync(filePath)}`));
|
|
4854
|
+
console.log(import_chalk2.default.gray(` Is file: ${fileStats.isFile()}
|
|
4855
|
+
`));
|
|
4825
4856
|
const startTime = Date.now();
|
|
4826
|
-
const spinner = (0, import_ora.default)(`
|
|
4857
|
+
const spinner = (0, import_ora.default)(`Preparing upload...`).start();
|
|
4858
|
+
let totalSize = 0;
|
|
4859
|
+
try {
|
|
4860
|
+
const stats = import_fs_extra3.default.statSync(filePath);
|
|
4861
|
+
totalSize = stats.size;
|
|
4862
|
+
} catch (error) {
|
|
4863
|
+
}
|
|
4864
|
+
const smartProgress = new SmartProgressBar(fileName, 1, totalSize, spinner);
|
|
4827
4865
|
const timeInterval = setInterval(() => {
|
|
4828
|
-
|
|
4829
|
-
const progressBar = createProgressBar(elapsed, Math.max(elapsed + 1, 20));
|
|
4830
|
-
const duration = formatDuration(elapsed);
|
|
4831
|
-
spinner.text = `Uploading ${fileName} ${progressBar} ${duration}`;
|
|
4866
|
+
smartProgress.updateTime();
|
|
4832
4867
|
}, 1e3);
|
|
4868
|
+
const progressInterval = setInterval(() => {
|
|
4869
|
+
smartProgress.updateProgress();
|
|
4870
|
+
}, 200);
|
|
4833
4871
|
try {
|
|
4872
|
+
smartProgress.startUpload();
|
|
4834
4873
|
const formData = new import_form_data2.default();
|
|
4835
4874
|
const encodedFileName = encodeURIComponent(fileName);
|
|
4836
4875
|
formData.append("file", import_fs_extra3.default.createReadStream(filePath), {
|
|
@@ -4847,22 +4886,23 @@ async function uploadFile(filePath, deviceId) {
|
|
|
4847
4886
|
// 30 minutes timeout
|
|
4848
4887
|
}
|
|
4849
4888
|
);
|
|
4850
|
-
clearInterval(
|
|
4889
|
+
clearInterval(progressInterval);
|
|
4890
|
+
smartProgress.startPolling();
|
|
4851
4891
|
const trace_id = response.data.data.trace_id;
|
|
4852
4892
|
if (!trace_id) {
|
|
4853
|
-
|
|
4893
|
+
smartProgress.fail("No request id received from server");
|
|
4894
|
+
clearInterval(timeInterval);
|
|
4854
4895
|
return null;
|
|
4855
4896
|
}
|
|
4856
|
-
|
|
4857
|
-
console.log(import_chalk2.default.blue(`
|
|
4858
|
-
\u{1F50D} REQUEST ID: ${trace_id}`));
|
|
4897
|
+
smartProgress.updateDisplay();
|
|
4859
4898
|
const uploadResult = await pollUploadStatus(
|
|
4860
4899
|
trace_id,
|
|
4861
4900
|
deviceId,
|
|
4862
|
-
|
|
4901
|
+
smartProgress,
|
|
4863
4902
|
startTime
|
|
4864
4903
|
);
|
|
4865
4904
|
if (!uploadResult) {
|
|
4905
|
+
clearInterval(timeInterval);
|
|
4866
4906
|
return null;
|
|
4867
4907
|
}
|
|
4868
4908
|
const fileItem = uploadResult.upload_rst;
|
|
@@ -4878,12 +4918,14 @@ async function uploadFile(filePath, deviceId) {
|
|
|
4878
4918
|
shortUrl: fileItem.ShortUrl || null
|
|
4879
4919
|
};
|
|
4880
4920
|
saveUploadHistory(uploadData);
|
|
4921
|
+
smartProgress.complete(trace_id);
|
|
4922
|
+
clearInterval(timeInterval);
|
|
4881
4923
|
return {
|
|
4882
4924
|
hash: fileItem.Hash,
|
|
4883
4925
|
shortUrl: fileItem.ShortUrl
|
|
4884
4926
|
};
|
|
4885
4927
|
}
|
|
4886
|
-
|
|
4928
|
+
smartProgress.fail("File hash not found in response");
|
|
4887
4929
|
console.log(
|
|
4888
4930
|
import_chalk2.default.red(`
|
|
4889
4931
|
\u274C File upload failed: File hash not found in response`)
|
|
@@ -4892,20 +4934,24 @@ async function uploadFile(filePath, deviceId) {
|
|
|
4892
4934
|
\u{1F4CB} Error diagnosis information:`));
|
|
4893
4935
|
console.log(import_chalk2.default.gray(` - File name: ${fileName}`));
|
|
4894
4936
|
console.log(
|
|
4895
|
-
import_chalk2.default.gray(
|
|
4896
|
-
` - Name returned by IPFS: ${uploadResult.upload_rst.Name}`
|
|
4897
|
-
)
|
|
4937
|
+
import_chalk2.default.gray(` - Name returned by IPFS: ${uploadResult.upload_rst.Name}`)
|
|
4898
4938
|
);
|
|
4899
4939
|
console.log(import_chalk2.default.blue(`
|
|
4900
4940
|
\u{1F527} Solutions:`));
|
|
4901
4941
|
console.log(import_chalk2.default.gray(` 1. Check if file is corrupted or unreadable`));
|
|
4902
4942
|
console.log(import_chalk2.default.gray(` 2. Check network connection stability`));
|
|
4903
4943
|
console.log(import_chalk2.default.gray(` 3. Try uploading a smaller file for testing`));
|
|
4944
|
+
clearInterval(timeInterval);
|
|
4945
|
+
return null;
|
|
4904
4946
|
} catch (error) {
|
|
4947
|
+
clearInterval(progressInterval);
|
|
4905
4948
|
clearInterval(timeInterval);
|
|
4906
4949
|
if (error.message && error.message.includes("multipart")) {
|
|
4907
|
-
const errorMessage = handleMultipartError(
|
|
4908
|
-
|
|
4950
|
+
const errorMessage = handleMultipartError(
|
|
4951
|
+
error,
|
|
4952
|
+
`File upload: ${fileName}`
|
|
4953
|
+
);
|
|
4954
|
+
smartProgress.fail(errorMessage);
|
|
4909
4955
|
console.log(import_chalk2.default.red(`
|
|
4910
4956
|
\u274C ${errorMessage}`));
|
|
4911
4957
|
return null;
|
|
@@ -4913,40 +4959,186 @@ async function uploadFile(filePath, deviceId) {
|
|
|
4913
4959
|
if (error.response && error.response.data && error.response.data.code) {
|
|
4914
4960
|
const errorCode = error.response.data.code.toString();
|
|
4915
4961
|
if (ERROR_CODES[errorCode]) {
|
|
4916
|
-
|
|
4962
|
+
smartProgress.fail(
|
|
4963
|
+
`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`
|
|
4964
|
+
);
|
|
4917
4965
|
console.log(
|
|
4918
4966
|
import_chalk2.default.red(`Error: ${ERROR_CODES[errorCode]} (Code: ${errorCode})`)
|
|
4919
4967
|
);
|
|
4920
4968
|
return null;
|
|
4921
4969
|
}
|
|
4922
4970
|
}
|
|
4923
|
-
|
|
4971
|
+
smartProgress.fail(`Error: ${error.message}`);
|
|
4924
4972
|
console.log(import_chalk2.default.red(`Error: ${error.message}`));
|
|
4925
4973
|
return null;
|
|
4926
4974
|
}
|
|
4927
4975
|
}
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4976
|
+
var SmartProgressBar = class {
|
|
4977
|
+
timeConstant;
|
|
4978
|
+
startTime;
|
|
4979
|
+
uploadStartTime;
|
|
4980
|
+
isUploading;
|
|
4981
|
+
isPolling;
|
|
4982
|
+
fileCount;
|
|
4983
|
+
totalSize;
|
|
4984
|
+
spinner;
|
|
4985
|
+
fileName;
|
|
4986
|
+
isCompleted;
|
|
4987
|
+
// Add completion flag
|
|
4988
|
+
constructor(fileName, fileCount, totalSize, spinner) {
|
|
4989
|
+
this.fileName = fileName;
|
|
4990
|
+
this.fileCount = fileCount;
|
|
4991
|
+
this.totalSize = totalSize;
|
|
4992
|
+
this.spinner = spinner;
|
|
4993
|
+
this.timeConstant = this.calcTimeConstant(fileCount, totalSize);
|
|
4994
|
+
this.startTime = Date.now();
|
|
4995
|
+
this.uploadStartTime = 0;
|
|
4996
|
+
this.isUploading = false;
|
|
4997
|
+
this.isPolling = false;
|
|
4998
|
+
this.isCompleted = false;
|
|
4999
|
+
}
|
|
5000
|
+
// Calculate time constant based on file count and total size
|
|
5001
|
+
calcTimeConstant(fileCount, totalSize) {
|
|
5002
|
+
const base = 8e3;
|
|
5003
|
+
const countFactor = 0.3 * Math.log(1 + fileCount);
|
|
5004
|
+
const sizeFactor = 0.7 * Math.log(1 + totalSize / 1024 / 1024);
|
|
5005
|
+
const minTimeConstant = 15e3;
|
|
5006
|
+
const calculatedTimeConstant = base * (1 + countFactor + sizeFactor);
|
|
5007
|
+
return Math.max(calculatedTimeConstant, minTimeConstant);
|
|
5008
|
+
}
|
|
5009
|
+
// Calculate progress using exponential decay model with upper limit
|
|
5010
|
+
calculateProgress() {
|
|
5011
|
+
const elapsed = Date.now() - this.startTime;
|
|
5012
|
+
const rawProgress = 1 - Math.exp(-elapsed / this.timeConstant);
|
|
5013
|
+
const maxProgress = this.isPolling ? 0.95 : 0.9;
|
|
5014
|
+
return Math.min(rawProgress, maxProgress);
|
|
5015
|
+
}
|
|
5016
|
+
// Start upload phase
|
|
5017
|
+
startUpload() {
|
|
5018
|
+
this.isUploading = true;
|
|
5019
|
+
this.uploadStartTime = Date.now();
|
|
5020
|
+
}
|
|
5021
|
+
// Start polling phase
|
|
5022
|
+
startPolling() {
|
|
5023
|
+
this.isPolling = true;
|
|
5024
|
+
this.isUploading = false;
|
|
5025
|
+
}
|
|
5026
|
+
// Update progress display
|
|
5027
|
+
update() {
|
|
5028
|
+
if (this.isCompleted) {
|
|
5029
|
+
return;
|
|
5030
|
+
}
|
|
5031
|
+
const progress = this.calculateProgress();
|
|
5032
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5033
|
+
const progressBar = this.createProgressBar(progress);
|
|
5034
|
+
const duration = this.formatDuration(elapsed);
|
|
5035
|
+
let status = "";
|
|
5036
|
+
if (this.isUploading) {
|
|
5037
|
+
status = "uploading";
|
|
5038
|
+
} else if (this.isPolling) {
|
|
5039
|
+
status = "processing";
|
|
5040
|
+
} else {
|
|
5041
|
+
status = "preparing";
|
|
5042
|
+
}
|
|
5043
|
+
const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
|
|
5044
|
+
this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
|
|
4948
5045
|
}
|
|
4949
|
-
|
|
5046
|
+
// Update time display only (called every second)
|
|
5047
|
+
updateTime() {
|
|
5048
|
+
if (this.isCompleted) {
|
|
5049
|
+
return;
|
|
5050
|
+
}
|
|
5051
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5052
|
+
const duration = this.formatDuration(elapsed);
|
|
5053
|
+
const progress = this.calculateProgress();
|
|
5054
|
+
const progressBar = this.createProgressBar(progress);
|
|
5055
|
+
let status = "";
|
|
5056
|
+
if (this.isUploading) {
|
|
5057
|
+
status = "uploading";
|
|
5058
|
+
} else if (this.isPolling) {
|
|
5059
|
+
status = "processing";
|
|
5060
|
+
} else {
|
|
5061
|
+
status = "preparing";
|
|
5062
|
+
}
|
|
5063
|
+
const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
|
|
5064
|
+
this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
|
|
5065
|
+
}
|
|
5066
|
+
// Update progress bar only (called every 200ms)
|
|
5067
|
+
updateProgress() {
|
|
5068
|
+
if (this.isCompleted) {
|
|
5069
|
+
return;
|
|
5070
|
+
}
|
|
5071
|
+
const progress = this.calculateProgress();
|
|
5072
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5073
|
+
const progressBar = this.createProgressBar(progress);
|
|
5074
|
+
const duration = this.formatDuration(elapsed);
|
|
5075
|
+
let status = "";
|
|
5076
|
+
if (this.isUploading) {
|
|
5077
|
+
status = "uploading";
|
|
5078
|
+
} else if (this.isPolling) {
|
|
5079
|
+
status = "processing";
|
|
5080
|
+
} else {
|
|
5081
|
+
status = "preparing";
|
|
5082
|
+
}
|
|
5083
|
+
const fileInfo = this.fileCount > 1 ? `${this.fileName} (${this.fileCount} files)` : this.fileName;
|
|
5084
|
+
this.spinner.text = `Uploading ${fileInfo} ${progressBar} ${duration} (${status})`;
|
|
5085
|
+
}
|
|
5086
|
+
// Update display (for manual updates)
|
|
5087
|
+
updateDisplay() {
|
|
5088
|
+
this.updateTime();
|
|
5089
|
+
}
|
|
5090
|
+
// Update progress display only (no progress bar)
|
|
5091
|
+
updateTimeOnly() {
|
|
5092
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5093
|
+
const duration = this.formatDuration(elapsed);
|
|
5094
|
+
this.spinner.text = `Uploading ${this.fileName} ${duration}`;
|
|
5095
|
+
}
|
|
5096
|
+
// Complete progress
|
|
5097
|
+
complete(traceId) {
|
|
5098
|
+
if (this.isCompleted) {
|
|
5099
|
+
return;
|
|
5100
|
+
}
|
|
5101
|
+
const progressBar = this.createProgressBar(1);
|
|
5102
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5103
|
+
const duration = this.formatDuration(elapsed);
|
|
5104
|
+
this.spinner.succeed(`Upload completed ${progressBar} ${duration}`);
|
|
5105
|
+
this.isCompleted = true;
|
|
5106
|
+
}
|
|
5107
|
+
// Fail progress
|
|
5108
|
+
fail(message, traceId) {
|
|
5109
|
+
if (this.isCompleted) {
|
|
5110
|
+
return;
|
|
5111
|
+
}
|
|
5112
|
+
const elapsed = Math.floor((Date.now() - this.startTime) / 1e3);
|
|
5113
|
+
const duration = this.formatDuration(elapsed);
|
|
5114
|
+
this.spinner.fail(`${message} ${duration}`);
|
|
5115
|
+
this.isCompleted = true;
|
|
5116
|
+
}
|
|
5117
|
+
// Create visual progress bar
|
|
5118
|
+
createProgressBar(progress, width = 20) {
|
|
5119
|
+
const percentage = Math.min(progress, 1);
|
|
5120
|
+
const filledWidth = Math.round(width * percentage);
|
|
5121
|
+
const emptyWidth = width - filledWidth;
|
|
5122
|
+
const filled = "\u2588".repeat(filledWidth);
|
|
5123
|
+
const empty = "\u2591".repeat(emptyWidth);
|
|
5124
|
+
return `[${filled}${empty}] ${Math.round(percentage * 100)}%`;
|
|
5125
|
+
}
|
|
5126
|
+
// Format time duration
|
|
5127
|
+
formatDuration(seconds) {
|
|
5128
|
+
if (seconds < 60) {
|
|
5129
|
+
return `${seconds}s`;
|
|
5130
|
+
} else if (seconds < 3600) {
|
|
5131
|
+
const minutes = Math.floor(seconds / 60);
|
|
5132
|
+
const remainingSeconds = seconds % 60;
|
|
5133
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
5134
|
+
} else {
|
|
5135
|
+
const hours = Math.floor(seconds / 3600);
|
|
5136
|
+
const minutes = Math.floor(seconds % 3600 / 60);
|
|
5137
|
+
const remainingSeconds = seconds % 60;
|
|
5138
|
+
return `${hours}h ${minutes}m ${remainingSeconds}s`;
|
|
5139
|
+
}
|
|
5140
|
+
}
|
|
5141
|
+
};
|
|
4950
5142
|
async function uploadToIpfs_default(filePath) {
|
|
4951
5143
|
const deviceId = getDeviceId();
|
|
4952
5144
|
if (!deviceId) {
|