smart-home-engine 1.35.1 → 1.36.0
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-ji2CpixA.css → index-hiXQxo8M.css} +1 -1
- package/dist/web/assets/{index-DxSKkp8l.js → index-y0wyYG2_.js} +89 -89
- package/dist/web/assets/{tsMode-CLFEQmTc.js → tsMode-DIQ3Qnwp.js} +1 -1
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/service/she-servicectl +11 -5
- package/src/lib/services-host.js +1 -1
- package/src/lib/services-inventory.js +22 -0
- package/src/web/services-api.js +14 -1
|
@@ -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-y0wyYG2_.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
|
@@ -172,10 +172,10 @@
|
|
|
172
172
|
}
|
|
173
173
|
})();
|
|
174
174
|
</script>
|
|
175
|
-
<script type="module" crossorigin src="/assets/index-
|
|
175
|
+
<script type="module" crossorigin src="/assets/index-y0wyYG2_.js"></script>
|
|
176
176
|
<link rel="modulepreload" crossorigin href="/assets/monaco-langs-DKJI_o9J.js">
|
|
177
177
|
<link rel="stylesheet" crossorigin href="/assets/monaco-langs-DyX1CsEw.css">
|
|
178
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
178
|
+
<link rel="stylesheet" crossorigin href="/assets/index-hiXQxo8M.css">
|
|
179
179
|
</head>
|
|
180
180
|
<body>
|
|
181
181
|
<div id="app"></div>
|
package/package.json
CHANGED
package/service/she-servicectl
CHANGED
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
# a wrapper or symlink /usr/local/bin/<adapter>.
|
|
17
17
|
#
|
|
18
18
|
# she-servicectl version
|
|
19
|
-
# she-servicectl list (adapters = template units + npm packages with mqttInterfaces
|
|
19
|
+
# she-servicectl list (adapters = template units + npm packages with mqttInterfaces; instances carry
|
|
20
|
+
# systemd's MemoryCurrent / CPUUsageNSec for the dashboard)
|
|
20
21
|
# she-servicectl unit <adapter> <instance> start|stop|restart|enable|disable|status
|
|
21
22
|
# she-servicectl logs <adapter> <instance> [-n N] [--follow]
|
|
22
23
|
# she-servicectl env <adapter> <instance> read|write (write: file on stdin)
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
|
|
41
42
|
set -eu
|
|
42
43
|
|
|
43
|
-
VERSION=
|
|
44
|
+
VERSION=10
|
|
44
45
|
BROKER_ENV=/etc/mqtt-interfaces/broker.env
|
|
45
46
|
UNIT_DIR=/etc/systemd/system
|
|
46
47
|
|
|
@@ -314,15 +315,20 @@ cmd_list() {
|
|
|
314
315
|
valid_instance "$i" || continue
|
|
315
316
|
[ $first -eq 1 ] || printf ','
|
|
316
317
|
first=0
|
|
317
|
-
show=$(systemctl show -p ActiveState -p SubState -p UnitFileState -p ExecMainStartTimestamp -p NRestarts "$a@$i.service" 2>/dev/null || true)
|
|
318
|
+
show=$(systemctl show -p ActiveState -p SubState -p UnitFileState -p ExecMainStartTimestamp -p NRestarts -p MainPID -p MemoryCurrent -p CPUUsageNSec "$a@$i.service" 2>/dev/null || true)
|
|
318
319
|
active=$(printf '%s\n' "$show" | sed -n 's/^ActiveState=//p')
|
|
320
|
+
pid=$(printf '%s\n' "$show" | sed -n 's/^MainPID=//p')
|
|
321
|
+
mem=$(printf '%s\n' "$show" | sed -n 's/^MemoryCurrent=//p')
|
|
322
|
+
cpuns=$(printf '%s\n' "$show" | sed -n 's/^CPUUsageNSec=//p')
|
|
323
|
+
case "$mem" in *[!0-9]*|'') mem=null ;; esac
|
|
324
|
+
case "$cpuns" in *[!0-9]*|'') cpuns=null ;; esac
|
|
319
325
|
sub=$(printf '%s\n' "$show" | sed -n 's/^SubState=//p')
|
|
320
326
|
uf=$(printf '%s\n' "$show" | sed -n 's/^UnitFileState=//p')
|
|
321
327
|
since=$(printf '%s\n' "$show" | sed -n 's/^ExecMainStartTimestamp=//p')
|
|
322
328
|
nr=$(printf '%s\n' "$show" | sed -n 's/^NRestarts=//p')
|
|
323
|
-
printf '{"adapter":"%s","instance":"%s","active":"%s","sub":"%s","unitFile":"%s","since":"%s","restarts":%s}' \
|
|
329
|
+
printf '{"adapter":"%s","instance":"%s","active":"%s","sub":"%s","unitFile":"%s","since":"%s","restarts":%s,"pid":%s,"memory":%s,"cpuNs":%s}' \
|
|
324
330
|
"$a" "$i" "$(json_escape "$active")" "$(json_escape "$sub")" "$(json_escape "$uf")" \
|
|
325
|
-
"$(json_escape "$since")" "${nr:-0}"
|
|
331
|
+
"$(json_escape "$since")" "${nr:-0}" "${pid:-0}" "$mem" "$cpuns"
|
|
326
332
|
done
|
|
327
333
|
done
|
|
328
334
|
printf ']}\n'
|
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 = 10; // must match VERSION in service/she-servicectl
|
|
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). */
|
|
@@ -69,6 +69,21 @@ function parseInfo(val) {
|
|
|
69
69
|
return v;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
+
/** `<name>/maintenance/stats` payload (core 0.8+): numbers only, anything else → null. */
|
|
73
|
+
function parseStats(v) {
|
|
74
|
+
if (typeof v === 'string') {
|
|
75
|
+
try {
|
|
76
|
+
v = JSON.parse(v);
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (!v || typeof v !== 'object' || Array.isArray(v)) return null;
|
|
82
|
+
const out = {};
|
|
83
|
+
for (const k of ['rss', 'heapUsed', 'heapTotal', 'cpu', 'eventLoopLag', 'uptime', 'ts']) if (typeof v[k] === 'number' && Number.isFinite(v[k])) out[k] = v[k];
|
|
84
|
+
return typeof out.rss === 'number' ? out : null;
|
|
85
|
+
}
|
|
86
|
+
|
|
72
87
|
/**
|
|
73
88
|
* Derive the service inventory from the retained MQTT state.
|
|
74
89
|
*
|
|
@@ -80,11 +95,17 @@ function analyzeServices(entries, opts = {}) {
|
|
|
80
95
|
const now = opts.now ?? Date.now();
|
|
81
96
|
const infos = new Map(); // instance → {info, ts}
|
|
82
97
|
const conns = new Map(); // instance → {connected, ts, lc}
|
|
98
|
+
const stats = new Map(); // instance → {stats, ts} (<name>/maintenance/stats, core 0.8+)
|
|
83
99
|
const topics = new Set();
|
|
84
100
|
|
|
85
101
|
for (const [topic, obj] of entries) {
|
|
86
102
|
topics.add(topic);
|
|
87
103
|
const slash = topic.indexOf('/');
|
|
104
|
+
if (slash > 0 && topic.slice(slash) === '/maintenance/stats') {
|
|
105
|
+
const st = parseStats(obj && obj.val);
|
|
106
|
+
if (st) stats.set(topic.slice(0, slash), { stats: st, ts: obj.ts });
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
88
109
|
if (slash <= 0 || topic.indexOf('/', slash + 1) !== -1) continue; // exactly two levels
|
|
89
110
|
const instance = topic.slice(0, slash);
|
|
90
111
|
const leaf = topic.slice(slash + 1);
|
|
@@ -129,6 +150,7 @@ function analyzeServices(entries, opts = {}) {
|
|
|
129
150
|
connectedTs: c ? c.ts : null,
|
|
130
151
|
connectedLc: c ? (c.lc ?? c.ts) : null,
|
|
131
152
|
infoTs: i ? i.ts : null,
|
|
153
|
+
stats: stats.has(instance) && connected !== null && connected > 0 ? { ...stats.get(instance).stats, receivedTs: stats.get(instance).ts } : null,
|
|
132
154
|
statusTopics,
|
|
133
155
|
info,
|
|
134
156
|
});
|
package/src/web/services-api.js
CHANGED
|
@@ -556,6 +556,19 @@ router.get('/hosts', async (req, res) => {
|
|
|
556
556
|
res.json({ hosts: await promise, cached: false });
|
|
557
557
|
});
|
|
558
558
|
|
|
559
|
+
/** CPUUsageNSec samples per host + unit → cpu share (% of one core) between two listings. */
|
|
560
|
+
const _cpuSamples = new Map();
|
|
561
|
+
function withCpuShare(hostName, instances, now = Date.now()) {
|
|
562
|
+
return (instances || []).map((i) => {
|
|
563
|
+
if (typeof i.cpuNs !== 'number') return i;
|
|
564
|
+
const key = hostName + '|' + i.adapter + '@' + i.instance;
|
|
565
|
+
const prev = _cpuSamples.get(key);
|
|
566
|
+
_cpuSamples.set(key, { cpuNs: i.cpuNs, ts: now });
|
|
567
|
+
if (!prev || now - prev.ts < 1000 || i.cpuNs < prev.cpuNs) return { ...i, cpu: null };
|
|
568
|
+
return { ...i, cpu: Math.round(((i.cpuNs - prev.cpuNs) / ((now - prev.ts) * 1e6)) * 1000) / 10 };
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
|
|
559
572
|
async function listHosts(req) {
|
|
560
573
|
return Promise.all(
|
|
561
574
|
hostEntries(req).map(async ({ cfg, driver }) => {
|
|
@@ -581,7 +594,7 @@ async function listHosts(req) {
|
|
|
581
594
|
}
|
|
582
595
|
}),
|
|
583
596
|
);
|
|
584
|
-
return { ...base, ok: true, hostname: base.hostname || list.hostname, ...list, adapters };
|
|
597
|
+
return { ...base, ok: true, hostname: base.hostname || list.hostname, ...list, instances: withCpuShare(cfg.name, list.instances), adapters };
|
|
585
598
|
} catch (err) {
|
|
586
599
|
return { ...base, ok: false, code: err.code || 'ERROR', error: err.message };
|
|
587
600
|
}
|