smart-home-engine 3.0.0-beta.1 → 3.0.0-beta.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/dist/web/assets/{index-DJs_h--E.js → index-DbYEAVZF.js} +97 -97
- package/dist/web/assets/{index-Bwi3GpP7.css → index-eopsqoPx.css} +1 -1
- package/dist/web/assets/{tsMode-qUI0UNxn.js → tsMode-BhjG23dq.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/service/install.sh +3 -0
- package/service/she-servicectl +22 -1
- package/src/index.js +1 -0
- package/src/lib/self-update.js +136 -0
- package/src/lib/services-host.js +1 -1
- package/src/lib/update-channel.js +16 -1
- package/src/web/server.js +52 -12
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{m as O}from"./monaco-langs-DKJI_o9J.js";import{t as I}from"./index-
|
|
1
|
+
import{m as O}from"./monaco-langs-DKJI_o9J.js";import{t as I}from"./index-DbYEAVZF.js";/*!-----------------------------------------------------------------------------
|
|
2
2
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
3
|
* Version: 0.52.2(404545bded1df6ffa41ea0af4e8ddb219018c6c1)
|
|
4
4
|
* Released under the MIT license
|
package/dist/web/index.html
CHANGED
|
@@ -175,10 +175,10 @@
|
|
|
175
175
|
}
|
|
176
176
|
})();
|
|
177
177
|
</script>
|
|
178
|
-
<script type="module" crossorigin src="/assets/index-
|
|
178
|
+
<script type="module" crossorigin src="/assets/index-DbYEAVZF.js"></script>
|
|
179
179
|
<link rel="modulepreload" crossorigin href="/assets/monaco-langs-DKJI_o9J.js">
|
|
180
180
|
<link rel="stylesheet" crossorigin href="/assets/monaco-langs-DyX1CsEw.css">
|
|
181
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
181
|
+
<link rel="stylesheet" crossorigin href="/assets/index-eopsqoPx.css">
|
|
182
182
|
</head>
|
|
183
183
|
<body>
|
|
184
184
|
<div id="app"></div>
|
package/package.json
CHANGED
package/service/install.sh
CHANGED
|
@@ -45,6 +45,9 @@ install -m 755 -o root -g root "$HELPER_SRC" "$HELPER_DST"
|
|
|
45
45
|
echo "installed $HELPER_DST"
|
|
46
46
|
|
|
47
47
|
# --- sudoers rules -------------------------------------------------------
|
|
48
|
+
# she's own update runs through the helper (she-servicectl she-update <version>). The npm line is
|
|
49
|
+
# the fallback for a daemon that still updates with the literal command (she up to 3.0.0-beta.1);
|
|
50
|
+
# it goes away in a later release.
|
|
48
51
|
NPM_BIN="$(command -v npm)"
|
|
49
52
|
SUDOERS_FILE=/etc/sudoers.d/she
|
|
50
53
|
cat > "$SUDOERS_FILE" <<EOF
|
package/service/she-servicectl
CHANGED
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
# she-servicectl node update [--lts|--latest|--stable|--version X.Y.Z] install/refresh tj/n (downloaded, no npm), then n install <label|version> — JSON with the version before and after
|
|
35
35
|
# she-servicectl restart-all restart every running instance on this host (after a node update, say)
|
|
36
36
|
# she-servicectl self-update replace this script with the one on stdin (she ships it)
|
|
37
|
+
# she-servicectl she-update <version> she's own update: npm install -g smart-home-engine@<version> (the she host only)
|
|
37
38
|
# she-servicectl remove-key drop the public key on stdin from the calling user's authorized_keys
|
|
38
39
|
# she-servicectl teardown [--force] remove she from this host: that key, the sudoers rule, this script,
|
|
39
40
|
# the she-services user (adapters and their instances stay untouched)
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
|
|
46
47
|
set -eu
|
|
47
48
|
|
|
48
|
-
VERSION=
|
|
49
|
+
VERSION=16
|
|
49
50
|
BROKER_ENV=/etc/mqtt-interfaces/broker.env
|
|
50
51
|
UNIT_DIR=/etc/systemd/system
|
|
51
52
|
|
|
@@ -62,6 +63,9 @@ die() { printf 'she-servicectl: %s\n' "$*" >&2; exit 2; }
|
|
|
62
63
|
|
|
63
64
|
valid_adapter() { printf '%s' "$1" | grep -Eq '^[a-z0-9][a-z0-9._-]{0,213}$'; }
|
|
64
65
|
valid_instance() { printf '%s' "$1" | grep -Eq '^[A-Za-z0-9_.-]{1,64}$'; }
|
|
66
|
+
# a release version as npm publishes it (pre-release suffix allowed): nothing npm could read as a
|
|
67
|
+
# range, a dist-tag, a URL or a second package
|
|
68
|
+
valid_she_version() { printf '%s' "$1" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$'; }
|
|
65
69
|
|
|
66
70
|
# a template unit written by mqtt-interfaces-core's installer: per-instance env file under /etc/<adapter>/
|
|
67
71
|
installed_adapter() {
|
|
@@ -632,6 +636,22 @@ cmd_self_update() {
|
|
|
632
636
|
printf 'she-servicectl updated %s -> %s at %s\n' "$VERSION" "$newver" "$self"
|
|
633
637
|
}
|
|
634
638
|
|
|
639
|
+
# ── she's own update ────────────────────────────────────────────────────────────
|
|
640
|
+
# The update button of the she daemon (v16). she's update channels install an exact version, and
|
|
641
|
+
# the sudoers line `she --install` used to write for that — `npm install -g smart-home-engine`,
|
|
642
|
+
# matched literally by sudo — cannot take one; this command can, through the rule the helper
|
|
643
|
+
# already has. The version is checked strictly, npm's exit code is the command's, and the npm is
|
|
644
|
+
# the one next to the node that runs she (as for the adapters). Meant for the she host: the daemon
|
|
645
|
+
# calls it locally only, and the command refuses where no she is installed.
|
|
646
|
+
cmd_she_update() {
|
|
647
|
+
[ $# -eq 1 ] || die "usage: she-update <version>"
|
|
648
|
+
valid_she_version "$1" || die "invalid version: $1"
|
|
649
|
+
adapter_cmd she >/dev/null 2>&1 || die "she is not installed on this host"
|
|
650
|
+
npm=$(adapter_npm she)
|
|
651
|
+
node=$(adapter_node she)
|
|
652
|
+
PATH="$(dirname "$node"):$PATH" exec "$npm" install -g "smart-home-engine@$1" --no-audit --no-fund
|
|
653
|
+
}
|
|
654
|
+
|
|
635
655
|
# ── removing she from this host ─────────────────────────────────────────────────
|
|
636
656
|
# The account she logs in as is the sudo caller (root when she connects as root).
|
|
637
657
|
caller_user() { printf '%s' "${SUDO_USER:-$(id -un)}"; }
|
|
@@ -869,6 +889,7 @@ case "$c" in
|
|
|
869
889
|
file) cmd_file "$@" ;;
|
|
870
890
|
asset) cmd_asset "$@" ;;
|
|
871
891
|
self-update) cmd_self_update "$@" ;;
|
|
892
|
+
she-update) cmd_she_update "$@" ;;
|
|
872
893
|
migrate) cmd_migrate "$@" ;;
|
|
873
894
|
remove-key) cmd_remove_key "$@" ;;
|
|
874
895
|
teardown) cmd_teardown "$@" ;;
|
package/src/index.js
CHANGED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
/**
|
|
3
|
+
* she's own update: how the version the update check offers gets installed, and when the daemon
|
|
4
|
+
* may restart afterwards.
|
|
5
|
+
*
|
|
6
|
+
* The daemon runs as the `she` user without a general sudo. Since 3.0.0-beta.2 the install goes
|
|
7
|
+
* through the privileged helper — `she-servicectl she-update <version>` (helper v16) — which checks
|
|
8
|
+
* the version strictly and runs `npm install -g smart-home-engine@<version>` as root through the one
|
|
9
|
+
* sudoers rule every installation has. Before that, `she --install` wrote a second rule allowing
|
|
10
|
+
* exactly `npm install -g smart-home-engine`: sudo matches arguments literally, so the exact-version
|
|
11
|
+
* install the update channels need (3.0.0-beta.0) was refused — and the daemon restarted on the old
|
|
12
|
+
* version regardless, which made the failure invisible. That literal command installs npm's `latest`
|
|
13
|
+
* and is kept as the fallback for a host whose helper is still older than v16, but only when the
|
|
14
|
+
* offered version *is* `latest`; otherwise the update asks for the helper update first.
|
|
15
|
+
*
|
|
16
|
+
* The restart happens only after npm exited 0. A failure keeps the daemon running and reports npm's
|
|
17
|
+
* exit code and the last lines of its output.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
const VERSION_RX = /^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$/;
|
|
21
|
+
/** the first helper version with the `she-update` command */
|
|
22
|
+
const HELPER_SHE_UPDATE_VERSION = 16;
|
|
23
|
+
const PACKAGE = 'smart-home-engine';
|
|
24
|
+
const HELPER = '/usr/local/bin/she-servicectl';
|
|
25
|
+
const HELPER_NEEDED = 'update needs the current she-servicectl helper — Update helper on the Services → Hosts tab, or run `sudo she --install` once';
|
|
26
|
+
/** output lines kept for the log and the error message */
|
|
27
|
+
const TAIL_LINES = 12;
|
|
28
|
+
const TAIL_LINES_IN_ERROR = 3;
|
|
29
|
+
|
|
30
|
+
/** A release version as npm publishes it: `3.0.0`, `3.0.0-beta.2` — no ranges, tags, URLs or spaces. */
|
|
31
|
+
function isValidVersion(v) {
|
|
32
|
+
return typeof v === 'string' && VERSION_RX.test(v);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** The helper version a driver reports, or null when the helper is missing, denied or unreadable. */
|
|
36
|
+
async function helperVersionOf(driver) {
|
|
37
|
+
try {
|
|
38
|
+
const { stdout } = await driver.exec(['version'], { timeout: 20000 });
|
|
39
|
+
const n = Number(String(stdout).trim());
|
|
40
|
+
return Number.isInteger(n) && n > 0 ? n : null;
|
|
41
|
+
} catch {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* How to install `version`: through the helper when it has `she-update`, through the old literal
|
|
48
|
+
* sudo rule when the version is npm's `latest`, otherwise not at all.
|
|
49
|
+
* @param {{version: string, helperVersion: number|null, npmLatest?: string|null}} ctx
|
|
50
|
+
* @returns {{mode: 'helper'|'npm-latest'}|{error: string}}
|
|
51
|
+
*/
|
|
52
|
+
function planUpdate({ version, helperVersion, npmLatest }) {
|
|
53
|
+
if (!isValidVersion(version)) return { error: `not a release version: ${version}` };
|
|
54
|
+
if (Number.isInteger(helperVersion) && helperVersion >= HELPER_SHE_UPDATE_VERSION) return { mode: 'helper' };
|
|
55
|
+
if (npmLatest && npmLatest === version) return { mode: 'npm-latest' };
|
|
56
|
+
return { error: HELPER_NEEDED };
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/** The command a plan runs: `[cmd, argv]`. */
|
|
60
|
+
function commandFor(plan, version, { helper = HELPER } = {}) {
|
|
61
|
+
if (plan.mode === 'helper') return ['sudo', ['-n', helper, 'she-update', version]];
|
|
62
|
+
if (plan.mode === 'npm-latest') return ['sudo', ['npm', 'install', '-g', PACKAGE]];
|
|
63
|
+
throw new Error('no command for this plan');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Run the install and wait for it. Never rejects.
|
|
68
|
+
* @param {[string, string[]]} command
|
|
69
|
+
* @param {{spawn: Function, onLine?: (line: string) => void}} opts spawn: child_process.spawn or a stub
|
|
70
|
+
* @returns {Promise<{ok: boolean, code: number|null, signal: string|null, tail: string[], reason: string}>}
|
|
71
|
+
*/
|
|
72
|
+
function runInstall([cmd, argv], { spawn, onLine } = {}) {
|
|
73
|
+
return new Promise((resolve) => {
|
|
74
|
+
const tail = [];
|
|
75
|
+
let partial = '';
|
|
76
|
+
const take = (chunk) => {
|
|
77
|
+
partial += String(chunk);
|
|
78
|
+
const lines = partial.split(/\r?\n/);
|
|
79
|
+
partial = lines.pop();
|
|
80
|
+
for (const raw of lines) {
|
|
81
|
+
const line = raw.replace(/\r/g, '').trimEnd();
|
|
82
|
+
if (!line.trim()) continue;
|
|
83
|
+
tail.push(line);
|
|
84
|
+
if (tail.length > TAIL_LINES) tail.shift();
|
|
85
|
+
if (onLine) onLine(line);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
const finish = (ok, code, signal, reason) => {
|
|
89
|
+
if (partial.trim()) take('\n');
|
|
90
|
+
resolve({ ok, code, signal, tail: tail.slice(), reason });
|
|
91
|
+
};
|
|
92
|
+
let child;
|
|
93
|
+
try {
|
|
94
|
+
child = spawn(cmd, argv, { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
95
|
+
} catch (err) {
|
|
96
|
+
finish(false, null, null, `could not start ${cmd}: ${err.message}`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (child.stdout) child.stdout.on('data', take);
|
|
100
|
+
if (child.stderr) child.stderr.on('data', take);
|
|
101
|
+
let done = false;
|
|
102
|
+
child.on('error', (err) => {
|
|
103
|
+
if (done) return;
|
|
104
|
+
done = true;
|
|
105
|
+
finish(false, null, null, `could not start ${cmd}: ${err.message}`);
|
|
106
|
+
});
|
|
107
|
+
child.on('close', (code, signal) => {
|
|
108
|
+
if (done) return;
|
|
109
|
+
done = true;
|
|
110
|
+
if (code === 0) finish(true, 0, null, 'ok');
|
|
111
|
+
else finish(false, code, signal, signal ? `npm was killed by ${signal}` : `npm exited ${code}`);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Install `version` as planned and restart only when npm succeeded.
|
|
118
|
+
* @param {{plan: {mode: string}, version: string, spawn: Function, onRestart: Function, log?: (level: string, msg: string) => void, helper?: string}} opts
|
|
119
|
+
* @returns {Promise<{ok: true}|{ok: false, error: string}>} `error` is what the UI shows
|
|
120
|
+
*/
|
|
121
|
+
async function performUpdate({ plan, version, spawn, onRestart, log = () => {}, helper }) {
|
|
122
|
+
const command = commandFor(plan, version, { helper });
|
|
123
|
+
log('info', `update: installing ${PACKAGE}@${version} ${plan.mode === 'helper' ? 'through she-servicectl' : "through the literal sudo rule (npm's latest)"}`);
|
|
124
|
+
const r = await runInstall(command, { spawn, onLine: (line) => log('info', `update: ${line}`) });
|
|
125
|
+
if (r.ok) {
|
|
126
|
+
log('info', `update: ${version} installed, restarting`);
|
|
127
|
+
onRestart();
|
|
128
|
+
return { ok: true };
|
|
129
|
+
}
|
|
130
|
+
const tail = r.tail.slice(-TAIL_LINES_IN_ERROR).join(' | ');
|
|
131
|
+
const error = `update to ${version} failed: ${r.reason}${tail ? ' — ' + tail : ''}`;
|
|
132
|
+
log('error', `${error}${r.tail.length ? '\n' + r.tail.join('\n') : ''}`);
|
|
133
|
+
return { ok: false, error };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
module.exports = { HELPER_SHE_UPDATE_VERSION, HELPER_NEEDED, PACKAGE, VERSION_RX, isValidVersion, helperVersionOf, planUpdate, commandFor, runInstall, performUpdate };
|
package/src/lib/services-host.js
CHANGED
|
@@ -26,7 +26,7 @@ const { execFile, spawn } = require('child_process');
|
|
|
26
26
|
const sshDeploy = require('./ssh-deploy');
|
|
27
27
|
|
|
28
28
|
const HELPER = '/usr/local/bin/she-servicectl';
|
|
29
|
-
const HELPER_VERSION =
|
|
29
|
+
const HELPER_VERSION = 16; // must match VERSION in service/she-servicectl (test/unit/helper-version.test.js)
|
|
30
30
|
/** Default identity for services.hosts[].ssh — one key for all managed hosts (I5). */
|
|
31
31
|
const DEFAULT_SERVICES_IDENTITY = '~/.she/ssh/services_id_ed25519';
|
|
32
32
|
/** The helper as shipped with this she version (copied to remote hosts by the deploy route). */
|
|
@@ -97,6 +97,21 @@ async function existsOnNpm(version) {
|
|
|
97
97
|
return data && data.version === version;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* npm's `latest` dist-tag of the package, or null when the registry does not answer. Only the
|
|
102
|
+
* self-update's fallback asks (the literal `npm install -g smart-home-engine` installs exactly this).
|
|
103
|
+
*/
|
|
104
|
+
async function npmLatest() {
|
|
105
|
+
try {
|
|
106
|
+
const res = await _fetch(`${NPM_REGISTRY}/${PACKAGE}/latest`, { signal: AbortSignal.timeout(10000) });
|
|
107
|
+
if (!res.ok) return null;
|
|
108
|
+
const data = await res.json();
|
|
109
|
+
return data && VERSION_RX.test(String(data.version)) ? data.version : null;
|
|
110
|
+
} catch {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
100
115
|
/**
|
|
101
116
|
* Check for an update on a channel.
|
|
102
117
|
* @param {object} opts
|
|
@@ -149,4 +164,4 @@ async function checkUpdate(opts) {
|
|
|
149
164
|
return result;
|
|
150
165
|
}
|
|
151
166
|
|
|
152
|
-
module.exports = { CHANNELS, PACKAGE, checkUpdate, newestOf, offeredVersion, versionOfTag, isPrerelease, normalizeChannel, setFetch };
|
|
167
|
+
module.exports = { CHANNELS, PACKAGE, checkUpdate, npmLatest, newestOf, offeredVersion, versionOfTag, isPrerelease, normalizeChannel, setFetch };
|
package/src/web/server.js
CHANGED
|
@@ -6,6 +6,8 @@ const { spawn } = require('child_process');
|
|
|
6
6
|
const pkg = require('../../package.json');
|
|
7
7
|
const { router: configRouter, DEFAULT_CONFIG_PATH } = require('./config-api');
|
|
8
8
|
const updateChannel = require('../lib/update-channel');
|
|
9
|
+
const selfUpdate = require('../lib/self-update');
|
|
10
|
+
const servicesHost = require('../lib/services-host');
|
|
9
11
|
const { router: scriptsRouter } = require('./scripts-api');
|
|
10
12
|
const { router: shedbRouter } = require('./shedb-api');
|
|
11
13
|
const { router: matterRouter } = require('./matter-api');
|
|
@@ -127,7 +129,9 @@ function _updateFields() {
|
|
|
127
129
|
}
|
|
128
130
|
if (_update && _update.stable) f.latestStable = _update.stable;
|
|
129
131
|
if (_update && _update.prerelease) f.latestBeta = _update.prerelease;
|
|
130
|
-
if (
|
|
132
|
+
if (_updateFailed) f.updateError = _updateFailed;
|
|
133
|
+
else if (_update && _update.error) f.updateError = _update.error;
|
|
134
|
+
if (_updating) f.updating = true;
|
|
131
135
|
return f;
|
|
132
136
|
}
|
|
133
137
|
|
|
@@ -137,21 +141,51 @@ app.post('/she/check-update', async (req, res) => {
|
|
|
137
141
|
res.json({ latestVersion: r.latest, ..._updateFields() });
|
|
138
142
|
});
|
|
139
143
|
|
|
140
|
-
// Update — install the offered version exactly, then restart
|
|
141
|
-
//
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
+
// Update — install the offered version exactly, then restart — but only after npm succeeded.
|
|
145
|
+
// The install runs through the helper (`she-servicectl she-update <version>`, v16) when the host
|
|
146
|
+
// has it; a host with an older helper falls back to the literal `sudo npm install -g
|
|
147
|
+
// smart-home-engine` of the old sudoers rule when the offered version is npm's `latest`, and is
|
|
148
|
+
// asked to update the helper otherwise. Without a known version there is nothing to install.
|
|
149
|
+
let _updating = false; // an install is running
|
|
150
|
+
let _updateFailed = null; // the last failed install's message, until the next attempt
|
|
151
|
+
|
|
152
|
+
function _log(level, msg) {
|
|
153
|
+
if (_logger) _logger[level](msg);
|
|
154
|
+
else (level === 'error' || level === 'warn' ? console.error : console.log)(msg);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
async function _planUpdate(version) {
|
|
158
|
+
const helperVersion = await selfUpdate.helperVersionOf(servicesHost.createLocalDriver());
|
|
159
|
+
// npm's `latest` matters only for the fallback, so it is fetched only when the helper is too old
|
|
160
|
+
const helperOk = Number.isInteger(helperVersion) && helperVersion >= selfUpdate.HELPER_SHE_UPDATE_VERSION;
|
|
161
|
+
return selfUpdate.planUpdate({ version, helperVersion, npmLatest: helperOk ? null : await updateChannel.npmLatest() });
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
app.post('/she/update', async (req, res) => {
|
|
144
165
|
const version = _update && _update.latest;
|
|
145
166
|
if (!version || _isDocker) {
|
|
146
167
|
res.status(409).json({ ok: false, error: _isDocker ? 'a Docker container is updated by pulling a new image' : 'no update known — check for updates first' });
|
|
147
168
|
return;
|
|
148
169
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
170
|
+
if (_updating) {
|
|
171
|
+
res.status(409).json({ ok: false, error: 'an update is already running' });
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const plan = await _planUpdate(version);
|
|
175
|
+
if (plan.error) {
|
|
176
|
+
_updateFailed = plan.error;
|
|
177
|
+
_log('warn', `update to ${version} not possible: ${plan.error}`);
|
|
178
|
+
res.status(409).json({ ok: false, error: plan.error });
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
_updating = true;
|
|
182
|
+
_updateFailed = null;
|
|
183
|
+
res.json({ ok: true, version, via: plan.mode });
|
|
184
|
+
// async spawn, so the HTTP server (and the UI's polling) stays responsive while npm runs
|
|
185
|
+
setTimeout(async () => {
|
|
186
|
+
const r = await selfUpdate.performUpdate({ plan, version, spawn, onRestart: _systemdRestart, log: _log });
|
|
187
|
+
_updating = false;
|
|
188
|
+
if (!r.ok) _updateFailed = r.error;
|
|
155
189
|
}, 200);
|
|
156
190
|
});
|
|
157
191
|
|
|
@@ -356,4 +390,10 @@ function stopServer() {
|
|
|
356
390
|
});
|
|
357
391
|
}
|
|
358
392
|
|
|
359
|
-
|
|
393
|
+
let _logger = null;
|
|
394
|
+
/** The daemon's logger; without one the update path writes to the console. */
|
|
395
|
+
function setLogger(log) {
|
|
396
|
+
_logger = log;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
module.exports = { app, registerRoute, unregisterRoutesByScript, setStatsProvider, setHealthProvider, setLogger, startServer, stopServer };
|