@homebridge-plugins/homebridge-eufy-security 5.0.0-beta.4 → 5.0.0-beta.40
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/CONTRIBUTING.md +9 -17
- package/config.schema.json +60 -0
- package/dist/account/ownership.js +16 -16
- package/dist/account/ownership.js.map +1 -1
- package/dist/account/persistence.js +24 -74
- package/dist/account/persistence.js.map +1 -1
- package/dist/account/temporary-authentication.js +5 -3
- package/dist/account/temporary-authentication.js.map +1 -1
- package/dist/configuration.js +50 -13
- package/dist/configuration.js.map +1 -1
- package/dist/device/member-evidence.js +11 -4
- package/dist/device/member-evidence.js.map +1 -1
- package/dist/device/member-trust.js +14 -32
- package/dist/device/member-trust.js.map +1 -1
- package/dist/device/snapshot.js +6 -18
- package/dist/device/snapshot.js.map +1 -1
- package/dist/diagnostics.js +951 -334
- package/dist/diagnostics.js.map +1 -1
- package/dist/homekit/adapter.js +4 -1
- package/dist/homekit/adapter.js.map +1 -1
- package/dist/homekit/adapters/battery.js +3 -3
- package/dist/homekit/adapters/battery.js.map +1 -1
- package/dist/homekit/adapters/camera-controls.js +15 -37
- package/dist/homekit/adapters/camera-controls.js.map +1 -1
- package/dist/homekit/adapters/camera-streaming.js +74 -48
- package/dist/homekit/adapters/camera-streaming.js.map +1 -1
- package/dist/homekit/adapters/contact.js +5 -5
- package/dist/homekit/adapters/contact.js.map +1 -1
- package/dist/homekit/adapters/doorbell.js +3 -15
- package/dist/homekit/adapters/doorbell.js.map +1 -1
- package/dist/homekit/adapters/lock.js +72 -221
- package/dist/homekit/adapters/lock.js.map +1 -1
- package/dist/homekit/adapters/motion.js +3 -3
- package/dist/homekit/adapters/motion.js.map +1 -1
- package/dist/homekit/adapters/package-sensor.js +63 -0
- package/dist/homekit/adapters/package-sensor.js.map +1 -0
- package/dist/homekit/adapters/registry.js +2 -0
- package/dist/homekit/adapters/registry.js.map +1 -1
- package/dist/homekit/adapters/security-system.js +106 -250
- package/dist/homekit/adapters/security-system.js.map +1 -1
- package/dist/homekit/adapters/siren.js +5 -33
- package/dist/homekit/adapters/siren.js.map +1 -1
- package/dist/homekit/adapters/smart-light.js +19 -217
- package/dist/homekit/adapters/smart-light.js.map +1 -1
- package/dist/homekit/coverage-matrix.js +8 -67
- package/dist/homekit/coverage-matrix.js.map +1 -1
- package/dist/homekit/device-control.js +249 -13
- package/dist/homekit/device-control.js.map +1 -1
- package/dist/homekit/reconciler.js +25 -9
- package/dist/homekit/reconciler.js.map +1 -1
- package/dist/media/last-successful-image.js +8 -23
- package/dist/media/last-successful-image.js.map +1 -1
- package/dist/media/live-preview.js +217 -0
- package/dist/media/live-preview.js.map +1 -0
- package/dist/media/live-stream.js +689 -160
- package/dist/media/live-stream.js.map +1 -1
- package/dist/media/recording.js +41 -118
- package/dist/media/recording.js.map +1 -1
- package/dist/media/snapshot.js +22 -17
- package/dist/media/snapshot.js.map +1 -1
- package/dist/media/station-live-sessions.js +40 -51
- package/dist/media/station-live-sessions.js.map +1 -1
- package/dist/platform.js +61 -10
- package/dist/platform.js.map +1 -1
- package/dist/runtime/channel.js +227 -40
- package/dist/runtime/channel.js.map +1 -1
- package/dist/runtime/device-settings.js +88 -0
- package/dist/runtime/device-settings.js.map +1 -0
- package/dist/runtime/owner.js +30 -5
- package/dist/runtime/owner.js.map +1 -1
- package/dist/runtime/sdk-client.js +21 -17
- package/dist/runtime/sdk-client.js.map +1 -1
- package/dist/runtime/tracker.js +8 -38
- package/dist/runtime/tracker.js.map +1 -1
- package/dist/storage.js +1 -1
- package/dist/storage.js.map +1 -1
- package/dist/ui/dashboard.js +36 -16
- package/dist/ui/dashboard.js.map +1 -1
- package/dist/ui/runtime-channel-client.js +155 -184
- package/dist/ui/runtime-channel-client.js.map +1 -1
- package/dist/ui/server.js +81 -38
- package/dist/ui/server.js.map +1 -1
- package/homebridge-ui/public/app.css +531 -239
- package/homebridge-ui/public/assets/icons/auto_fix_high.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_0.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_1.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_2.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_3.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_4.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_5.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_6.svg +1 -0
- package/homebridge-ui/public/assets/icons/battery_full.svg +1 -0
- package/homebridge-ui/public/assets/icons/contact_support.svg +1 -0
- package/homebridge-ui/public/assets/icons/delete.svg +1 -0
- package/homebridge-ui/public/assets/icons/download.svg +1 -0
- package/homebridge-ui/public/assets/icons/extension_off.svg +1 -0
- package/homebridge-ui/public/assets/icons/info.svg +1 -0
- package/homebridge-ui/public/assets/icons/key_off.svg +1 -0
- package/homebridge-ui/public/assets/icons/keyboard_arrow_left.svg +1 -0
- package/homebridge-ui/public/assets/icons/keyboard_arrow_right.svg +1 -0
- package/homebridge-ui/public/assets/icons/keyboard_double_arrow_left.svg +1 -0
- package/homebridge-ui/public/assets/icons/keyboard_double_arrow_right.svg +1 -0
- package/homebridge-ui/public/assets/icons/movie_off.svg +1 -0
- package/homebridge-ui/public/assets/icons/play_arrow.svg +1 -0
- package/homebridge-ui/public/assets/icons/refresh.svg +1 -0
- package/homebridge-ui/public/assets/icons/satellite_alt.svg +1 -0
- package/homebridge-ui/public/assets/icons/search_off.svg +1 -0
- package/homebridge-ui/public/assets/icons/sensors_off.svg +1 -0
- package/homebridge-ui/public/assets/icons/settings_photo_camera.svg +1 -0
- package/homebridge-ui/public/assets/icons/solar_power.svg +1 -0
- package/homebridge-ui/public/assets/icons/stop.svg +1 -0
- package/homebridge-ui/public/assets/icons/videocam_off.svg +1 -0
- package/homebridge-ui/public/i18n/en.json +160 -82
- package/homebridge-ui/public/i18n/fr.json +161 -83
- package/homebridge-ui/public/index.html +225 -96
- package/homebridge-ui/public/js/app.js +814 -435
- package/homebridge-ui/public/js/dashboard.js +148 -31
- package/i18n/runtime/en.json +10 -3
- package/package.json +10 -11
- package/homebridge-ui/public/js/legacy-settings.js +0 -37
- package/homebridge-ui/public/js/profile-wizard.js +0 -61
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { createConnection } from 'node:net';
|
|
2
|
-
import { answeredDevice, answeredStatus, areRuntimeChannelDevices, FrameReader, isRuntimeChannelStatus, ownedSocket, RUNTIME_CHANNEL_CONNECT_TIMEOUT_MS, RUNTIME_CHANNEL_PROTOCOL, RUNTIME_CHANNEL_RESPONSE_TIMEOUT_MS, RUNTIME_CHANNEL_STAND_DOWN_TIMEOUT_MS, RUNTIME_DEVICES_PATH, RUNTIME_DIAGNOSTICS_PATH, RUNTIME_RESTART_PATH, RUNTIME_STAND_DOWN_PATH, RUNTIME_STATUS_PATH, } from '../runtime/channel.js';
|
|
2
|
+
import { answeredDevice, answeredDeviceSetting, answeredStatus, areRuntimeChannelDevices, areRuntimeChannelDeviceSettings, FrameReader, isRuntimeChannelStatus, LIVE_UNPLAYABLE, ownedSocket, RUNTIME_CHANNEL_CONNECT_TIMEOUT_MS, RUNTIME_CHANNEL_PROTOCOL, RUNTIME_DEVICE_LIVE_ADAPT_PATH, RUNTIME_CHANNEL_RESPONSE_TIMEOUT_MS, RUNTIME_CHANNEL_STAND_DOWN_TIMEOUT_MS, RUNTIME_CHANNEL_WRITE_TIMEOUT_MS, RUNTIME_DEVICE_LIVE_PATH, RUNTIME_DEVICE_SETTING_WRITE_PATH, RUNTIME_DEVICE_SETTINGS_PATH, RUNTIME_DEVICES_PATH, RUNTIME_DIAGNOSTICS_PATH, RUNTIME_RESTART_PATH, RUNTIME_STAND_DOWN_PATH, RUNTIME_STATUS_PATH, } from '../runtime/channel.js';
|
|
3
3
|
const STATUS_REQUEST = 1;
|
|
4
4
|
const DEVICES_REQUEST = 2;
|
|
5
5
|
const DIAGNOSTICS_REQUEST = 3;
|
|
6
6
|
const DEPARTURE_REQUEST = 4;
|
|
7
|
+
const SETTINGS_REQUEST = 5;
|
|
7
8
|
/**
|
|
8
9
|
* Speaks the channel the runtime serves while it owns the account session: reads, notifications, requests.
|
|
9
10
|
*
|
|
@@ -21,14 +22,103 @@ export class RuntimeChannelClient {
|
|
|
21
22
|
connectTimeoutMs;
|
|
22
23
|
responseTimeoutMs;
|
|
23
24
|
standDownTimeoutMs;
|
|
25
|
+
writeTimeoutMs;
|
|
24
26
|
constructor(endpoint, options = {}) {
|
|
25
27
|
this.endpoint = endpoint;
|
|
26
28
|
this.connectTimeoutMs = options.connectTimeoutMs ?? RUNTIME_CHANNEL_CONNECT_TIMEOUT_MS;
|
|
27
29
|
this.responseTimeoutMs = options.responseTimeoutMs ?? RUNTIME_CHANNEL_RESPONSE_TIMEOUT_MS;
|
|
28
30
|
this.standDownTimeoutMs = options.standDownTimeoutMs ?? RUNTIME_CHANNEL_STAND_DOWN_TIMEOUT_MS;
|
|
31
|
+
this.writeTimeoutMs = options.writeTimeoutMs ?? RUNTIME_CHANNEL_WRITE_TIMEOUT_MS;
|
|
29
32
|
}
|
|
33
|
+
/** A device's eufy settings, or undefined where no runtime answers them. */
|
|
34
|
+
async readDeviceSettings(serial) {
|
|
35
|
+
return this.over(undefined, (connection) => this.converse(connection, () => frame(SETTINGS_REQUEST, RUNTIME_DEVICE_SETTINGS_PATH, { serial }), (response, conclude) => {
|
|
36
|
+
if (response?.id !== SETTINGS_REQUEST)
|
|
37
|
+
return;
|
|
38
|
+
conclude(response.ok && areRuntimeChannelDeviceSettings(response.data)
|
|
39
|
+
? response.data.map(answeredDeviceSetting)
|
|
40
|
+
: undefined);
|
|
41
|
+
}, () => undefined, this.responseTimeoutMs));
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Writes one device setting, true where the runtime delivered it. Delivery is not the device changing: the next
|
|
45
|
+
* read is what states that. An absent runtime refuses every write.
|
|
46
|
+
*/
|
|
47
|
+
async writeDeviceSetting(write) {
|
|
48
|
+
return this.over(false, (connection) => this.converse(connection, () => frame(SETTINGS_REQUEST, RUNTIME_DEVICE_SETTING_WRITE_PATH, write), answered, () => false, this.writeTimeoutMs));
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Streams one camera's live preview as base64 JPEG pictures, each with its side and the live encoder and rate
|
|
52
|
+
* of the HomeKit side, until it ends, the runtime is gone, or `signal` aborts. Settles once it has stopped, true
|
|
53
|
+
* where the last HomeKit run yielded no picture; a runtime without the path, or with no preview to give, settles
|
|
54
|
+
* at once.
|
|
55
|
+
*/
|
|
56
|
+
async liveDevice(query, onPicture, signal) {
|
|
57
|
+
return this.over(false, (connection) => {
|
|
58
|
+
if (signal.aborted)
|
|
59
|
+
connection.destroy();
|
|
60
|
+
else
|
|
61
|
+
signal.addEventListener('abort', () => connection.destroy(), { once: true });
|
|
62
|
+
return this.converse(connection, () => frame(SETTINGS_REQUEST, RUNTIME_DEVICE_LIVE_PATH, query), (response, conclude) => {
|
|
63
|
+
if (response?.id !== SETTINGS_REQUEST)
|
|
64
|
+
return;
|
|
65
|
+
if (!response.ok)
|
|
66
|
+
return conclude(response.data === LIVE_UNPLAYABLE);
|
|
67
|
+
const { side, encoder, kbps } = response.coding ?? {};
|
|
68
|
+
if (typeof response.data !== 'string' || typeof encoder !== 'string')
|
|
69
|
+
return conclude(false);
|
|
70
|
+
if (side !== 'raw' && side !== 'homekit')
|
|
71
|
+
return conclude(false);
|
|
72
|
+
onPicture(response.data, typeof kbps === 'number' ? { side, encoder, kbps } : { side, encoder });
|
|
73
|
+
}, () => false);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** Restarts the HomeKit side of the camera's running preview with other settings; false where none runs. */
|
|
77
|
+
async adaptLive(query) {
|
|
78
|
+
return this.over(false, (connection) => this.converse(connection, () => frame(SETTINGS_REQUEST, RUNTIME_DEVICE_LIVE_ADAPT_PATH, query), answered, () => false, this.responseTimeoutMs));
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Reads the greeting, the status, and the observations.
|
|
82
|
+
*
|
|
83
|
+
* The status is one answer and the observations are another, so a runtime that answers the first and then says
|
|
84
|
+
* nothing, closes, or overruns the frame bound concludes with the status alone. Only a read with no status at
|
|
85
|
+
* all, an unreadable frame, or an answer this client cannot use is absence.
|
|
86
|
+
*/
|
|
30
87
|
async read() {
|
|
31
|
-
|
|
88
|
+
let greeting;
|
|
89
|
+
let status;
|
|
90
|
+
let devices;
|
|
91
|
+
let devicesSettled = false;
|
|
92
|
+
const reading = () => status && {
|
|
93
|
+
ready: greeting.ready,
|
|
94
|
+
status,
|
|
95
|
+
...(devices === undefined ? {} : { devices }),
|
|
96
|
+
...(greeting.version === undefined ? {} : { version: greeting.version }),
|
|
97
|
+
...(greeting.build === undefined ? {} : { build: greeting.build }),
|
|
98
|
+
...(greeting.restartable === undefined ? {} : { restartable: greeting.restartable }),
|
|
99
|
+
};
|
|
100
|
+
return this.over(undefined, (connection) => this.converse(connection, (opened) => {
|
|
101
|
+
if (typeof opened.ready !== 'boolean')
|
|
102
|
+
return undefined;
|
|
103
|
+
greeting = opened;
|
|
104
|
+
return frame(STATUS_REQUEST, RUNTIME_STATUS_PATH) + frame(DEVICES_REQUEST, RUNTIME_DEVICES_PATH);
|
|
105
|
+
}, (response, conclude) => {
|
|
106
|
+
if (response?.id === STATUS_REQUEST) {
|
|
107
|
+
if (!response.ok || !isRuntimeChannelStatus(response.data))
|
|
108
|
+
return conclude(undefined);
|
|
109
|
+
status = answeredStatus(response.data);
|
|
110
|
+
}
|
|
111
|
+
else if (response?.id === DEVICES_REQUEST) {
|
|
112
|
+
devicesSettled = true;
|
|
113
|
+
if (response.ok) {
|
|
114
|
+
if (!areRuntimeChannelDevices(response.data))
|
|
115
|
+
return conclude(undefined);
|
|
116
|
+
devices = response.data.map(answeredDevice);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (status && devicesSettled)
|
|
120
|
+
conclude(reading());
|
|
121
|
+
}, (ending) => (ending === 'fault' ? undefined : reading()), this.responseTimeoutMs));
|
|
32
122
|
}
|
|
33
123
|
/**
|
|
34
124
|
* Tells the runtime which authorized evidence window was written, so it reads the file now.
|
|
@@ -37,7 +127,10 @@ export class RuntimeChannelClient {
|
|
|
37
127
|
* way: the file the runtime reads is the authority, and it decided before this was sent.
|
|
38
128
|
*/
|
|
39
129
|
async notifyAuthorization(supportCaseId) {
|
|
40
|
-
return this.over(undefined, (connection) => this.
|
|
130
|
+
return this.over(undefined, (connection) => this.converse(connection, () => frame(DIAGNOSTICS_REQUEST, RUNTIME_DIAGNOSTICS_PATH, { supportCaseId }), (response, conclude) => {
|
|
131
|
+
if (response?.id === DIAGNOSTICS_REQUEST)
|
|
132
|
+
conclude();
|
|
133
|
+
}, () => undefined, this.responseTimeoutMs));
|
|
41
134
|
}
|
|
42
135
|
/**
|
|
43
136
|
* Asks the runtime to release the account session, reporting whether it stood down.
|
|
@@ -49,16 +142,30 @@ export class RuntimeChannelClient {
|
|
|
49
142
|
* answer, which is that the session was not freed.
|
|
50
143
|
*/
|
|
51
144
|
async requestStandDown() {
|
|
52
|
-
return this.over(false, (connection) => this.
|
|
145
|
+
return this.over(false, (connection) => this.departed(connection, RUNTIME_STAND_DOWN_PATH));
|
|
53
146
|
}
|
|
54
147
|
/**
|
|
55
148
|
* Asks the runtime to end itself so Homebridge brings up the installed build, reporting whether it accepted.
|
|
56
149
|
*
|
|
57
150
|
* A runtime that does not serve the path, or refuses because ending it would not replace it, is a false rather
|
|
58
|
-
* than a failure, so a caller never has to tell an old runtime apart from an unwilling one.
|
|
151
|
+
* than a failure, so a caller never has to tell an old runtime apart from an unwilling one. Whether the
|
|
152
|
+
* replacement came up is read from the next greeting.
|
|
59
153
|
*/
|
|
60
154
|
async requestRestart() {
|
|
61
|
-
return this.over(false, (connection) => this.
|
|
155
|
+
return this.over(false, (connection) => this.departed(connection, RUNTIME_RESTART_PATH));
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Sends one departure request and reports whether the endpoint then closed without refusing it.
|
|
159
|
+
*
|
|
160
|
+
* A runtime that releases its session or ends for replacement closes its endpoint at the end of its own bounded
|
|
161
|
+
* shutdown, so the closing is the completion this waits for and an explicit refusal is the one answer that ends
|
|
162
|
+
* it early. Acceptance is not waited for, because a runtime that closes the connection may not have flushed it.
|
|
163
|
+
*/
|
|
164
|
+
departed(connection, path) {
|
|
165
|
+
return this.converse(connection, () => frame(DEPARTURE_REQUEST, path), (response, conclude) => {
|
|
166
|
+
if (response?.id === DEPARTURE_REQUEST && !response.ok)
|
|
167
|
+
conclude(false);
|
|
168
|
+
}, (ending) => ending === 'closed', this.standDownTimeoutMs);
|
|
62
169
|
}
|
|
63
170
|
/**
|
|
64
171
|
* Runs one operation over its own connection, answering `absent` wherever the endpoint could not be used.
|
|
@@ -102,204 +209,68 @@ export class RuntimeChannelClient {
|
|
|
102
209
|
});
|
|
103
210
|
}
|
|
104
211
|
/**
|
|
105
|
-
*
|
|
212
|
+
* Holds one conversation: writes what `request` makes of the greeting, then hands each response to `onResponse`
|
|
213
|
+
* until it concludes, and answers every other ending with `unanswered`.
|
|
106
214
|
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
215
|
+
* Everything before the request is written is a `fault`: a greeting naming another protocol or one `request`
|
|
216
|
+
* refuses is never sent the request, so a runtime running older code is never handed a frame it would read as
|
|
217
|
+
* something else. An unreadable frame is a `fault` too. After the request, the endpoint closing is `closed`, and
|
|
218
|
+
* `timeoutMs` passing or a frame beyond the frame bound is `lapsed`.
|
|
109
219
|
*/
|
|
110
|
-
|
|
220
|
+
converse(connection, request, onResponse, unanswered, timeoutMs) {
|
|
111
221
|
return new Promise((resolve) => {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
const conclude = () => {
|
|
222
|
+
let requested = false;
|
|
223
|
+
let done = false;
|
|
224
|
+
const conclude = (value) => {
|
|
225
|
+
done = true;
|
|
115
226
|
clearTimeout(settle);
|
|
116
|
-
resolve();
|
|
227
|
+
resolve(value);
|
|
117
228
|
};
|
|
118
|
-
const
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
connection.once('close', conclude);
|
|
122
|
-
connection.on('data', (chunk) => {
|
|
123
|
-
const frames = reader.accept(chunk);
|
|
124
|
-
if (!frames) {
|
|
125
|
-
conclude();
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
for (const frame of frames) {
|
|
129
|
-
let parsed;
|
|
130
|
-
try {
|
|
131
|
-
parsed = JSON.parse(frame);
|
|
132
|
-
}
|
|
133
|
-
catch {
|
|
134
|
-
conclude();
|
|
135
|
-
return;
|
|
136
|
-
}
|
|
137
|
-
if (greeted) {
|
|
138
|
-
if (parsed?.id === DIAGNOSTICS_REQUEST) {
|
|
139
|
-
conclude();
|
|
140
|
-
return;
|
|
141
|
-
}
|
|
142
|
-
continue;
|
|
143
|
-
}
|
|
144
|
-
if (parsed?.protocol !== RUNTIME_CHANNEL_PROTOCOL) {
|
|
145
|
-
conclude();
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
greeted = true;
|
|
149
|
-
connection.write(`${JSON.stringify({
|
|
150
|
-
v: RUNTIME_CHANNEL_PROTOCOL,
|
|
151
|
-
id: DIAGNOSTICS_REQUEST,
|
|
152
|
-
path: RUNTIME_DIAGNOSTICS_PATH,
|
|
153
|
-
body: { supportCaseId },
|
|
154
|
-
})}\n`);
|
|
155
|
-
}
|
|
156
|
-
});
|
|
157
|
-
});
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Sends one departure request after the greeting and reports what became of it.
|
|
161
|
-
*
|
|
162
|
-
* A runtime that releases its session or ends for replacement closes its endpoint at the end of its own bounded
|
|
163
|
-
* shutdown, so the closing is the completion this waits for and an explicit refusal is the one answer that ends
|
|
164
|
-
* it early. Acceptance is not waited for, because a runtime that closes the connection may not have flushed it.
|
|
165
|
-
* A protocol this client does not speak is never sent the request, so a frame an older runtime reads as
|
|
166
|
-
* something else cannot take a session down that nothing asked for.
|
|
167
|
-
*/
|
|
168
|
-
accepted(connection, path) {
|
|
169
|
-
return new Promise((resolve) => {
|
|
170
|
-
const settle = setTimeout(() => resolve(false), this.standDownTimeoutMs);
|
|
171
|
-
settle.unref();
|
|
172
|
-
const conclude = (accepted) => {
|
|
173
|
-
clearTimeout(settle);
|
|
174
|
-
resolve(accepted);
|
|
229
|
+
const end = (ending) => {
|
|
230
|
+
if (!done)
|
|
231
|
+
conclude(unanswered(requested ? ending : 'fault'));
|
|
175
232
|
};
|
|
233
|
+
const settle = timeoutMs === undefined ? undefined : setTimeout(() => end('lapsed'), timeoutMs);
|
|
234
|
+
settle?.unref();
|
|
176
235
|
const reader = new FrameReader();
|
|
177
|
-
|
|
178
|
-
connection.once('
|
|
179
|
-
connection.once('close', () => conclude(requested));
|
|
236
|
+
connection.once('error', () => end('closed'));
|
|
237
|
+
connection.once('close', () => end('closed'));
|
|
180
238
|
connection.on('data', (chunk) => {
|
|
181
239
|
const frames = reader.accept(chunk);
|
|
182
|
-
if (!frames)
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
for (const frame of frames) {
|
|
187
|
-
let parsed;
|
|
188
|
-
try {
|
|
189
|
-
parsed = JSON.parse(frame);
|
|
190
|
-
}
|
|
191
|
-
catch {
|
|
192
|
-
conclude(false);
|
|
240
|
+
if (!frames)
|
|
241
|
+
return end('lapsed');
|
|
242
|
+
for (const text of frames) {
|
|
243
|
+
if (done)
|
|
193
244
|
return;
|
|
194
|
-
}
|
|
195
|
-
if (!requested) {
|
|
196
|
-
if (parsed?.protocol !== RUNTIME_CHANNEL_PROTOCOL) {
|
|
197
|
-
conclude(false);
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
requested = true;
|
|
201
|
-
connection.write(`${JSON.stringify({ v: RUNTIME_CHANNEL_PROTOCOL, id: DEPARTURE_REQUEST, path })}\n`);
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
const response = parsed;
|
|
205
|
-
if (response?.id === DEPARTURE_REQUEST && !response.ok) {
|
|
206
|
-
conclude(false);
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
exchange(connection) {
|
|
214
|
-
return new Promise((resolve, reject) => {
|
|
215
|
-
const settle = setTimeout(() => concludeOrFail('runtime channel response timed out'), this.responseTimeoutMs);
|
|
216
|
-
settle.unref();
|
|
217
|
-
const reader = new FrameReader();
|
|
218
|
-
let greeting;
|
|
219
|
-
const fail = (message) => {
|
|
220
|
-
clearTimeout(settle);
|
|
221
|
-
reject(new Error(message));
|
|
222
|
-
};
|
|
223
|
-
/**
|
|
224
|
-
* Concludes with the status alone where the observations never settled.
|
|
225
|
-
*
|
|
226
|
-
* The status is one answer and the observations are another, so a runtime that answers the first and
|
|
227
|
-
* then says nothing must not cost both. Only a read with no status at all is a failure.
|
|
228
|
-
*/
|
|
229
|
-
const concludeOrFail = (message) => {
|
|
230
|
-
if (greeting && answeredStatusValue) {
|
|
231
|
-
devicesSettled = true;
|
|
232
|
-
settleIfComplete();
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
235
|
-
fail(message);
|
|
236
|
-
};
|
|
237
|
-
connection.once('error', () => concludeOrFail('runtime channel faulted'));
|
|
238
|
-
connection.once('close', () => concludeOrFail('runtime channel closed before answering'));
|
|
239
|
-
let answeredStatusValue;
|
|
240
|
-
let answeredDevices;
|
|
241
|
-
let devicesSettled = false;
|
|
242
|
-
const settleIfComplete = () => {
|
|
243
|
-
if (!greeting || !answeredStatusValue || !devicesSettled) {
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
clearTimeout(settle);
|
|
247
|
-
resolve({
|
|
248
|
-
ready: greeting.ready,
|
|
249
|
-
status: answeredStatusValue,
|
|
250
|
-
...(answeredDevices === undefined ? {} : { devices: answeredDevices }),
|
|
251
|
-
...(greeting.version === undefined ? {} : { version: greeting.version }),
|
|
252
|
-
...(greeting.restartable === undefined ? {} : { restartable: greeting.restartable }),
|
|
253
|
-
});
|
|
254
|
-
};
|
|
255
|
-
connection.on('data', (chunk) => {
|
|
256
|
-
const frames = reader.accept(chunk);
|
|
257
|
-
if (!frames) {
|
|
258
|
-
connection.destroy();
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
for (const frame of frames) {
|
|
262
245
|
let parsed;
|
|
263
246
|
try {
|
|
264
|
-
parsed = JSON.parse(
|
|
247
|
+
parsed = JSON.parse(text);
|
|
265
248
|
}
|
|
266
249
|
catch {
|
|
267
|
-
|
|
268
|
-
return;
|
|
250
|
+
return end('fault');
|
|
269
251
|
}
|
|
270
|
-
if (
|
|
271
|
-
|
|
272
|
-
if (opened?.protocol !== RUNTIME_CHANNEL_PROTOCOL || typeof opened.ready !== 'boolean') {
|
|
273
|
-
fail('runtime channel speaks another protocol');
|
|
274
|
-
return;
|
|
275
|
-
}
|
|
276
|
-
greeting = opened;
|
|
277
|
-
connection.write(`${JSON.stringify({ v: RUNTIME_CHANNEL_PROTOCOL, id: STATUS_REQUEST, path: RUNTIME_STATUS_PATH })}\n` +
|
|
278
|
-
`${JSON.stringify({ v: RUNTIME_CHANNEL_PROTOCOL, id: DEVICES_REQUEST, path: RUNTIME_DEVICES_PATH })}\n`);
|
|
252
|
+
if (requested) {
|
|
253
|
+
onResponse(parsed, conclude);
|
|
279
254
|
continue;
|
|
280
255
|
}
|
|
281
|
-
const
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
answeredStatusValue = answeredStatus(response.data);
|
|
288
|
-
}
|
|
289
|
-
else if (response?.id === DEVICES_REQUEST) {
|
|
290
|
-
devicesSettled = true;
|
|
291
|
-
if (response.ok) {
|
|
292
|
-
if (!areRuntimeChannelDevices(response.data)) {
|
|
293
|
-
fail('runtime channel answered no observations this client can use');
|
|
294
|
-
return;
|
|
295
|
-
}
|
|
296
|
-
answeredDevices = response.data.map(answeredDevice);
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
settleIfComplete();
|
|
256
|
+
const greeting = parsed;
|
|
257
|
+
const written = greeting?.protocol === RUNTIME_CHANNEL_PROTOCOL ? request(greeting) : undefined;
|
|
258
|
+
if (written === undefined)
|
|
259
|
+
return end('fault');
|
|
260
|
+
requested = true;
|
|
261
|
+
connection.write(written);
|
|
300
262
|
}
|
|
301
263
|
});
|
|
302
264
|
});
|
|
303
265
|
}
|
|
304
266
|
}
|
|
267
|
+
/** One request frame of this protocol. */
|
|
268
|
+
function frame(id, path, body) {
|
|
269
|
+
return `${JSON.stringify({ v: RUNTIME_CHANNEL_PROTOCOL, id, path, ...(body === undefined ? {} : { body }) })}\n`;
|
|
270
|
+
}
|
|
271
|
+
/** Concludes on the settings request's answer: true where accepted, false where refused. */
|
|
272
|
+
function answered(response, conclude) {
|
|
273
|
+
if (response?.id === SETTINGS_REQUEST)
|
|
274
|
+
conclude(!!response.ok);
|
|
275
|
+
}
|
|
305
276
|
//# sourceMappingURL=runtime-channel-client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-channel-client.js","sourceRoot":"","sources":["../../src/ui/runtime-channel-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAe,MAAM,UAAU,CAAC;AAEzD,OAAO,EACL,cAAc,EACd,cAAc,EACd,wBAAwB,EACxB,WAAW,EACX,sBAAsB,EACtB,WAAW,EACX,kCAAkC,EAClC,wBAAwB,EACxB,mCAAmC,EACnC,qCAAqC,EACrC,oBAAoB,EACpB,wBAAwB,EACxB,oBAAoB,EACpB,uBAAuB,EACvB,mBAAmB,
|
|
1
|
+
{"version":3,"file":"runtime-channel-client.js","sourceRoot":"","sources":["../../src/ui/runtime-channel-client.ts"],"names":[],"mappings":"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"}
|