dsh-mobile 0.6.8 → 0.6.9
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/CHANGELOG.md +15 -3
- package/CONTRIBUTORS.md +1 -1
- package/README.en.md +13 -7
- package/README.md +13 -7
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/apps/mobile/README.md +11 -7
- package/apps/mobile/release.json +3 -3
- package/docs/CADDY_MANAGED.en.md +21 -17
- package/docs/CADDY_MANAGED.md +21 -17
- package/docs/README.md +3 -3
- package/docs/SELF_HOSTED_FRP.en.md +1 -1
- package/docs/SELF_HOSTED_FRP.md +1 -1
- package/docs/SELF_HOSTED_ORIGIN.en.md +3 -1
- package/docs/SELF_HOSTED_ORIGIN.md +4 -2
- package/lib/client.js +9 -9
- package/lib/client.js.map +1 -1
- package/lib/index.mjs +201 -45
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/packages/question-fixes/package.json +1 -1
package/lib/index.mjs
CHANGED
|
@@ -10610,6 +10610,8 @@ var RemoteProviderCoordinator = class {
|
|
|
10610
10610
|
store;
|
|
10611
10611
|
selectedValue;
|
|
10612
10612
|
queue = Promise.resolve();
|
|
10613
|
+
closing = false;
|
|
10614
|
+
closeTask;
|
|
10613
10615
|
constructor(selected, controllers, store) {
|
|
10614
10616
|
this.controllers = controllers;
|
|
10615
10617
|
this.store = store;
|
|
@@ -10661,8 +10663,16 @@ var RemoteProviderCoordinator = class {
|
|
|
10661
10663
|
}
|
|
10662
10664
|
});
|
|
10663
10665
|
}
|
|
10666
|
+
/** Stop admitting mutations and wait for accepted work before callers release provider resources. */
|
|
10667
|
+
close() {
|
|
10668
|
+
this.closing = true;
|
|
10669
|
+
this.closeTask ??= this.queue;
|
|
10670
|
+
return this.closeTask;
|
|
10671
|
+
}
|
|
10664
10672
|
enqueue(operation) {
|
|
10665
|
-
|
|
10673
|
+
if (this.closing) return Promise.reject(/* @__PURE__ */ new Error("remote_provider_closed"));
|
|
10674
|
+
const run = () => this.closing ? Promise.reject(/* @__PURE__ */ new Error("remote_provider_closed")) : this.runAndEnforce(operation);
|
|
10675
|
+
const task = this.queue.then(run, run);
|
|
10666
10676
|
this.queue = task.then(() => void 0, () => void 0);
|
|
10667
10677
|
return task;
|
|
10668
10678
|
}
|
|
@@ -13353,6 +13363,8 @@ const MOBILE_CUSTOMIZATION_GUIDE_BODY = `你在为用户定制 DSH Mobile 的手
|
|
|
13353
13363
|
|
|
13354
13364
|
动手前先读已有的定制文件。若要调整 DSH 自带的输入框、侧栏或设置等现有界面,先确认当前 DSH 版本与手机页面模式(专用移动页面或 ?frontend=stock),只读核对运行页面的 DOM、属性和样式;本机有同版本前端源码时可参考相应组件,没有源码时可查看已安装的客户端产物,不必下载源码。优先使用扩展 API、插槽和稳定的 data-* 标记,不凭猜测依赖构建类名。只读查看不改变前述写入范围。
|
|
13355
13365
|
|
|
13366
|
+
旧 CSS 可能覆盖新版内置修复。先备份并在同一会话、方向和字号下对比有无该样式,不要无症状叠加旧补丁。CSS Modules 的后缀/子串匹配必须限定到已核对的区域祖先,例如 [data-dsh-mobile-header] [class*="_titleRow"];不要裸匹配整页。display: none 会让其中的操作不可用,不得把隐藏功能描述成折叠。
|
|
13367
|
+
|
|
13356
13368
|
2. 电脑端能力 —— 手机需要读电脑文件、执行命令或访问硬件时,创建扩展:
|
|
13357
13369
|
- 目录:$DSH_HOME/mobile-access/extensions/<id>/,id 用小写字母数字和连字符(如 media-remote)
|
|
13358
13370
|
- extension.json:{"schemaVersion":1,"id":"<id>","name":"显示名","version":"0.1.0","description":"说明"}
|
|
@@ -15295,10 +15307,35 @@ async function removeCaddyTree(root, target) {
|
|
|
15295
15307
|
}
|
|
15296
15308
|
//#endregion
|
|
15297
15309
|
//#region src/caddy-component.ts
|
|
15298
|
-
const CADDY_VERSION = "2.11.
|
|
15310
|
+
const CADDY_VERSION = "2.11.7";
|
|
15299
15311
|
const CADDY_DNS_PLUGIN_VERSION = "v0.4.3";
|
|
15300
|
-
const CADDY_DOWNLOAD_PAGE = "https://
|
|
15301
|
-
const CADDY_COMPONENT_RELEASES = Object.freeze({
|
|
15312
|
+
const CADDY_DOWNLOAD_PAGE = "https://github.com/saya-ch/dsh-mobile/releases/tag/caddy-component-2.11.7-tencentcloud-0.4.3-r1";
|
|
15313
|
+
const CADDY_COMPONENT_RELEASES = Object.freeze({
|
|
15314
|
+
"linux-x64": Object.freeze({
|
|
15315
|
+
version: CADDY_VERSION,
|
|
15316
|
+
dnsPluginVersion: CADDY_DNS_PLUGIN_VERSION,
|
|
15317
|
+
platform: "linux",
|
|
15318
|
+
arch: "x64",
|
|
15319
|
+
executableName: "caddy",
|
|
15320
|
+
downloadUrl: "https://github.com/saya-ch/dsh-mobile/releases/download/caddy-component-2.11.7-tencentcloud-0.4.3-r1/caddy-2.11.7-tencentcloud-0.4.3-linux-x64",
|
|
15321
|
+
downloadBytes: 81995704,
|
|
15322
|
+
executableBytes: 81995704,
|
|
15323
|
+
downloadSha256: "13652ef9ea3792ebff772a5b873ade63ed6de1c0a794bb3403a523639b8f57af",
|
|
15324
|
+
executableSha256: "13652ef9ea3792ebff772a5b873ade63ed6de1c0a794bb3403a523639b8f57af"
|
|
15325
|
+
}),
|
|
15326
|
+
"win32-x64": Object.freeze({
|
|
15327
|
+
version: CADDY_VERSION,
|
|
15328
|
+
dnsPluginVersion: CADDY_DNS_PLUGIN_VERSION,
|
|
15329
|
+
platform: "win32",
|
|
15330
|
+
arch: "x64",
|
|
15331
|
+
executableName: "caddy.exe",
|
|
15332
|
+
downloadUrl: "https://github.com/saya-ch/dsh-mobile/releases/download/caddy-component-2.11.7-tencentcloud-0.4.3-r1/caddy-2.11.7-tencentcloud-0.4.3-win32-x64.exe",
|
|
15333
|
+
downloadBytes: 82816e3,
|
|
15334
|
+
executableBytes: 82816e3,
|
|
15335
|
+
downloadSha256: "962f7937a06e1e737513d2d1d4ad75df54ba503d36fa2a458912bd38fbd0094a",
|
|
15336
|
+
executableSha256: "962f7937a06e1e737513d2d1d4ad75df54ba503d36fa2a458912bd38fbd0094a"
|
|
15337
|
+
})
|
|
15338
|
+
});
|
|
15302
15339
|
Object.freeze({
|
|
15303
15340
|
version: CADDY_VERSION,
|
|
15304
15341
|
dnsPluginVersion: CADDY_DNS_PLUGIN_VERSION
|
|
@@ -15322,14 +15359,16 @@ function caddyInspectionEnvironment(environment = process.env) {
|
|
|
15322
15359
|
]) if (environment[name] !== void 0) result[name] = environment[name];
|
|
15323
15360
|
return result;
|
|
15324
15361
|
}
|
|
15325
|
-
async function inspect(executable) {
|
|
15362
|
+
async function inspect(executable, assertOpen) {
|
|
15326
15363
|
const options = {
|
|
15327
15364
|
env: caddyInspectionEnvironment(),
|
|
15328
15365
|
timeout: 15e3,
|
|
15329
15366
|
maxBuffer: 262144
|
|
15330
15367
|
};
|
|
15368
|
+
const version = (await execFileText(executable, ["version"], options)).stdout.trim();
|
|
15369
|
+
assertOpen();
|
|
15331
15370
|
return {
|
|
15332
|
-
version
|
|
15371
|
+
version,
|
|
15333
15372
|
modules: (await execFileText(executable, ["list-modules", "--versions"], options)).stdout
|
|
15334
15373
|
};
|
|
15335
15374
|
}
|
|
@@ -15348,6 +15387,10 @@ var CaddyComponentManager = class {
|
|
|
15348
15387
|
installed = false;
|
|
15349
15388
|
errorCode;
|
|
15350
15389
|
queue = Promise.resolve();
|
|
15390
|
+
closed = false;
|
|
15391
|
+
closing;
|
|
15392
|
+
download;
|
|
15393
|
+
cleanupPaths = /* @__PURE__ */ new Set();
|
|
15351
15394
|
constructor(options) {
|
|
15352
15395
|
if (!isAbsolute(options.stateDirectory)) throw new Error("caddy state directory must be absolute");
|
|
15353
15396
|
this.stateDirectory = resolve(options.stateDirectory);
|
|
@@ -15357,7 +15400,7 @@ var CaddyComponentManager = class {
|
|
|
15357
15400
|
if (artifact !== void 0 && (artifact.platform !== platform || artifact.arch !== arch || !/^https:\/\//u.test(artifact.downloadUrl) || !/^[a-f0-9]{64}$/u.test(artifact.downloadSha256) || !/^[a-f0-9]{64}$/u.test(artifact.executableSha256) || artifact.downloadBytes < 1 || artifact.executableBytes < 1 || !/^[a-z0-9.-]+$/u.test(artifact.executableName))) throw new Error("caddy_artifact_invalid");
|
|
15358
15401
|
this.artifact = artifact;
|
|
15359
15402
|
this.componentRoot = join(this.stateDirectory, "components", "caddy");
|
|
15360
|
-
this.componentStorage = join(this.componentRoot, artifact?.version ?? "2.11.
|
|
15403
|
+
this.componentStorage = join(this.componentRoot, artifact?.version ?? "2.11.7");
|
|
15361
15404
|
this.executable = join(this.componentStorage, artifact?.executableName ?? (platform === "win32" ? "caddy.exe" : "caddy"));
|
|
15362
15405
|
this.logRoot = join(this.stateDirectory, "caddy", "logs");
|
|
15363
15406
|
this.stagingRoot = join(this.stateDirectory, "staging", "caddy");
|
|
@@ -15367,41 +15410,48 @@ var CaddyComponentManager = class {
|
|
|
15367
15410
|
expectedBytes: artifact?.downloadBytes ?? 0,
|
|
15368
15411
|
errorPrefix: "caddy"
|
|
15369
15412
|
}));
|
|
15370
|
-
this.inspectExecutable = options.inspectExecutable ?? inspect;
|
|
15413
|
+
this.inspectExecutable = options.inspectExecutable ?? ((executable) => inspect(executable, () => this.assertOpen()));
|
|
15371
15414
|
this.promote = options.promoteDirectory ?? ((source, destination) => renameCaddyPath(this.stateDirectory, source, destination));
|
|
15372
15415
|
}
|
|
15373
15416
|
/** Recheck a pinned executable before launching; no unverified local binary can run. */
|
|
15374
|
-
|
|
15417
|
+
ensureExecutable() {
|
|
15418
|
+
return this.enqueue(() => this.checkExecutable());
|
|
15419
|
+
}
|
|
15420
|
+
async checkExecutable() {
|
|
15375
15421
|
const artifact = this.artifact;
|
|
15376
15422
|
if (artifact === void 0) throw new Error("caddy_component_unavailable");
|
|
15377
15423
|
await assertCaddyParents(this.stateDirectory, this.executable);
|
|
15424
|
+
this.assertOpen();
|
|
15378
15425
|
const entry = await lstat(this.executable);
|
|
15379
15426
|
if (!entry.isFile() || entry.isSymbolicLink() || entry.size !== artifact.executableBytes || await digest(this.executable) !== artifact.executableSha256) throw new Error("caddy_component_invalid");
|
|
15380
15427
|
await this.verifyMetadata(this.executable, artifact);
|
|
15381
15428
|
}
|
|
15382
15429
|
async initialize() {
|
|
15383
|
-
this.
|
|
15384
|
-
|
|
15385
|
-
|
|
15386
|
-
this.
|
|
15387
|
-
|
|
15388
|
-
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
|
|
15392
|
-
|
|
15393
|
-
|
|
15394
|
-
|
|
15430
|
+
return this.enqueue(async () => {
|
|
15431
|
+
this.installed = false;
|
|
15432
|
+
this.errorCode = void 0;
|
|
15433
|
+
if (this.artifact === void 0) {
|
|
15434
|
+
this.errorCode = "caddy_component_unavailable";
|
|
15435
|
+
return;
|
|
15436
|
+
}
|
|
15437
|
+
try {
|
|
15438
|
+
await this.checkExecutable();
|
|
15439
|
+
this.installed = true;
|
|
15440
|
+
} catch (error) {
|
|
15441
|
+
this.assertOpen();
|
|
15442
|
+
if (error.code !== "ENOENT") this.errorCode = "caddy_component_invalid";
|
|
15443
|
+
}
|
|
15444
|
+
});
|
|
15395
15445
|
}
|
|
15396
15446
|
status() {
|
|
15397
15447
|
const artifact = this.artifact;
|
|
15398
15448
|
return Object.freeze({
|
|
15399
15449
|
supported: artifact !== void 0,
|
|
15400
15450
|
installed: this.installed,
|
|
15401
|
-
version: artifact?.version ?? "2.11.
|
|
15451
|
+
version: artifact?.version ?? "2.11.7",
|
|
15402
15452
|
downloadBytes: artifact?.downloadBytes ?? 0,
|
|
15403
15453
|
installedBytes: this.installed ? artifact?.executableBytes ?? 0 : 0,
|
|
15404
|
-
sourceUrl: artifact?.downloadUrl ?? "https://
|
|
15454
|
+
sourceUrl: artifact?.downloadUrl ?? "https://github.com/saya-ch/dsh-mobile/releases/tag/caddy-component-2.11.7-tencentcloud-0.4.3-r1",
|
|
15405
15455
|
downloadPage: CADDY_DOWNLOAD_PAGE,
|
|
15406
15456
|
storagePath: this.componentRoot,
|
|
15407
15457
|
...this.errorCode === void 0 ? {} : { errorCode: this.errorCode }
|
|
@@ -15413,28 +15463,40 @@ var CaddyComponentManager = class {
|
|
|
15413
15463
|
const artifact = this.artifact;
|
|
15414
15464
|
if (artifact === void 0) throw new Error("caddy_component_unavailable");
|
|
15415
15465
|
await ensureCaddyDirectory(this.stateDirectory, this.stagingRoot);
|
|
15466
|
+
this.assertOpen();
|
|
15416
15467
|
await ensureCaddyDirectory(this.stateDirectory, this.componentRoot);
|
|
15468
|
+
this.assertOpen();
|
|
15417
15469
|
const staging = await mkdtemp(join(this.stagingRoot, "install-"));
|
|
15418
15470
|
const candidate = join(this.componentRoot, ".install-" + randomBytes(12).toString("hex"));
|
|
15419
15471
|
const backup = join(this.componentRoot, ".previous-" + randomBytes(12).toString("hex"));
|
|
15420
15472
|
let previous = false;
|
|
15421
15473
|
let promoted = false;
|
|
15422
15474
|
let failed = false;
|
|
15475
|
+
let operationError;
|
|
15423
15476
|
try {
|
|
15477
|
+
this.assertOpen();
|
|
15424
15478
|
const controller = new AbortController();
|
|
15425
15479
|
const timeout = setTimeout(() => {
|
|
15426
15480
|
controller.abort();
|
|
15427
15481
|
}, 6e5);
|
|
15428
15482
|
timeout.unref();
|
|
15483
|
+
this.download = {
|
|
15484
|
+
controller,
|
|
15485
|
+
timeout
|
|
15486
|
+
};
|
|
15429
15487
|
let bytes;
|
|
15430
15488
|
try {
|
|
15431
15489
|
bytes = await this.fetchArtifact(artifact.downloadUrl, controller.signal);
|
|
15432
15490
|
} finally {
|
|
15433
15491
|
clearTimeout(timeout);
|
|
15492
|
+
this.download = void 0;
|
|
15434
15493
|
}
|
|
15494
|
+
this.assertOpen();
|
|
15495
|
+
controller.signal.throwIfAborted();
|
|
15435
15496
|
if (bytes.byteLength !== artifact.downloadBytes) throw new Error("caddy_download_size_mismatch");
|
|
15436
15497
|
if (createHash("sha256").update(bytes).digest("hex") !== artifact.downloadSha256) throw new Error("caddy_download_hash_mismatch");
|
|
15437
15498
|
await ensureCaddyDirectory(this.stateDirectory, candidate);
|
|
15499
|
+
this.assertOpen();
|
|
15438
15500
|
const executable = join(candidate, artifact.executableName);
|
|
15439
15501
|
await writeFile(executable, bytes, {
|
|
15440
15502
|
flag: "wx",
|
|
@@ -15443,8 +15505,10 @@ var CaddyComponentManager = class {
|
|
|
15443
15505
|
await chmod(executable, 448);
|
|
15444
15506
|
if (bytes.byteLength !== artifact.executableBytes || await digest(executable) !== artifact.executableSha256) throw new Error("caddy_executable_hash_mismatch");
|
|
15445
15507
|
await this.verifyMetadata(executable, artifact);
|
|
15508
|
+
this.assertOpen();
|
|
15446
15509
|
try {
|
|
15447
15510
|
const entry = await lstat(this.componentStorage);
|
|
15511
|
+
this.assertOpen();
|
|
15448
15512
|
if (!entry.isDirectory() || entry.isSymbolicLink()) throw new Error("caddy_path_invalid");
|
|
15449
15513
|
await renameCaddyPath(this.stateDirectory, this.componentStorage, backup);
|
|
15450
15514
|
previous = true;
|
|
@@ -15452,6 +15516,7 @@ var CaddyComponentManager = class {
|
|
|
15452
15516
|
if (error.code !== "ENOENT") throw error;
|
|
15453
15517
|
}
|
|
15454
15518
|
try {
|
|
15519
|
+
this.assertOpen();
|
|
15455
15520
|
await this.promote(candidate, this.componentStorage);
|
|
15456
15521
|
promoted = true;
|
|
15457
15522
|
} catch (error) {
|
|
@@ -15469,21 +15534,29 @@ var CaddyComponentManager = class {
|
|
|
15469
15534
|
this.errorCode = void 0;
|
|
15470
15535
|
} catch (error) {
|
|
15471
15536
|
failed = true;
|
|
15537
|
+
operationError = error;
|
|
15472
15538
|
throw error;
|
|
15473
15539
|
} finally {
|
|
15474
|
-
|
|
15540
|
+
const cleanupErrors = [];
|
|
15475
15541
|
for (const path of [
|
|
15476
15542
|
staging,
|
|
15477
15543
|
candidate,
|
|
15478
15544
|
...previous && promoted ? [backup] : []
|
|
15479
|
-
])
|
|
15480
|
-
|
|
15481
|
-
|
|
15482
|
-
|
|
15545
|
+
]) {
|
|
15546
|
+
this.cleanupPaths.add(path);
|
|
15547
|
+
try {
|
|
15548
|
+
await removeCaddyTree(this.stateDirectory, path);
|
|
15549
|
+
this.cleanupPaths.delete(path);
|
|
15550
|
+
} catch (error) {
|
|
15551
|
+
cleanupErrors.push(error);
|
|
15552
|
+
}
|
|
15553
|
+
}
|
|
15554
|
+
if (cleanupErrors.length > 0) {
|
|
15555
|
+
if (!failed && cleanupErrors.length === 1) throw cleanupErrors[0];
|
|
15556
|
+
throw new AggregateError([...failed ? [operationError] : [], ...cleanupErrors], "caddy_component_cleanup_failed", failed ? { cause: operationError } : void 0);
|
|
15483
15557
|
}
|
|
15484
|
-
if (!failed && cleanupError !== void 0) throw cleanupError;
|
|
15485
15558
|
}
|
|
15486
|
-
});
|
|
15559
|
+
}).then(() => this.status());
|
|
15487
15560
|
}
|
|
15488
15561
|
/** Remove optional component files; callers stop the controller and purge runtime configuration separately. */
|
|
15489
15562
|
purge() {
|
|
@@ -15492,18 +15565,57 @@ var CaddyComponentManager = class {
|
|
|
15492
15565
|
await removeCaddyTree(this.stateDirectory, this.stagingRoot);
|
|
15493
15566
|
this.installed = false;
|
|
15494
15567
|
this.errorCode = this.artifact === void 0 ? "caddy_component_unavailable" : void 0;
|
|
15568
|
+
}).then(() => this.status());
|
|
15569
|
+
}
|
|
15570
|
+
/**
|
|
15571
|
+
* Permanently stop admission and abort downloads, then await admitted work and cleanup.
|
|
15572
|
+
* An already started promotion/purge settles normally; cancellation does not undo committed bytes.
|
|
15573
|
+
* A downloader that ignores abort remains owned until its promise settles. Failed temporary cleanup
|
|
15574
|
+
* is retried here; a failed close can be called again without reopening admission or deleting recovery backups.
|
|
15575
|
+
*/
|
|
15576
|
+
close() {
|
|
15577
|
+
if (this.closing !== void 0) return this.closing;
|
|
15578
|
+
this.closed = true;
|
|
15579
|
+
if (this.download !== void 0) {
|
|
15580
|
+
clearTimeout(this.download.timeout);
|
|
15581
|
+
this.download.controller.abort(/* @__PURE__ */ new Error("caddy_component_closed"));
|
|
15582
|
+
}
|
|
15583
|
+
const task = this.queue.then(async () => {
|
|
15584
|
+
const errors = [];
|
|
15585
|
+
for (const path of this.cleanupPaths) try {
|
|
15586
|
+
await removeCaddyTree(this.stateDirectory, path);
|
|
15587
|
+
this.cleanupPaths.delete(path);
|
|
15588
|
+
} catch (error) {
|
|
15589
|
+
errors.push(error);
|
|
15590
|
+
}
|
|
15591
|
+
if (errors.length === 1) throw errors[0];
|
|
15592
|
+
if (errors.length > 1) throw new AggregateError(errors, "caddy_component_cleanup_failed");
|
|
15593
|
+
});
|
|
15594
|
+
this.closing = task;
|
|
15595
|
+
task.catch(() => {
|
|
15596
|
+
if (this.closing === task) this.closing = void 0;
|
|
15495
15597
|
});
|
|
15598
|
+
return task;
|
|
15496
15599
|
}
|
|
15497
15600
|
async verifyMetadata(executable, artifact) {
|
|
15601
|
+
this.assertOpen();
|
|
15498
15602
|
const info = await this.inspectExecutable(executable);
|
|
15603
|
+
this.assertOpen();
|
|
15499
15604
|
if (!info.version.startsWith("v" + artifact.version + " ")) throw new Error("caddy_executable_version_mismatch");
|
|
15500
15605
|
const nonstandard = info.modules.split(/\r?\n/u).filter((line) => line.startsWith("dns.providers."));
|
|
15501
15606
|
if (nonstandard.length !== 1 || nonstandard[0] !== "dns.providers.tencentcloud " + artifact.dnsPluginVersion || !info.modules.includes("Non-standard modules: 1")) throw new Error("caddy_executable_modules_mismatch");
|
|
15502
15607
|
}
|
|
15608
|
+
assertOpen() {
|
|
15609
|
+
if (this.closed) throw new Error("caddy_component_closed");
|
|
15610
|
+
}
|
|
15503
15611
|
enqueue(operation) {
|
|
15504
|
-
|
|
15612
|
+
if (this.closed) return Promise.reject(/* @__PURE__ */ new Error("caddy_component_closed"));
|
|
15613
|
+
const task = this.queue.then(() => {
|
|
15614
|
+
this.assertOpen();
|
|
15615
|
+
return operation();
|
|
15616
|
+
});
|
|
15505
15617
|
this.queue = task.then(() => void 0, () => void 0);
|
|
15506
|
-
return task
|
|
15618
|
+
return task;
|
|
15507
15619
|
}
|
|
15508
15620
|
};
|
|
15509
15621
|
const MAX_CONFIG_BYTES = 16384;
|
|
@@ -15862,6 +15974,7 @@ var CaddyController = class {
|
|
|
15862
15974
|
} catch {}
|
|
15863
15975
|
}
|
|
15864
15976
|
async start() {
|
|
15977
|
+
if (this.child !== void 0 || this.gatewayValue !== void 0) await this.stop();
|
|
15865
15978
|
const generation = ++this.generation;
|
|
15866
15979
|
const startup = new AbortController();
|
|
15867
15980
|
this.startupAbort = startup;
|
|
@@ -15911,12 +16024,19 @@ var CaddyController = class {
|
|
|
15911
16024
|
"--adapter",
|
|
15912
16025
|
"caddyfile"
|
|
15913
16026
|
], environment);
|
|
15914
|
-
|
|
16027
|
+
const ownedChild = {
|
|
16028
|
+
process: child,
|
|
16029
|
+
closed: false
|
|
16030
|
+
};
|
|
16031
|
+
this.child = ownedChild;
|
|
16032
|
+
child.once("close", () => {
|
|
16033
|
+
ownedChild.closed = true;
|
|
16034
|
+
});
|
|
15915
16035
|
child.stdout.resume();
|
|
15916
16036
|
child.stderr.resume();
|
|
15917
16037
|
child.stdin.end();
|
|
15918
16038
|
const failed = (code) => {
|
|
15919
|
-
if (generation !== this.generation || this.child !==
|
|
16039
|
+
if (generation !== this.generation || this.child !== ownedChild) return;
|
|
15920
16040
|
childFailure = code;
|
|
15921
16041
|
startup.abort();
|
|
15922
16042
|
if (this.latest.state === "ready") this.enqueue(async () => {
|
|
@@ -15991,20 +16111,49 @@ var CaddyController = class {
|
|
|
15991
16111
|
this.startupAbort?.abort();
|
|
15992
16112
|
await this.stopResources();
|
|
15993
16113
|
}
|
|
16114
|
+
waitForChildClose(child) {
|
|
16115
|
+
if (child.closed) return Promise.resolve();
|
|
16116
|
+
return new Promise((resolve, reject) => {
|
|
16117
|
+
const finish = (error) => {
|
|
16118
|
+
clearTimeout(timer);
|
|
16119
|
+
child.process.removeListener("close", closed);
|
|
16120
|
+
if (error === void 0) resolve();
|
|
16121
|
+
else reject(error);
|
|
16122
|
+
};
|
|
16123
|
+
const closed = () => {
|
|
16124
|
+
finish();
|
|
16125
|
+
};
|
|
16126
|
+
const timer = setTimeout(() => {
|
|
16127
|
+
finish(/* @__PURE__ */ new Error("caddy_process_close_timeout"));
|
|
16128
|
+
}, 1500);
|
|
16129
|
+
timer.unref();
|
|
16130
|
+
child.process.once("close", closed);
|
|
16131
|
+
});
|
|
16132
|
+
}
|
|
15994
16133
|
async stopResources() {
|
|
15995
16134
|
const child = this.child;
|
|
15996
16135
|
const gateway = this.gatewayValue;
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
|
|
16004
|
-
|
|
16005
|
-
if (
|
|
16006
|
-
|
|
16007
|
-
|
|
16136
|
+
try {
|
|
16137
|
+
await settleRemoteResources([async () => {
|
|
16138
|
+
if (child !== void 0) {
|
|
16139
|
+
await (this.options.terminateProcess ?? terminateRemoteProcess)(child.process);
|
|
16140
|
+
await this.waitForChildClose(child);
|
|
16141
|
+
if (this.child === child) this.child = void 0;
|
|
16142
|
+
}
|
|
16143
|
+
}, async () => {
|
|
16144
|
+
if (gateway !== void 0) {
|
|
16145
|
+
await gateway.close();
|
|
16146
|
+
if (this.gatewayValue === gateway) this.gatewayValue = void 0;
|
|
16147
|
+
}
|
|
16148
|
+
}], "caddy cleanup failed");
|
|
16149
|
+
} catch (error) {
|
|
16150
|
+
this.publish({
|
|
16151
|
+
enabled: this.enabled,
|
|
16152
|
+
state: "error",
|
|
16153
|
+
errorCode: "caddy_cleanup_failed"
|
|
16154
|
+
});
|
|
16155
|
+
throw error;
|
|
16156
|
+
}
|
|
16008
16157
|
}
|
|
16009
16158
|
};
|
|
16010
16159
|
//#endregion
|
|
@@ -18020,6 +18169,11 @@ async function apply(ctx, config) {
|
|
|
18020
18169
|
adminClosing = true;
|
|
18021
18170
|
unregister();
|
|
18022
18171
|
};
|
|
18172
|
+
const drainRemoteWork = async () => {
|
|
18173
|
+
const draining = remoteProviders.close();
|
|
18174
|
+
caddyController.cancelPendingStart();
|
|
18175
|
+
await settleCleanupSteps([() => caddyComponent.close(), () => draining]);
|
|
18176
|
+
};
|
|
18023
18177
|
const disposeMobileCommand = ctx.commands.register({
|
|
18024
18178
|
name: "mobile",
|
|
18025
18179
|
description: "定制手机界面或添加电脑能力",
|
|
@@ -18086,6 +18240,7 @@ async function apply(ctx, config) {
|
|
|
18086
18240
|
try {
|
|
18087
18241
|
await settleCleanupSteps([
|
|
18088
18242
|
stopAdmin,
|
|
18243
|
+
drainRemoteWork,
|
|
18089
18244
|
() => trustedNetworksWrite,
|
|
18090
18245
|
disposeMobileCommand,
|
|
18091
18246
|
disposeTaskEvents,
|
|
@@ -18105,6 +18260,7 @@ async function apply(ctx, config) {
|
|
|
18105
18260
|
return async () => {
|
|
18106
18261
|
await settleCleanupSteps([
|
|
18107
18262
|
stopAdmin,
|
|
18263
|
+
drainRemoteWork,
|
|
18108
18264
|
() => trustedNetworksWrite,
|
|
18109
18265
|
disposeMobileCommand,
|
|
18110
18266
|
disposeTaskEvents,
|