@alwaysai/device-agent 1.4.0 → 2.0.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/lib/application-control/config.d.ts.map +1 -1
- package/lib/application-control/config.js +10 -5
- package/lib/application-control/config.js.map +1 -1
- package/lib/application-control/environment-variables.d.ts +1 -5
- package/lib/application-control/environment-variables.d.ts.map +1 -1
- package/lib/application-control/environment-variables.js +9 -26
- package/lib/application-control/environment-variables.js.map +1 -1
- package/lib/application-control/environment-variables.test.js +27 -7
- package/lib/application-control/environment-variables.test.js.map +1 -1
- package/lib/application-control/index.d.ts +4 -4
- package/lib/application-control/index.d.ts.map +1 -1
- package/lib/application-control/index.js +1 -4
- package/lib/application-control/index.js.map +1 -1
- package/lib/application-control/install.d.ts.map +1 -1
- package/lib/application-control/install.js +9 -7
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/models.d.ts +5 -11
- package/lib/application-control/models.d.ts.map +1 -1
- package/lib/application-control/models.js +27 -64
- package/lib/application-control/models.js.map +1 -1
- package/lib/application-control/status.d.ts.map +1 -1
- package/lib/application-control/status.js +10 -12
- package/lib/application-control/status.js.map +1 -1
- package/lib/application-control/utils.d.ts +0 -4
- package/lib/application-control/utils.d.ts.map +1 -1
- package/lib/application-control/utils.js +3 -26
- package/lib/application-control/utils.js.map +1 -1
- package/lib/cloud-connection/bootstrap-provision.js +3 -2
- package/lib/cloud-connection/bootstrap-provision.js.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts +11 -16
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +295 -246
- package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
- package/lib/cloud-connection/device-agent.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent.js +11 -9
- package/lib/cloud-connection/device-agent.js.map +1 -1
- package/lib/cloud-connection/live-updates-handler.d.ts +18 -27
- package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
- package/lib/cloud-connection/live-updates-handler.js +58 -170
- package/lib/cloud-connection/live-updates-handler.js.map +1 -1
- package/lib/cloud-connection/live-updates-handler.test.js +76 -54
- package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
- package/lib/cloud-connection/passthrough-handler.d.ts +9 -4
- package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
- package/lib/cloud-connection/passthrough-handler.js +95 -62
- package/lib/cloud-connection/passthrough-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.d.ts +5 -1
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
- package/lib/cloud-connection/shadow-handler.js +63 -31
- package/lib/cloud-connection/shadow-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.test.js +45 -57
- package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
- package/lib/cloud-connection/shadow.d.ts.map +1 -1
- package/lib/cloud-connection/shadow.js +2 -1
- package/lib/cloud-connection/shadow.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.d.ts +7 -2
- package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
- package/lib/cloud-connection/transaction-manager.js +29 -29
- package/lib/cloud-connection/transaction-manager.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.test.js +105 -3
- package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
- package/lib/device-control/device-control.d.ts +14 -6
- package/lib/device-control/device-control.d.ts.map +1 -1
- package/lib/device-control/device-control.js +172 -72
- package/lib/device-control/device-control.js.map +1 -1
- package/lib/docker/docker-compose.d.ts +14 -0
- package/lib/docker/docker-compose.d.ts.map +1 -0
- package/lib/docker/docker-compose.js +57 -0
- package/lib/docker/docker-compose.js.map +1 -0
- package/lib/index.js +2 -5
- package/lib/index.js.map +1 -1
- package/lib/infrastructure/agent-config.d.ts +46 -14
- package/lib/infrastructure/agent-config.d.ts.map +1 -1
- package/lib/infrastructure/agent-config.js +36 -21
- package/lib/infrastructure/agent-config.js.map +1 -1
- package/lib/infrastructure/agent-config.test.js +6 -1
- package/lib/infrastructure/agent-config.test.js.map +1 -1
- package/lib/infrastructure/config-check-utility.d.ts +6 -0
- package/lib/infrastructure/config-check-utility.d.ts.map +1 -0
- package/lib/infrastructure/config-check-utility.js +67 -0
- package/lib/infrastructure/config-check-utility.js.map +1 -0
- package/lib/infrastructure/config-check-utility.test.d.ts +2 -0
- package/lib/infrastructure/config-check-utility.test.d.ts.map +1 -0
- package/lib/infrastructure/config-check-utility.test.js +109 -0
- package/lib/infrastructure/config-check-utility.test.js.map +1 -0
- package/lib/infrastructure/device-certificate.d.ts +10 -0
- package/lib/infrastructure/device-certificate.d.ts.map +1 -0
- package/lib/infrastructure/device-certificate.js +47 -0
- package/lib/infrastructure/device-certificate.js.map +1 -0
- package/lib/infrastructure/device-certificate.test.d.ts +2 -0
- package/lib/infrastructure/device-certificate.test.d.ts.map +1 -0
- package/lib/infrastructure/device-certificate.test.js +24 -0
- package/lib/infrastructure/device-certificate.test.js.map +1 -0
- package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts +2 -0
- package/lib/infrastructure/legacy-migration/legacy-file.test.d.ts.map +1 -0
- package/lib/infrastructure/legacy-migration/legacy-file.test.js +61 -0
- package/lib/infrastructure/legacy-migration/legacy-file.test.js.map +1 -0
- package/lib/infrastructure/legacy-migration/legacy-files.d.ts +75 -0
- package/lib/infrastructure/legacy-migration/legacy-files.d.ts.map +1 -0
- package/lib/infrastructure/legacy-migration/legacy-files.js +75 -0
- package/lib/infrastructure/legacy-migration/legacy-files.js.map +1 -0
- package/lib/infrastructure/legacy-migration/legacy-migration.d.ts +6 -0
- package/lib/infrastructure/legacy-migration/legacy-migration.d.ts.map +1 -0
- package/lib/infrastructure/legacy-migration/legacy-migration.js +149 -0
- package/lib/infrastructure/legacy-migration/legacy-migration.js.map +1 -0
- package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts +2 -0
- package/lib/infrastructure/legacy-migration/legacy-migration.test.d.ts.map +1 -0
- package/lib/infrastructure/legacy-migration/legacy-migration.test.js +226 -0
- package/lib/infrastructure/legacy-migration/legacy-migration.test.js.map +1 -0
- package/lib/infrastructure/require-files-present-ready.test.d.ts +2 -0
- package/lib/infrastructure/require-files-present-ready.test.d.ts.map +1 -0
- package/lib/infrastructure/require-files-present-ready.test.js +44 -0
- package/lib/infrastructure/require-files-present-ready.test.js.map +1 -0
- package/lib/infrastructure/required-config-checks.d.ts +2 -0
- package/lib/infrastructure/required-config-checks.d.ts.map +1 -0
- package/lib/infrastructure/required-config-checks.js +30 -0
- package/lib/infrastructure/required-config-checks.js.map +1 -0
- package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -1
- package/lib/infrastructure/tokens-and-device-cfg.js +11 -8
- package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -1
- package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -1
- package/lib/local-connection/rabbitmq-connection.js +21 -21
- package/lib/local-connection/rabbitmq-connection.js.map +1 -1
- package/lib/secure-tunneling/secure-tunneling.d.ts +15 -23
- package/lib/secure-tunneling/secure-tunneling.d.ts.map +1 -1
- package/lib/secure-tunneling/secure-tunneling.js +52 -47
- package/lib/secure-tunneling/secure-tunneling.js.map +1 -1
- package/lib/secure-tunneling/secure-tunneling.test.js +29 -31
- package/lib/secure-tunneling/secure-tunneling.test.js.map +1 -1
- package/lib/subcommands/app/analytics.d.ts.map +1 -1
- package/lib/subcommands/app/analytics.js +1 -2
- package/lib/subcommands/app/analytics.js.map +1 -1
- package/lib/subcommands/app/env-vars.d.ts +4 -0
- package/lib/subcommands/app/env-vars.d.ts.map +1 -1
- package/lib/subcommands/app/env-vars.js +52 -6
- package/lib/subcommands/app/env-vars.js.map +1 -1
- package/lib/subcommands/app/index.d.ts.map +1 -1
- package/lib/subcommands/app/index.js +1 -3
- package/lib/subcommands/app/index.js.map +1 -1
- package/lib/subcommands/app/models.d.ts +0 -11
- package/lib/subcommands/app/models.d.ts.map +1 -1
- package/lib/subcommands/app/models.js +2 -58
- package/lib/subcommands/app/models.js.map +1 -1
- package/lib/subcommands/app/shadow.d.ts.map +1 -1
- package/lib/subcommands/app/shadow.js +6 -5
- package/lib/subcommands/app/shadow.js.map +1 -1
- package/lib/subcommands/app/version.d.ts.map +1 -1
- package/lib/subcommands/app/version.js +2 -4
- package/lib/subcommands/app/version.js.map +1 -1
- package/lib/subcommands/config.d.ts +2 -0
- package/lib/subcommands/config.d.ts.map +1 -0
- package/lib/subcommands/config.js +39 -0
- package/lib/subcommands/config.js.map +1 -0
- package/lib/subcommands/device/clean.d.ts +1 -1
- package/lib/subcommands/device/clean.d.ts.map +1 -1
- package/lib/subcommands/device/clean.js +25 -15
- package/lib/subcommands/device/clean.js.map +1 -1
- package/lib/subcommands/device/get-info.d.ts +2 -0
- package/lib/subcommands/device/get-info.d.ts.map +1 -0
- package/lib/subcommands/device/get-info.js +36 -0
- package/lib/subcommands/device/get-info.js.map +1 -0
- package/lib/subcommands/device/index.d.ts.map +1 -1
- package/lib/subcommands/device/index.js +13 -2
- package/lib/subcommands/device/index.js.map +1 -1
- package/lib/subcommands/device/init.d.ts +5 -0
- package/lib/subcommands/device/init.d.ts.map +1 -0
- package/lib/subcommands/device/{device.js → init.js} +10 -49
- package/lib/subcommands/device/init.js.map +1 -0
- package/lib/subcommands/device/migrate.d.ts +2 -0
- package/lib/subcommands/device/migrate.d.ts.map +1 -0
- package/lib/subcommands/device/migrate.js +24 -0
- package/lib/subcommands/device/migrate.js.map +1 -0
- package/lib/subcommands/device/refresh.d.ts +2 -0
- package/lib/subcommands/device/refresh.d.ts.map +1 -0
- package/lib/subcommands/device/refresh.js +25 -0
- package/lib/subcommands/device/refresh.js.map +1 -0
- package/lib/subcommands/device/restart.d.ts +2 -0
- package/lib/subcommands/device/restart.d.ts.map +1 -0
- package/lib/subcommands/device/restart.js +14 -0
- package/lib/subcommands/device/restart.js.map +1 -0
- package/lib/subcommands/index.d.ts +1 -1
- package/lib/subcommands/index.d.ts.map +1 -1
- package/lib/subcommands/index.js +3 -1
- package/lib/subcommands/index.js.map +1 -1
- package/lib/subcommands/rabbitmq-connection.d.ts +1 -1
- package/lib/subcommands/rabbitmq-connection.d.ts.map +1 -1
- package/lib/util/aai-error.d.ts +12 -0
- package/lib/util/aai-error.d.ts.map +1 -0
- package/lib/util/aai-error.js +11 -0
- package/lib/util/aai-error.js.map +1 -0
- package/lib/util/aws-regions.d.ts +2 -0
- package/lib/util/aws-regions.d.ts.map +1 -0
- package/lib/util/{cloud-mode-ready.js → aws-regions.js} +2 -20
- package/lib/util/aws-regions.js.map +1 -0
- package/lib/util/check-for-updates.d.ts +3 -0
- package/lib/util/check-for-updates.d.ts.map +1 -0
- package/lib/util/check-for-updates.js +46 -0
- package/lib/util/check-for-updates.js.map +1 -0
- package/lib/util/clean-certs.d.ts.map +1 -1
- package/lib/util/clean-certs.js +5 -4
- package/lib/util/clean-certs.js.map +1 -1
- package/lib/util/directories.d.ts +4 -18
- package/lib/util/directories.d.ts.map +1 -1
- package/lib/util/directories.js +18 -32
- package/lib/util/directories.js.map +1 -1
- package/lib/util/file.d.ts +11 -0
- package/lib/util/file.d.ts.map +1 -0
- package/lib/util/file.js +127 -0
- package/lib/util/file.js.map +1 -0
- package/lib/util/file.test.d.ts +2 -0
- package/lib/util/file.test.d.ts.map +1 -0
- package/lib/util/file.test.js +87 -0
- package/lib/util/file.test.js.map +1 -0
- package/lib/util/get-device-id.d.ts.map +1 -1
- package/lib/util/get-device-id.js +7 -1
- package/lib/util/get-device-id.js.map +1 -1
- package/lib/util/http-client.js +3 -3
- package/lib/util/http-client.js.map +1 -1
- package/package.json +22 -19
- package/readme.md +15 -35
- package/src/application-control/config.ts +10 -13
- package/src/application-control/environment-variables.test.ts +28 -7
- package/src/application-control/environment-variables.ts +13 -40
- package/src/application-control/index.ts +3 -16
- package/src/application-control/install.ts +16 -10
- package/src/application-control/models.ts +40 -98
- package/src/application-control/status.ts +9 -7
- package/src/application-control/utils.ts +1 -29
- package/src/cloud-connection/bootstrap-provision.ts +7 -7
- package/src/cloud-connection/device-agent-cloud-connection.ts +647 -509
- package/src/cloud-connection/device-agent.ts +16 -7
- package/src/cloud-connection/live-updates-handler.test.ts +137 -64
- package/src/cloud-connection/live-updates-handler.ts +103 -234
- package/src/cloud-connection/passthrough-handler.ts +134 -75
- package/src/cloud-connection/shadow-handler.test.ts +45 -57
- package/src/cloud-connection/shadow-handler.ts +114 -56
- package/src/cloud-connection/shadow.ts +4 -1
- package/src/cloud-connection/transaction-manager.test.ts +127 -3
- package/src/cloud-connection/transaction-manager.ts +68 -39
- package/src/device-control/device-control.ts +179 -72
- package/src/docker/docker-compose.ts +61 -0
- package/src/index.ts +2 -6
- package/src/infrastructure/agent-config.test.ts +9 -2
- package/src/infrastructure/agent-config.ts +45 -46
- package/src/infrastructure/config-check-utility.test.ts +154 -0
- package/src/infrastructure/config-check-utility.ts +77 -0
- package/src/infrastructure/device-certificate.test.ts +40 -0
- package/src/infrastructure/device-certificate.ts +58 -0
- package/src/infrastructure/legacy-migration/legacy-file.test.ts +88 -0
- package/src/infrastructure/legacy-migration/legacy-files.ts +101 -0
- package/src/infrastructure/legacy-migration/legacy-migration.test.ts +396 -0
- package/src/infrastructure/legacy-migration/legacy-migration.ts +229 -0
- package/src/infrastructure/require-files-present-ready.test.ts +53 -0
- package/src/infrastructure/required-config-checks.ts +33 -0
- package/src/infrastructure/tokens-and-device-cfg.ts +12 -10
- package/src/local-connection/rabbitmq-connection.ts +28 -23
- package/src/secure-tunneling/secure-tunneling.test.ts +37 -39
- package/src/secure-tunneling/secure-tunneling.ts +74 -69
- package/src/subcommands/app/analytics.ts +2 -4
- package/src/subcommands/app/env-vars.ts +72 -9
- package/src/subcommands/app/index.ts +3 -11
- package/src/subcommands/app/models.ts +5 -81
- package/src/subcommands/app/shadow.ts +6 -5
- package/src/subcommands/app/version.ts +3 -4
- package/src/subcommands/config.ts +42 -0
- package/src/subcommands/device/clean.ts +32 -18
- package/src/subcommands/device/get-info.ts +49 -0
- package/src/subcommands/device/index.ts +13 -2
- package/src/subcommands/device/{device.ts → init.ts} +11 -69
- package/src/subcommands/device/migrate.ts +20 -0
- package/src/subcommands/device/refresh.ts +23 -0
- package/src/subcommands/device/restart.ts +11 -0
- package/src/subcommands/index.ts +3 -1
- package/src/util/aai-error.ts +20 -0
- package/src/util/{cloud-mode-ready.ts → aws-regions.ts} +0 -24
- package/src/util/check-for-updates.ts +53 -0
- package/src/util/clean-certs.ts +8 -4
- package/src/util/directories.ts +23 -67
- package/src/util/file.test.ts +90 -0
- package/src/util/file.ts +156 -0
- package/src/util/get-device-id.ts +7 -7
- package/src/util/http-client.ts +2 -2
- package/lib/docker/docker-compose-cmd.d.ts +0 -5
- package/lib/docker/docker-compose-cmd.d.ts.map +0 -1
- package/lib/docker/docker-compose-cmd.js +0 -16
- package/lib/docker/docker-compose-cmd.js.map +0 -1
- package/lib/subcommands/device/device.d.ts +0 -7
- package/lib/subcommands/device/device.d.ts.map +0 -1
- package/lib/subcommands/device/device.js.map +0 -1
- package/lib/util/cloud-mode-ready.d.ts +0 -3
- package/lib/util/cloud-mode-ready.d.ts.map +0 -1
- package/lib/util/cloud-mode-ready.js.map +0 -1
- package/lib/util/download-file.d.ts +0 -6
- package/lib/util/download-file.d.ts.map +0 -1
- package/lib/util/download-file.js +0 -25
- package/lib/util/download-file.js.map +0 -1
- package/lib/util/fetch-with-timeout.d.ts +0 -4
- package/lib/util/fetch-with-timeout.d.ts.map +0 -1
- package/lib/util/fetch-with-timeout.js +0 -30
- package/lib/util/fetch-with-timeout.js.map +0 -1
- package/lib/util/parsing.d.ts +0 -2
- package/lib/util/parsing.d.ts.map +0 -1
- package/lib/util/parsing.js +0 -17
- package/lib/util/parsing.js.map +0 -1
- package/lib/util/safe-rimraf.d.ts +0 -2
- package/lib/util/safe-rimraf.d.ts.map +0 -1
- package/lib/util/safe-rimraf.js +0 -16
- package/lib/util/safe-rimraf.js.map +0 -1
- package/src/docker/docker-compose-cmd.ts +0 -15
- package/src/util/download-file.ts +0 -25
- package/src/util/fetch-with-timeout.ts +0 -35
- package/src/util/parsing.ts +0 -11
- package/src/util/safe-rimraf.ts +0 -14
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
// eslint-disable-next-line
|
|
2
2
|
const awsIot = require('aws-iot-device-sdk');
|
|
3
|
+
import { getTargetHardwareUuid } from 'alwaysai/lib/core/app';
|
|
3
4
|
import {
|
|
5
|
+
DEVICE_CERTIFICATE_FILE_NAME,
|
|
6
|
+
DEVICE_CERTIFICATE_ID_FILE_NAME,
|
|
4
7
|
DEVICE_PRIVATE_KEY_FILE_NAME,
|
|
8
|
+
LOCAL_CERT_AND_KEY_DIR
|
|
9
|
+
} from 'alwaysai/lib/infrastructure';
|
|
10
|
+
import { JsSpawner } from 'alwaysai/lib/util';
|
|
11
|
+
import {
|
|
5
12
|
CERTIFICATE_OWNERSHIP_TOKEN_FILE_NAME,
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
} from '../util/directories';
|
|
13
|
+
getBootstrapCertificateDirectoryPath
|
|
14
|
+
} from '../infrastructure/device-certificate';
|
|
9
15
|
import { getDeviceUuid } from '../util/get-device-id';
|
|
10
|
-
import { JsSpawner } from 'alwaysai/lib/util';
|
|
11
16
|
import { logger } from '../util/logger';
|
|
12
|
-
|
|
13
|
-
import { LOCAL_CERT_AND_KEY_DIR } from 'alwaysai/lib/paths';
|
|
17
|
+
|
|
14
18
|
// eslint-disable-next-line
|
|
15
19
|
const process = require('process');
|
|
16
20
|
|
|
@@ -85,7 +89,10 @@ export class BootstrapAgent extends DeviceAgent {
|
|
|
85
89
|
|
|
86
90
|
await certSpawner.writeFile(DEVICE_PRIVATE_KEY_FILE_NAME, privateKey);
|
|
87
91
|
|
|
88
|
-
await certSpawner.writeFile(
|
|
92
|
+
await certSpawner.writeFile(
|
|
93
|
+
DEVICE_CERTIFICATE_ID_FILE_NAME,
|
|
94
|
+
certificateId
|
|
95
|
+
);
|
|
89
96
|
|
|
90
97
|
await certSpawner.writeFile(
|
|
91
98
|
CERTIFICATE_OWNERSHIP_TOKEN_FILE_NAME,
|
|
@@ -111,6 +118,8 @@ export class BootstrapAgent extends DeviceAgent {
|
|
|
111
118
|
}
|
|
112
119
|
case '$aws/provisioning-templates/FleetProvisionTemplate/provision/json/accepted': {
|
|
113
120
|
logger.info('Device agent provisioning: success');
|
|
121
|
+
const spawner = JsSpawner();
|
|
122
|
+
await spawner.rimraf(getBootstrapCertificateDirectoryPath());
|
|
114
123
|
process.exit();
|
|
115
124
|
}
|
|
116
125
|
}
|
|
@@ -1,89 +1,162 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_INTERVALS_MS,
|
|
3
|
+
LiveUpdatesHandler
|
|
4
|
+
} from './live-updates-handler';
|
|
5
|
+
import { keyMirrors } from '@alwaysai/device-agent-schemas';
|
|
6
|
+
import { randomUUID } from 'crypto';
|
|
7
|
+
import { PassThrough } from 'stream';
|
|
8
|
+
|
|
9
|
+
jest.mock('../util/sleep');
|
|
10
|
+
jest.mock('./messages');
|
|
11
|
+
jest.useFakeTimers();
|
|
5
12
|
|
|
6
13
|
// https://github.com/facebook/react-native/issues/35701
|
|
7
14
|
Object.defineProperty(global, 'performance', {
|
|
8
15
|
writable: true
|
|
9
16
|
});
|
|
10
17
|
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
appState: true
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
const testFalseToggles = {
|
|
17
|
-
deviceStats: false,
|
|
18
|
-
appState: false
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const mockClient = jest.fn();
|
|
22
|
-
const clientId = 'test-client';
|
|
23
|
-
const emptyTxId = '';
|
|
24
|
-
|
|
25
|
-
// NOTE: this was the way I found to mock private class functions
|
|
26
|
-
const mockStartPublishingLiveUpdates = jest.spyOn(
|
|
27
|
-
LiveUpdatesHandler.prototype as any,
|
|
28
|
-
'startPublishingLiveUpdates'
|
|
29
|
-
);
|
|
30
|
-
mockStartPublishingLiveUpdates.mockResolvedValue(null);
|
|
18
|
+
const mockTransactionId = '9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d';
|
|
19
|
+
const mockProjectId = '12345678-abcd-abcd-abcd-0123456789ab';
|
|
31
20
|
|
|
32
21
|
describe('Test Live Updates Handler', () => {
|
|
33
22
|
let liveUpdatesHandler: LiveUpdatesHandler;
|
|
34
|
-
let publisher: Publisher;
|
|
35
23
|
|
|
36
24
|
beforeEach(() => {
|
|
37
|
-
|
|
38
|
-
liveUpdatesHandler = new LiveUpdatesHandler(publisher, clientId);
|
|
25
|
+
liveUpdatesHandler = new LiveUpdatesHandler();
|
|
39
26
|
jest.clearAllMocks();
|
|
40
27
|
});
|
|
41
28
|
|
|
42
|
-
test('
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// restartLiveUpdatesTimeout is always called once when handleToggles is called
|
|
47
|
-
expect(jest.mocked(setTimeout)).toBeCalledTimes(1);
|
|
29
|
+
test('enable interval', async () => {
|
|
30
|
+
const mockPublishingFn = jest.fn();
|
|
31
|
+
const mockClearInterval = jest.spyOn(global, 'clearInterval');
|
|
32
|
+
const mockSetInterval = jest.spyOn(global, 'setInterval');
|
|
48
33
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
34
|
+
await liveUpdatesHandler.enable(
|
|
35
|
+
keyMirrors.toClientMessageType.device_stats,
|
|
36
|
+
mockPublishingFn
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
jest.advanceTimersByTime(DEFAULT_INTERVALS_MS);
|
|
40
|
+
|
|
41
|
+
expect(mockPublishingFn).toBeCalledTimes(2);
|
|
42
|
+
expect(mockClearInterval).toBeCalledWith(undefined);
|
|
43
|
+
expect(mockSetInterval).toBeCalledTimes(1);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('subsequent enable resets interval with no duplicates', async () => {
|
|
47
|
+
const mockPublishingFn = jest.fn();
|
|
48
|
+
const mockSetInterval = jest.spyOn(global, 'setInterval');
|
|
49
|
+
const mockClearInterval = jest.spyOn(global, 'clearInterval');
|
|
50
|
+
|
|
51
|
+
await liveUpdatesHandler.enable(
|
|
52
|
+
keyMirrors.toClientMessageType.device_stats,
|
|
53
|
+
mockPublishingFn,
|
|
54
|
+
mockTransactionId
|
|
55
|
+
);
|
|
56
|
+
await liveUpdatesHandler.enable(
|
|
57
|
+
keyMirrors.toClientMessageType.device_stats,
|
|
58
|
+
mockPublishingFn,
|
|
59
|
+
mockTransactionId
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
jest.advanceTimersByTime(DEFAULT_INTERVALS_MS);
|
|
63
|
+
|
|
64
|
+
expect(mockClearInterval.mock.calls[0][0]).toEqual(undefined);
|
|
65
|
+
expect(mockClearInterval.mock.calls[1][0]).toEqual(
|
|
66
|
+
mockSetInterval.mock.results[0].value
|
|
67
|
+
);
|
|
68
|
+
expect(mockSetInterval).toBeCalledTimes(2);
|
|
69
|
+
expect(mockPublishingFn).toBeCalledTimes(3);
|
|
54
70
|
});
|
|
55
71
|
|
|
56
72
|
test('test disable live updates', async () => {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
expect(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
const mockSetInterval = jest.spyOn(global, 'setInterval');
|
|
74
|
+
const mockClearInterval = jest.spyOn(global, 'clearInterval');
|
|
75
|
+
|
|
76
|
+
await liveUpdatesHandler.enable(
|
|
77
|
+
keyMirrors.toClientMessageType.device_stats,
|
|
78
|
+
async () => undefined,
|
|
79
|
+
mockTransactionId
|
|
80
|
+
);
|
|
81
|
+
liveUpdatesHandler.disable(
|
|
82
|
+
keyMirrors.toClientMessageType.device_stats,
|
|
83
|
+
mockTransactionId
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
expect(mockClearInterval).toHaveBeenLastCalledWith(
|
|
87
|
+
mockSetInterval.mock.results[0].value
|
|
88
|
+
);
|
|
73
89
|
});
|
|
74
90
|
|
|
75
|
-
test('timeout turns off live updates', async () => {
|
|
76
|
-
jest.
|
|
91
|
+
test('kill all timeout turns off all live updates', async () => {
|
|
92
|
+
const mockPublishingFn = jest.fn();
|
|
93
|
+
const mockSetInterval = jest.spyOn(global, 'setInterval');
|
|
94
|
+
const mockClearInterval = jest.spyOn(global, 'clearInterval');
|
|
95
|
+
jest.spyOn(global, 'setTimeout');
|
|
96
|
+
|
|
97
|
+
const numLivingIntervals = 5;
|
|
98
|
+
for (let i = 0; i < numLivingIntervals; i++) {
|
|
99
|
+
await liveUpdatesHandler.enable(
|
|
100
|
+
keyMirrors.toClientMessageType.status_response,
|
|
101
|
+
mockPublishingFn,
|
|
102
|
+
randomUUID()
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
mockSetInterval.mock.results.forEach((result) =>
|
|
107
|
+
clearInterval(result.value)
|
|
108
|
+
);
|
|
109
|
+
jest.runAllTimers();
|
|
77
110
|
|
|
78
|
-
|
|
79
|
-
expect(
|
|
80
|
-
|
|
81
|
-
|
|
111
|
+
expect(mockPublishingFn).toBeCalledTimes(numLivingIntervals);
|
|
112
|
+
expect(mockSetInterval).toBeCalledTimes(numLivingIntervals);
|
|
113
|
+
for (let i = 0; i < numLivingIntervals; i++) {
|
|
114
|
+
expect(mockClearInterval).toHaveBeenCalledWith(
|
|
115
|
+
mockSetInterval.mock.results[i].value
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
82
119
|
|
|
83
|
-
|
|
120
|
+
test('startStream streams data to publish', async () => {
|
|
121
|
+
const mockStream = new PassThrough();
|
|
122
|
+
const mockPublishingFn = jest
|
|
123
|
+
.fn()
|
|
124
|
+
.mockImplementation((logChunk: string) => undefined);
|
|
125
|
+
|
|
126
|
+
await liveUpdatesHandler.startStream(
|
|
127
|
+
mockProjectId,
|
|
128
|
+
async () => mockStream,
|
|
129
|
+
mockPublishingFn
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
const data = 'Data for stream';
|
|
133
|
+
mockStream.emit('data', data);
|
|
134
|
+
|
|
135
|
+
expect(mockPublishingFn).toBeCalledWith(data);
|
|
136
|
+
|
|
137
|
+
mockStream.end();
|
|
138
|
+
mockStream.destroy();
|
|
139
|
+
});
|
|
84
140
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
141
|
+
test('failure does not disable interval', async () => {
|
|
142
|
+
const mockPublishingFn = jest
|
|
143
|
+
.fn()
|
|
144
|
+
.mockImplementationOnce(() => undefined)
|
|
145
|
+
.mockImplementation(() => {
|
|
146
|
+
throw new Error('Manual throw for unit test');
|
|
147
|
+
});
|
|
148
|
+
jest.spyOn(global, 'setInterval');
|
|
149
|
+
const mockClearInterval = jest.spyOn(global, 'clearInterval');
|
|
150
|
+
|
|
151
|
+
await liveUpdatesHandler.enable(
|
|
152
|
+
keyMirrors.toClientMessageType.device_stats,
|
|
153
|
+
mockPublishingFn,
|
|
154
|
+
mockTransactionId
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
jest.advanceTimersByTime(DEFAULT_INTERVALS_MS);
|
|
158
|
+
|
|
159
|
+
expect(mockClearInterval).toBeCalledTimes(1);
|
|
160
|
+
expect(mockPublishingFn).toBeCalledTimes(2);
|
|
88
161
|
});
|
|
89
162
|
});
|
|
@@ -1,284 +1,153 @@
|
|
|
1
|
-
import {
|
|
2
|
-
AppLogsPayload,
|
|
3
|
-
keyMirrors,
|
|
4
|
-
LiveStateUpdatesTogglePayload,
|
|
5
|
-
ToClientMessage,
|
|
6
|
-
buildAppLogsMessage,
|
|
7
|
-
buildAppStateMessage,
|
|
8
|
-
buildDeviceStatsMessage,
|
|
9
|
-
StatusResponsePayload,
|
|
10
|
-
buildToClientStatusResponseMessage,
|
|
11
|
-
ToClientMessageTypeValue
|
|
12
|
-
} from '@alwaysai/device-agent-schemas';
|
|
13
|
-
import { getAppLogs } from '../application-control';
|
|
1
|
+
import { ToClientMessageTypeValue } from '@alwaysai/device-agent-schemas';
|
|
14
2
|
import { logger } from '../util/logger';
|
|
15
3
|
import sleep from '../util/sleep';
|
|
16
|
-
import { Publisher } from './publisher';
|
|
17
|
-
import { getAppStatePayload, getDeviceStatsPayload } from './messages';
|
|
18
4
|
import { ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS } from '../environment';
|
|
19
|
-
import {
|
|
5
|
+
import { stringifyError } from 'alwaysai/lib/util';
|
|
20
6
|
|
|
21
|
-
const
|
|
7
|
+
const KILL_ALL_TIMEOUT_MS = ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS
|
|
22
8
|
? parseInt(ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS)
|
|
23
|
-
:
|
|
9
|
+
: 80000;
|
|
10
|
+
|
|
11
|
+
export const DEFAULT_INTERVALS_MS = 5000;
|
|
12
|
+
|
|
13
|
+
interface IntervalOptions {
|
|
14
|
+
ms?: number;
|
|
15
|
+
}
|
|
24
16
|
|
|
25
17
|
export class LiveUpdatesHandler {
|
|
26
|
-
private
|
|
27
|
-
private
|
|
18
|
+
private killAllTimeout: ReturnType<typeof setTimeout>;
|
|
19
|
+
private livingIntervals: Record<string, ReturnType<typeof setInterval>> = {};
|
|
20
|
+
private livingStreams = new Set<string>();
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
[keyMirrors.toClientMessageType.status_response]: false
|
|
35
|
-
};
|
|
36
|
-
private liveUpdatesSleepIntervals = {
|
|
37
|
-
[keyMirrors.toClientMessageType.device_stats]: 5000,
|
|
38
|
-
[keyMirrors.toClientMessageType.app_state]: 5000,
|
|
39
|
-
[keyMirrors.toClientMessageType.app_logs]: 5000,
|
|
40
|
-
[keyMirrors.toClientMessageType.status_response]: 5000
|
|
41
|
-
};
|
|
22
|
+
constructor() {
|
|
23
|
+
logger.debug(
|
|
24
|
+
`Toggle live updates timeout set to ${KILL_ALL_TIMEOUT_MS} ms`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
42
27
|
|
|
43
|
-
|
|
44
|
-
|
|
28
|
+
public async enable(
|
|
29
|
+
intervalType: ToClientMessageTypeValue,
|
|
30
|
+
publishingFn: () => Promise<void>,
|
|
31
|
+
transactionId?: string,
|
|
32
|
+
options?: IntervalOptions
|
|
33
|
+
) {
|
|
34
|
+
this.restartKillAllTimeout();
|
|
45
35
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
36
|
+
const key = this.generateIntervalKey(intervalType, transactionId);
|
|
37
|
+
|
|
38
|
+
clearInterval(this.livingIntervals[key]);
|
|
39
|
+
|
|
40
|
+
// initial publish
|
|
41
|
+
await publishingFn();
|
|
42
|
+
|
|
43
|
+
this.livingIntervals[key] = setInterval(
|
|
44
|
+
async () => {
|
|
45
|
+
try {
|
|
46
|
+
await publishingFn();
|
|
47
|
+
} catch (e) {
|
|
48
|
+
logger.error(
|
|
49
|
+
`Error getting live updates: ${JSON.stringify(
|
|
50
|
+
e
|
|
51
|
+
)}: intervalKey: ${key}. Continuing...`
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
options?.ms ? options.ms : DEFAULT_INTERVALS_MS
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public disable(
|
|
60
|
+
intervalType: ToClientMessageTypeValue,
|
|
61
|
+
transactionId?: string
|
|
62
|
+
) {
|
|
63
|
+
const key = this.generateIntervalKey(intervalType, transactionId);
|
|
64
|
+
clearInterval(this.livingIntervals[key]);
|
|
65
|
+
delete this.livingIntervals[key];
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
public async startStream(
|
|
69
|
+
projectId: string,
|
|
70
|
+
streamGetter: () => Promise<NodeJS.ReadableStream | null>,
|
|
71
|
+
publishingFn: (logChunk: string) => void
|
|
72
|
+
) {
|
|
68
73
|
logger.info(`Starting log stream for ${projectId}`);
|
|
69
74
|
|
|
70
|
-
this.
|
|
75
|
+
this.livingStreams.add(projectId);
|
|
71
76
|
|
|
72
|
-
const readable = await this.
|
|
77
|
+
const readable = await this.getStreamWithRetry(projectId, streamGetter);
|
|
73
78
|
|
|
74
79
|
if (readable === null) {
|
|
75
80
|
logger.info(
|
|
76
|
-
`
|
|
81
|
+
`Stream terminated prior to starting. Readable stream is null. ProjectId: ${projectId}`
|
|
77
82
|
);
|
|
78
83
|
return;
|
|
79
84
|
}
|
|
80
85
|
|
|
81
86
|
readable.on('data', async (chunk: Buffer) => {
|
|
82
|
-
if (!this.
|
|
87
|
+
if (!this.livingStreams.has(projectId)) {
|
|
83
88
|
// why doesn't typescript know about this function?
|
|
84
89
|
// @ts-ignore
|
|
85
90
|
readable.destroy();
|
|
86
|
-
logger.info(`
|
|
91
|
+
logger.info(`Stream terminated. ProjectId: ${projectId}`);
|
|
87
92
|
return;
|
|
88
93
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
projectId,
|
|
92
|
-
logChunk: logStr
|
|
93
|
-
};
|
|
94
|
-
const message = buildAppLogsMessage(this.clientId, payload, txId);
|
|
95
|
-
this.publisher.publishToClient(message, logger.silly);
|
|
94
|
+
|
|
95
|
+
publishingFn(chunk.toString());
|
|
96
96
|
});
|
|
97
97
|
|
|
98
98
|
readable.on('error', (error) => {
|
|
99
|
-
logger.error(
|
|
100
|
-
`App log stream terminated for project ${projectId}: ${error}`
|
|
101
|
-
);
|
|
99
|
+
logger.error(`Stream terminated. ProjectId: ${projectId} - ${error}`);
|
|
102
100
|
});
|
|
103
101
|
|
|
104
102
|
readable.on('finished', () => {
|
|
105
|
-
logger.info(`
|
|
103
|
+
logger.info(`Strean complete. ProjectId: ${projectId}`);
|
|
106
104
|
});
|
|
107
105
|
}
|
|
108
106
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
txId?: string
|
|
112
|
-
): boolean {
|
|
113
|
-
switch (flag) {
|
|
114
|
-
case keyMirrors.toClientMessageType.device_stats:
|
|
115
|
-
case keyMirrors.toClientMessageType.app_state:
|
|
116
|
-
return this.liveUpdatesAlive[flag];
|
|
117
|
-
case keyMirrors.toClientMessageType.status_response: {
|
|
118
|
-
if (!txId) {
|
|
119
|
-
throw new Error(`Transaction ID not provided to continuePublishing!`);
|
|
120
|
-
}
|
|
121
|
-
return this.transactionStatuses.has(txId);
|
|
122
|
-
}
|
|
123
|
-
default:
|
|
124
|
-
logger.error(`Unrecognized publishable flag ${flag}`);
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
private getLiveUpdatesInterval(flag: ToClientMessageTypeValue): number {
|
|
130
|
-
const exists = this.liveUpdatesSleepIntervals[flag];
|
|
131
|
-
if (exists) {
|
|
132
|
-
return exists;
|
|
133
|
-
}
|
|
134
|
-
logger.error(`Unrecognized live updates flag ${flag}`);
|
|
135
|
-
return -1;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
private setLiveUpdates(toggles: LiveStateUpdatesTogglePayload) {
|
|
139
|
-
if (toggles.deviceStats !== undefined) {
|
|
140
|
-
this.liveUpdatesAlive.device_stats = toggles.deviceStats;
|
|
141
|
-
}
|
|
142
|
-
if (toggles.appState !== undefined) {
|
|
143
|
-
this.liveUpdatesAlive.app_state = toggles.appState;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
private restartLiveUpdatesTimeout() {
|
|
148
|
-
clearTimeout(this.liveUpdatesTimeout);
|
|
149
|
-
this.liveUpdatesTimeout = setTimeout(() => {
|
|
150
|
-
this.setLiveUpdates({
|
|
151
|
-
deviceStats: false,
|
|
152
|
-
appState: false
|
|
153
|
-
});
|
|
154
|
-
this.appLogStreams.clear();
|
|
155
|
-
}, LIVE_UPDATES_TIMEOUT);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
private async startPublishingLiveUpdates(
|
|
159
|
-
messageType: ToClientMessageTypeValue,
|
|
160
|
-
getMessage: () => Promise<ToClientMessage>,
|
|
161
|
-
txId: string
|
|
162
|
-
) {
|
|
163
|
-
logger.info(`Turned on live updates for ${messageType}`);
|
|
164
|
-
try {
|
|
165
|
-
while (this.continuePublishing(messageType, txId)) {
|
|
166
|
-
const message = await getMessage();
|
|
167
|
-
this.publisher.publishToClient(message, logger.silly);
|
|
168
|
-
|
|
169
|
-
await sleep(this.getLiveUpdatesInterval(messageType));
|
|
170
|
-
}
|
|
171
|
-
} catch (e) {
|
|
172
|
-
logger.error(
|
|
173
|
-
`Error publishing live updates for ${messageType}: ${e.message}`
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
logger.info(`Turned off live updates for ${messageType}`);
|
|
107
|
+
public stopStream(streamId: string) {
|
|
108
|
+
this.livingStreams.delete(streamId);
|
|
177
109
|
}
|
|
178
110
|
|
|
179
111
|
/*=================================================================
|
|
180
|
-
|
|
112
|
+
Private interface
|
|
181
113
|
=================================================================*/
|
|
182
114
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
public getAppLogsLiveUpdates() {
|
|
200
|
-
return this.liveUpdatesAlive.app_logs;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
public async enableTransactionStatus(props: { txId: string }) {
|
|
204
|
-
const { txId } = props;
|
|
205
|
-
this.liveUpdatesAlive.status_response = true;
|
|
206
|
-
if (!this.transactionStatuses.has(txId)) {
|
|
207
|
-
this.transactionStatuses.add(txId);
|
|
208
|
-
// Don't wait for this call to finish since it loops until disabled
|
|
209
|
-
void this.startPublishingLiveUpdates(
|
|
210
|
-
keyMirrors.toClientMessageType.status_response,
|
|
211
|
-
async () => {
|
|
212
|
-
const payload: StatusResponsePayload = {
|
|
213
|
-
status: keyMirrors.statusResponse.in_progress
|
|
214
|
-
};
|
|
215
|
-
return buildToClientStatusResponseMessage(
|
|
216
|
-
this.clientId,
|
|
217
|
-
payload,
|
|
218
|
-
txId
|
|
219
|
-
);
|
|
220
|
-
},
|
|
221
|
-
txId
|
|
222
|
-
);
|
|
115
|
+
private async getStreamWithRetry(
|
|
116
|
+
streamId: string,
|
|
117
|
+
streamGetter: () => Promise<NodeJS.ReadableStream | null>
|
|
118
|
+
): Promise<NodeJS.ReadableStream | null> {
|
|
119
|
+
// Retry starting logs until it starts successfully or is terminated
|
|
120
|
+
while (this.livingStreams.has(streamId)) {
|
|
121
|
+
try {
|
|
122
|
+
return await streamGetter();
|
|
123
|
+
} catch (e) {
|
|
124
|
+
logger.info(
|
|
125
|
+
`Failed to start app logs, retrying in 1 second.\n${stringifyError(
|
|
126
|
+
e
|
|
127
|
+
)}`
|
|
128
|
+
);
|
|
129
|
+
await sleep(1000);
|
|
130
|
+
}
|
|
223
131
|
}
|
|
132
|
+
// Case where logs were disabled prior to connecting
|
|
133
|
+
return null;
|
|
224
134
|
}
|
|
225
135
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
this.
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
136
|
+
private restartKillAllTimeout() {
|
|
137
|
+
clearTimeout(this.killAllTimeout);
|
|
138
|
+
this.killAllTimeout = setTimeout(() => {
|
|
139
|
+
Object.values(this.livingIntervals).forEach((interval) =>
|
|
140
|
+
clearInterval(interval)
|
|
141
|
+
);
|
|
142
|
+
this.livingIntervals = {};
|
|
143
|
+
this.livingStreams.clear();
|
|
144
|
+
}, KILL_ALL_TIMEOUT_MS);
|
|
233
145
|
}
|
|
234
146
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
147
|
+
private generateIntervalKey(
|
|
148
|
+
intervalType: ToClientMessageTypeValue,
|
|
149
|
+
transactionId?: string
|
|
238
150
|
) {
|
|
239
|
-
|
|
240
|
-
this.restartLiveUpdatesTimeout();
|
|
241
|
-
|
|
242
|
-
if (deviceStats !== undefined) {
|
|
243
|
-
const currentDeviceStats = this.getDeviceStatsLiveUpdates();
|
|
244
|
-
this.liveUpdatesAlive.device_stats = deviceStats;
|
|
245
|
-
if (deviceStats && currentDeviceStats !== true) {
|
|
246
|
-
// Don't wait for this call to finish since it loops until disabled
|
|
247
|
-
void this.startPublishingLiveUpdates(
|
|
248
|
-
keyMirrors.toClientMessageType.device_stats,
|
|
249
|
-
async () => {
|
|
250
|
-
const payload = await getDeviceStatsPayload();
|
|
251
|
-
return buildDeviceStatsMessage(this.clientId, payload, txId);
|
|
252
|
-
},
|
|
253
|
-
txId
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
if (appState !== undefined) {
|
|
259
|
-
const currentAppState = this.getAppStateLiveUpdates();
|
|
260
|
-
this.liveUpdatesAlive.app_state = appState;
|
|
261
|
-
if (appState && currentAppState !== true) {
|
|
262
|
-
// Don't wait for this call to finish since it loops until disabled
|
|
263
|
-
void this.startPublishingLiveUpdates(
|
|
264
|
-
keyMirrors.toClientMessageType.app_state,
|
|
265
|
-
async () => {
|
|
266
|
-
const payload = await getAppStatePayload();
|
|
267
|
-
return buildAppStateMessage(this.clientId, payload, txId);
|
|
268
|
-
},
|
|
269
|
-
txId
|
|
270
|
-
);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
if (appLogs !== undefined) {
|
|
275
|
-
const currentAppLogs = this.getAppLogsLiveUpdates();
|
|
276
|
-
if (appLogs.toggle && currentAppLogs !== true) {
|
|
277
|
-
// Don't wait for this call to finish since it loops until disabled
|
|
278
|
-
void this.startAppLogStream(appLogs.projectId, txId);
|
|
279
|
-
} else {
|
|
280
|
-
this.appLogStreams.delete(appLogs.projectId);
|
|
281
|
-
}
|
|
282
|
-
}
|
|
151
|
+
return intervalType + `${transactionId ? ':' + transactionId : ''}`;
|
|
283
152
|
}
|
|
284
153
|
}
|