@yetech/estra7ah 3.3.0 → 3.3.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/estra7ah.js +99 -26
- package/package.json +1 -1
package/dist/estra7ah.js
CHANGED
|
@@ -36,6 +36,102 @@ function getRunner() {
|
|
|
36
36
|
throw new Error("Unsupported platform");
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
// The VPS caps throughput per TCP connection (~2.5 MB/s), not in total, so
|
|
40
|
+
// pulling the binary over several range requests at once is ~N times faster.
|
|
41
|
+
const PARALLEL_CHUNKS = 6;
|
|
42
|
+
|
|
43
|
+
function downloadRange(url, fd, start, end, progressBar, attempt = 0) {
|
|
44
|
+
return axios({
|
|
45
|
+
method: "get",
|
|
46
|
+
url,
|
|
47
|
+
responseType: "stream",
|
|
48
|
+
headers: { Range: `bytes=${start}-${end}` },
|
|
49
|
+
timeout: 0,
|
|
50
|
+
})
|
|
51
|
+
.then(
|
|
52
|
+
(response) =>
|
|
53
|
+
new Promise((resolve, reject) => {
|
|
54
|
+
let position = start;
|
|
55
|
+
response.data.on("data", (chunk) => {
|
|
56
|
+
fs.writeSync(fd, chunk, 0, chunk.length, position);
|
|
57
|
+
position += chunk.length;
|
|
58
|
+
progressBar.tick(chunk.length);
|
|
59
|
+
});
|
|
60
|
+
response.data.on("end", () => resolve(position));
|
|
61
|
+
response.data.on("error", (err) => reject({ err, position }));
|
|
62
|
+
})
|
|
63
|
+
)
|
|
64
|
+
.catch((failure) => {
|
|
65
|
+
const resumeAt = failure.position || start;
|
|
66
|
+
if (attempt < 2) return downloadRange(url, fd, resumeAt, end, progressBar, attempt + 1);
|
|
67
|
+
throw failure.err || failure;
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function downloadFileFast(url, destPath) {
|
|
72
|
+
let totalLength = 0;
|
|
73
|
+
try {
|
|
74
|
+
const head = await axios.head(url, { timeout: 10000 });
|
|
75
|
+
if ((head.headers["accept-ranges"] || "").includes("bytes")) {
|
|
76
|
+
totalLength = parseInt(head.headers["content-length"], 10) || 0;
|
|
77
|
+
}
|
|
78
|
+
} catch (error) {
|
|
79
|
+
// fall through to single-stream download
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (!totalLength) return downloadFileStream(url, destPath);
|
|
83
|
+
|
|
84
|
+
const progressBar = new ProgressBar("Downloading [:bar] :percent :etas", {
|
|
85
|
+
width: 40,
|
|
86
|
+
complete: "=",
|
|
87
|
+
incomplete: " ",
|
|
88
|
+
total: totalLength,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
// Download to a temp file so a failed/interrupted update never corrupts
|
|
92
|
+
// the runner binary we already have.
|
|
93
|
+
const tmpPath = `${destPath}.download`;
|
|
94
|
+
const fd = fs.openSync(tmpPath, "w");
|
|
95
|
+
try {
|
|
96
|
+
fs.ftruncateSync(fd, totalLength);
|
|
97
|
+
const chunkSize = Math.ceil(totalLength / PARALLEL_CHUNKS);
|
|
98
|
+
const jobs = [];
|
|
99
|
+
for (let start = 0; start < totalLength; start += chunkSize) {
|
|
100
|
+
const end = Math.min(start + chunkSize - 1, totalLength - 1);
|
|
101
|
+
jobs.push(downloadRange(url, fd, start, end, progressBar));
|
|
102
|
+
}
|
|
103
|
+
await Promise.all(jobs);
|
|
104
|
+
} catch (error) {
|
|
105
|
+
fs.closeSync(fd);
|
|
106
|
+
fs.unlinkSync(tmpPath);
|
|
107
|
+
throw error;
|
|
108
|
+
}
|
|
109
|
+
fs.closeSync(fd);
|
|
110
|
+
fs.renameSync(tmpPath, destPath);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function downloadFileStream(url, destPath) {
|
|
114
|
+
return axios({ method: "get", url, responseType: "stream" }).then((response) => {
|
|
115
|
+
const totalLength = parseInt(response.headers["content-length"], 10);
|
|
116
|
+
const progressBar = totalLength
|
|
117
|
+
? new ProgressBar("Downloading [:bar] :percent :etas", {
|
|
118
|
+
width: 40,
|
|
119
|
+
complete: "=",
|
|
120
|
+
incomplete: " ",
|
|
121
|
+
total: totalLength,
|
|
122
|
+
})
|
|
123
|
+
: null;
|
|
124
|
+
const writer = fs.createWriteStream(destPath);
|
|
125
|
+
return new Promise((resolve, reject) => {
|
|
126
|
+
if (progressBar) response.data.on("data", (chunk) => progressBar.tick(chunk.length));
|
|
127
|
+
writer.on("error", reject);
|
|
128
|
+
writer.on("finish", resolve);
|
|
129
|
+
response.data.on("error", reject);
|
|
130
|
+
response.data.pipe(writer);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
39
135
|
// Download the runner executable
|
|
40
136
|
async function downloadRunner() {
|
|
41
137
|
let version = null;
|
|
@@ -60,32 +156,9 @@ async function downloadRunner() {
|
|
|
60
156
|
const runnerPath = `${DIR_NAME}/${getRunner()}`;
|
|
61
157
|
|
|
62
158
|
try {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
responseType: "stream",
|
|
67
|
-
});
|
|
68
|
-
|
|
69
|
-
const totalLength = parseInt(response.headers["content-length"], 10);
|
|
70
|
-
const progressBar = new ProgressBar("Downloading [:bar] :percent :etas", {
|
|
71
|
-
width: 40,
|
|
72
|
-
complete: "=",
|
|
73
|
-
incomplete: " ",
|
|
74
|
-
total: totalLength,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const writer = fs.createWriteStream(runnerPath);
|
|
78
|
-
|
|
79
|
-
return new Promise((resolve, reject) => {
|
|
80
|
-
response.data.on("data", (chunk) => progressBar.tick(chunk.length));
|
|
81
|
-
writer.on("error", reject);
|
|
82
|
-
writer.on("finish", () => {
|
|
83
|
-
fs.writeFileSync(versionFilePath, version);
|
|
84
|
-
console.log("** Finished DOWNLOADING NEW RUNNER VERSION **");
|
|
85
|
-
resolve();
|
|
86
|
-
});
|
|
87
|
-
response.data.pipe(writer);
|
|
88
|
-
});
|
|
159
|
+
await downloadFileFast(serverFile, runnerPath);
|
|
160
|
+
fs.writeFileSync(versionFilePath, version);
|
|
161
|
+
console.log("** Finished DOWNLOADING NEW RUNNER VERSION **");
|
|
89
162
|
} catch (error) {
|
|
90
163
|
console.error("Error downloading runner:", error.message);
|
|
91
164
|
}
|