swayrouter 1.0.1 → 1.0.2
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/README.id.md +6 -1
- package/README.md +6 -1
- package/package.json +1 -1
- package/src/lib/tunnel/cloudflare/cloudflared.js +84 -29
package/README.id.md
CHANGED
|
@@ -149,12 +149,17 @@ Kalau mau ngembangin dashboard, jalanin `bun run dev` di dalam folder
|
|
|
149
149
|
|
|
150
150
|
### Docker — terisolasi dan datanya persistent
|
|
151
151
|
|
|
152
|
+
Gunakan image publik dari Docker Hub:
|
|
153
|
+
|
|
152
154
|
```bash
|
|
153
|
-
docker
|
|
155
|
+
docker pull envielxyz/swayrouter:latest
|
|
154
156
|
docker compose up -d
|
|
155
157
|
docker compose ps
|
|
156
158
|
```
|
|
157
159
|
|
|
160
|
+
Kalau ingin build image dari source, jalankan `docker build -t envielxyz/swayrouter:latest .`
|
|
161
|
+
sebelum menjalankan Compose.
|
|
162
|
+
|
|
158
163
|
Docker juga membuat secret persistent di data volume. Copy `.env.example`
|
|
159
164
|
menjadi `.env` hanya kalau kamu ingin memberi override deployment sendiri.
|
|
160
165
|
|
package/README.md
CHANGED
|
@@ -149,12 +149,17 @@ second terminal.
|
|
|
149
149
|
|
|
150
150
|
### Docker — isolated and persistent
|
|
151
151
|
|
|
152
|
+
Use the public image from Docker Hub:
|
|
153
|
+
|
|
152
154
|
```bash
|
|
153
|
-
docker
|
|
155
|
+
docker pull envielxyz/swayrouter:latest
|
|
154
156
|
docker compose up -d
|
|
155
157
|
docker compose ps
|
|
156
158
|
```
|
|
157
159
|
|
|
160
|
+
To build the image from source instead, run `docker build -t envielxyz/swayrouter:latest .`
|
|
161
|
+
before starting Compose.
|
|
162
|
+
|
|
158
163
|
Docker also generates persistent secrets in its data volume. Copy
|
|
159
164
|
`.env.example` to `.env` only when you want explicit deployment overrides.
|
|
160
165
|
|
package/package.json
CHANGED
|
@@ -58,22 +58,45 @@ export function getDownloadStatus() {
|
|
|
58
58
|
return { downloading: dlState.downloading, progress: dlState.progress };
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
function wait(ms) {
|
|
62
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function removeFile(filePath) {
|
|
66
|
+
try {
|
|
67
|
+
fs.unlinkSync(filePath);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
if (error?.code !== "ENOENT") throw error;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
61
73
|
function downloadFile(url, dest) {
|
|
62
74
|
return new Promise((resolve, reject) => {
|
|
63
75
|
const file = fs.createWriteStream(dest);
|
|
76
|
+
let settled = false;
|
|
77
|
+
|
|
78
|
+
const fail = (error) => {
|
|
79
|
+
if (settled) return;
|
|
80
|
+
settled = true;
|
|
81
|
+
dlState.downloading = false;
|
|
82
|
+
dlState.progress = 0;
|
|
83
|
+
file.destroy();
|
|
84
|
+
try { removeFile(dest); } catch {}
|
|
85
|
+
reject(error);
|
|
86
|
+
};
|
|
64
87
|
|
|
65
88
|
https.get(url, (response) => {
|
|
66
89
|
if ([301, 302, 303, 307, 308].includes(response.statusCode)) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
90
|
+
response.resume();
|
|
91
|
+
file.destroy();
|
|
92
|
+
try { removeFile(dest); } catch (error) { fail(error); return; }
|
|
93
|
+
downloadFile(response.headers.location, dest).then(resolve).catch(fail);
|
|
70
94
|
return;
|
|
71
95
|
}
|
|
72
96
|
|
|
73
97
|
if (response.statusCode !== 200) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
reject(new Error(`Download failed with status ${response.statusCode}`));
|
|
98
|
+
response.resume();
|
|
99
|
+
fail(new Error(`Download failed with status ${response.statusCode}`));
|
|
77
100
|
return;
|
|
78
101
|
}
|
|
79
102
|
|
|
@@ -90,25 +113,18 @@ function downloadFile(url, dest) {
|
|
|
90
113
|
response.pipe(file);
|
|
91
114
|
|
|
92
115
|
file.on("finish", () => {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
116
|
+
file.once("close", () => {
|
|
117
|
+
if (settled) return;
|
|
118
|
+
settled = true;
|
|
119
|
+
dlState.downloading = false;
|
|
120
|
+
dlState.progress = 100;
|
|
121
|
+
resolve(dest);
|
|
122
|
+
});
|
|
96
123
|
});
|
|
97
124
|
|
|
98
|
-
file.on("error",
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
file.close();
|
|
102
|
-
fs.unlinkSync(dest);
|
|
103
|
-
reject(err);
|
|
104
|
-
});
|
|
105
|
-
}).on("error", (err) => {
|
|
106
|
-
dlState.downloading = false;
|
|
107
|
-
dlState.progress = 0;
|
|
108
|
-
file.close();
|
|
109
|
-
if (fs.existsSync(dest)) fs.unlinkSync(dest);
|
|
110
|
-
reject(err);
|
|
111
|
-
});
|
|
125
|
+
file.on("error", fail);
|
|
126
|
+
response.on("error", fail);
|
|
127
|
+
}).on("error", fail);
|
|
112
128
|
});
|
|
113
129
|
}
|
|
114
130
|
|
|
@@ -131,6 +147,38 @@ function isValidBinary(filePath) {
|
|
|
131
147
|
}
|
|
132
148
|
}
|
|
133
149
|
|
|
150
|
+
async function installDownloadedBinary(downloadPath) {
|
|
151
|
+
if (!isValidBinary(downloadPath)) {
|
|
152
|
+
throw new Error("Downloaded cloudflared binary is invalid");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let lastError = null;
|
|
156
|
+
for (let attempt = 0; attempt < 6; attempt++) {
|
|
157
|
+
try {
|
|
158
|
+
if (fs.existsSync(BIN_PATH)) removeFile(BIN_PATH);
|
|
159
|
+
fs.renameSync(downloadPath, BIN_PATH);
|
|
160
|
+
if (!isValidBinary(BIN_PATH)) throw new Error("Installed cloudflared binary is invalid");
|
|
161
|
+
return;
|
|
162
|
+
} catch (error) {
|
|
163
|
+
lastError = error;
|
|
164
|
+
if (IS_WINDOWS && fs.existsSync(downloadPath)) {
|
|
165
|
+
try {
|
|
166
|
+
fs.copyFileSync(downloadPath, BIN_PATH);
|
|
167
|
+
if (isValidBinary(BIN_PATH)) {
|
|
168
|
+
try { removeFile(downloadPath); } catch {}
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
} catch (copyError) {
|
|
172
|
+
lastError = copyError;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
await wait(150 * (attempt + 1));
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
throw new Error(`Unable to install cloudflared binary: ${lastError?.message || "unknown file error"}`);
|
|
180
|
+
}
|
|
181
|
+
|
|
134
182
|
let downloadPromise = null;
|
|
135
183
|
|
|
136
184
|
export async function ensureCloudflared() {
|
|
@@ -146,7 +194,9 @@ async function _ensureCloudflared() {
|
|
|
146
194
|
|
|
147
195
|
const tmpPath = `${BIN_PATH}.tmp`;
|
|
148
196
|
if (fs.existsSync(tmpPath)) {
|
|
149
|
-
try {
|
|
197
|
+
try { removeFile(tmpPath); } catch (error) {
|
|
198
|
+
throw new Error(`Unable to clear stale cloudflared download: ${error.message}`);
|
|
199
|
+
}
|
|
150
200
|
}
|
|
151
201
|
|
|
152
202
|
if (fs.existsSync(BIN_PATH)) {
|
|
@@ -165,11 +215,16 @@ async function _ensureCloudflared() {
|
|
|
165
215
|
|
|
166
216
|
await downloadFile(url, downloadDest);
|
|
167
217
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
218
|
+
try {
|
|
219
|
+
if (isArchive) {
|
|
220
|
+
execSync(`tar -xzf "${downloadDest}" -C "${BIN_DIR}"`, { stdio: "pipe", windowsHide: true });
|
|
221
|
+
removeFile(downloadDest);
|
|
222
|
+
} else {
|
|
223
|
+
await installDownloadedBinary(downloadDest);
|
|
224
|
+
}
|
|
225
|
+
} catch (error) {
|
|
226
|
+
try { removeFile(downloadDest); } catch {}
|
|
227
|
+
throw error;
|
|
173
228
|
}
|
|
174
229
|
|
|
175
230
|
if (!IS_WINDOWS) {
|