@alwaysai/device-agent 1.5.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 +8 -3
- 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 +8 -7
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/models.d.ts +0 -11
- package/lib/application-control/models.d.ts.map +1 -1
- package/lib/application-control/models.js +5 -54
- package/lib/application-control/models.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 +1 -24
- 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 +10 -15
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +279 -250
- 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 -28
- package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
- package/lib/cloud-connection/live-updates-handler.js +54 -169
- package/lib/cloud-connection/live-updates-handler.js.map +1 -1
- package/lib/cloud-connection/live-updates-handler.test.js +71 -165
- package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
- package/lib/cloud-connection/passthrough-handler.d.ts +4 -1
- package/lib/cloud-connection/passthrough-handler.d.ts.map +1 -1
- package/lib/cloud-connection/passthrough-handler.js +30 -11
- package/lib/cloud-connection/passthrough-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.d.ts +5 -3
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
- package/lib/cloud-connection/shadow-handler.js +59 -27
- 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 +4 -2
- package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
- package/lib/cloud-connection/transaction-manager.js +18 -29
- package/lib/cloud-connection/transaction-manager.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.test.js +3 -3
- package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
- package/lib/device-control/device-control.d.ts +8 -8
- package/lib/device-control/device-control.d.ts.map +1 -1
- package/lib/device-control/device-control.js +95 -71
- package/lib/device-control/device-control.js.map +1 -1
- package/lib/docker/docker-compose.d.ts.map +1 -1
- package/lib/docker/docker-compose.js +2 -1
- package/lib/docker/docker-compose.js.map +1 -1
- package/lib/infrastructure/agent-config.d.ts +2 -1
- package/lib/infrastructure/agent-config.d.ts.map +1 -1
- package/lib/infrastructure/agent-config.js +7 -7
- package/lib/infrastructure/agent-config.js.map +1 -1
- package/lib/infrastructure/agent-config.test.js +3 -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 +14 -14
- package/lib/local-connection/rabbitmq-connection.js.map +1 -1
- package/lib/secure-tunneling/secure-tunneling.d.ts +9 -9
- package/lib/secure-tunneling/secure-tunneling.d.ts.map +1 -1
- package/lib/secure-tunneling/secure-tunneling.js +21 -16
- package/lib/secure-tunneling/secure-tunneling.js.map +1 -1
- package/lib/secure-tunneling/secure-tunneling.test.js +11 -13
- 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 +23 -13
- package/lib/subcommands/device/clean.js.map +1 -1
- package/lib/subcommands/device/index.d.ts.map +1 -1
- package/lib/subcommands/device/index.js +3 -1
- package/lib/subcommands/device/index.js.map +1 -1
- package/lib/subcommands/device/init.js +8 -8
- package/lib/subcommands/device/init.js.map +1 -1
- 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.map +1 -1
- package/lib/subcommands/device/refresh.js +1 -0
- package/lib/subcommands/device/refresh.js.map +1 -1
- 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.map +1 -1
- package/lib/util/check-for-updates.js +5 -28
- package/lib/util/check-for-updates.js.map +1 -1
- 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 +4 -0
- package/lib/util/file.d.ts.map +1 -1
- package/lib/util/file.js +65 -4
- package/lib/util/file.js.map +1 -1
- 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 +19 -17
- package/readme.md +12 -32
- package/src/application-control/config.ts +9 -12
- 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 +15 -10
- package/src/application-control/models.ts +6 -87
- package/src/application-control/utils.ts +0 -28
- package/src/cloud-connection/bootstrap-provision.ts +7 -7
- package/src/cloud-connection/device-agent-cloud-connection.ts +639 -525
- package/src/cloud-connection/device-agent.ts +16 -7
- package/src/cloud-connection/live-updates-handler.test.ts +121 -189
- package/src/cloud-connection/live-updates-handler.ts +99 -234
- package/src/cloud-connection/passthrough-handler.ts +55 -18
- package/src/cloud-connection/shadow-handler.test.ts +45 -57
- package/src/cloud-connection/shadow-handler.ts +103 -57
- package/src/cloud-connection/shadow.ts +4 -1
- package/src/cloud-connection/transaction-manager.test.ts +3 -3
- package/src/cloud-connection/transaction-manager.ts +53 -39
- package/src/device-control/device-control.ts +102 -70
- package/src/docker/docker-compose.ts +3 -2
- package/src/infrastructure/agent-config.test.ts +6 -2
- package/src/infrastructure/agent-config.ts +8 -7
- 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 +22 -17
- package/src/secure-tunneling/secure-tunneling.test.ts +20 -22
- package/src/secure-tunneling/secure-tunneling.ts +41 -29
- 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 +31 -17
- package/src/subcommands/device/index.ts +3 -1
- package/src/subcommands/device/init.ts +11 -11
- package/src/subcommands/device/migrate.ts +20 -0
- package/src/subcommands/device/refresh.ts +1 -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 +14 -30
- package/src/util/clean-certs.ts +8 -4
- package/src/util/directories.ts +23 -67
- package/src/util/file.ts +83 -3
- package/src/util/get-device-id.ts +7 -7
- package/src/util/http-client.ts +2 -2
- 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/src/util/download-file.ts +0 -25
- package/src/util/fetch-with-timeout.ts +0 -35
- package/src/util/parsing.ts +0 -11
|
@@ -4,34 +4,37 @@ exports.runDeviceAgentCloudInterface = exports.DeviceAgentCloudConnection = void
|
|
|
4
4
|
// eslint-disable-next-line
|
|
5
5
|
const awsIot = require('aws-iot-device-sdk');
|
|
6
6
|
const device_agent_schemas_1 = require("@alwaysai/device-agent-schemas");
|
|
7
|
+
const infrastructure_1 = require("alwaysai/lib/infrastructure");
|
|
8
|
+
const util_1 = require("alwaysai/lib/util");
|
|
9
|
+
const child_process_1 = require("child_process");
|
|
7
10
|
const fs_1 = require("fs");
|
|
11
|
+
const util_2 = require("util");
|
|
8
12
|
const application_control_1 = require("../application-control");
|
|
9
13
|
const backup_1 = require("../application-control/backup");
|
|
14
|
+
const models_1 = require("../application-control/models");
|
|
10
15
|
const device_control_1 = require("../device-control/device-control");
|
|
11
16
|
const environment_1 = require("../environment");
|
|
12
17
|
const agent_config_1 = require("../infrastructure/agent-config");
|
|
18
|
+
const device_certificate_1 = require("../infrastructure/device-certificate");
|
|
19
|
+
const legacy_migration_1 = require("../infrastructure/legacy-migration/legacy-migration");
|
|
20
|
+
const required_config_checks_1 = require("../infrastructure/required-config-checks");
|
|
13
21
|
const urls_1 = require("../infrastructure/urls");
|
|
14
22
|
const secure_tunneling_1 = require("../secure-tunneling/secure-tunneling");
|
|
15
|
-
const
|
|
23
|
+
const aai_error_1 = require("../util/aai-error");
|
|
24
|
+
const check_for_updates_1 = require("../util/check-for-updates");
|
|
16
25
|
const directories_1 = require("../util/directories");
|
|
17
26
|
const get_device_id_1 = require("../util/get-device-id");
|
|
18
27
|
const logger_1 = require("../util/logger");
|
|
19
28
|
const sleep_1 = require("../util/sleep");
|
|
20
29
|
const bootstrap_provision_1 = require("./bootstrap-provision");
|
|
21
30
|
const live_updates_handler_1 = require("./live-updates-handler");
|
|
31
|
+
const messages_1 = require("./messages");
|
|
22
32
|
const passthrough_handler_1 = require("./passthrough-handler");
|
|
23
33
|
const publisher_1 = require("./publisher");
|
|
24
34
|
const shadow_handler_1 = require("./shadow-handler");
|
|
25
35
|
const transaction_manager_1 = require("./transaction-manager");
|
|
26
|
-
const
|
|
27
|
-
const util_1 = require("util");
|
|
28
|
-
const models_1 = require("../application-control/models");
|
|
29
|
-
const check_for_updates_1 = require("../util/check-for-updates");
|
|
30
|
-
const exec_promise = (0, util_1.promisify)(child_process_1.exec);
|
|
36
|
+
const exec_promise = (0, util_2.promisify)(child_process_1.exec);
|
|
31
37
|
class DeviceAgentCloudConnection {
|
|
32
|
-
/*=================================================================
|
|
33
|
-
Public interface
|
|
34
|
-
=================================================================*/
|
|
35
38
|
constructor() {
|
|
36
39
|
this.device = awsIot.device;
|
|
37
40
|
this.clientId = (0, get_device_id_1.getDeviceUuid)();
|
|
@@ -152,17 +155,17 @@ class DeviceAgentCloudConnection {
|
|
|
152
155
|
return true;
|
|
153
156
|
};
|
|
154
157
|
this.device = awsIot.device({
|
|
155
|
-
keyPath:
|
|
156
|
-
certPath:
|
|
158
|
+
keyPath: infrastructure_1.DEVICE_PRIVATE_KEY_FILE_PATH,
|
|
159
|
+
certPath: infrastructure_1.DEVICE_CERTIFICATE_FILE_PATH,
|
|
157
160
|
caPath: directories_1.AWS_ROOT_CERTIFICATE_FILE_PATH,
|
|
158
161
|
clientId: this.clientId,
|
|
159
162
|
host: this.host,
|
|
160
163
|
port: this.port,
|
|
161
|
-
keepalive:
|
|
164
|
+
keepalive: 10 // time before re-connect attempt on dropped connection, default is 400 seconds
|
|
162
165
|
});
|
|
163
166
|
this.publisher = new publisher_1.Publisher(this.device, this.clientId);
|
|
164
167
|
this.shadowHandler = new shadow_handler_1.ShadowHandler(this.clientId, this.publisher);
|
|
165
|
-
this.liveUpdatesHandler = new live_updates_handler_1.LiveUpdatesHandler(
|
|
168
|
+
this.liveUpdatesHandler = new live_updates_handler_1.LiveUpdatesHandler();
|
|
166
169
|
this.txnMgr = new transaction_manager_1.TransactionManager(this.publisher, this.liveUpdatesHandler);
|
|
167
170
|
this.subscribe(this.toDeviceTopic);
|
|
168
171
|
this.subscribe(this.secureTunnelNotifyTopic);
|
|
@@ -171,127 +174,133 @@ class DeviceAgentCloudConnection {
|
|
|
171
174
|
}
|
|
172
175
|
this.subscribe(this.shadowHandler.shadowTopics.secureTunnel.updateDelta);
|
|
173
176
|
this.subscribe(this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted);
|
|
177
|
+
this.setupHandlers();
|
|
174
178
|
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
default: {
|
|
183
|
-
logger_1.logger.info(`Unrecognized device action requested: '${payload.action}'.`);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
async publishCloudRequest(message) {
|
|
188
|
-
this.publisher.publishToCloud(message);
|
|
179
|
+
/*=================================================================
|
|
180
|
+
Public interface
|
|
181
|
+
=================================================================*/
|
|
182
|
+
getClientId() {
|
|
183
|
+
return this.clientId;
|
|
189
184
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
this.device.subscribe(topic);
|
|
185
|
+
isCmdInProgress(projectId) {
|
|
186
|
+
return this.txnMgr.isOngoingTransactionForProjectID(projectId);
|
|
193
187
|
}
|
|
194
|
-
async
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
188
|
+
async handleMessage(topic, message) {
|
|
189
|
+
logger_1.logger.debug(`Received message: ${JSON.stringify({ topic, message }, null, 2)}`);
|
|
190
|
+
// ProjectShadow messages
|
|
191
|
+
if (this.shadowHandler.projectShadowTopics.includes(topic)) {
|
|
192
|
+
await this.handleProjectShadowMessage(topic, message);
|
|
198
193
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
194
|
+
else if (topic === this.toDeviceTopic) {
|
|
195
|
+
await this.handleDeviceAgentMessage({
|
|
196
|
+
topic,
|
|
197
|
+
message
|
|
198
|
+
});
|
|
199
|
+
// SecureTunnelNotify messages
|
|
200
|
+
}
|
|
201
|
+
else if (topic === this.secureTunnelNotifyTopic) {
|
|
202
|
+
await this.secureTunnelHandler.secureTunnelNotifyHandler(message);
|
|
203
|
+
// SecureTunnel messages
|
|
204
|
+
}
|
|
205
|
+
else if (topic === this.shadowHandler.shadowTopics.secureTunnel.updateDelta) {
|
|
206
|
+
await this.handleSecureTunnelMessage(message);
|
|
207
|
+
}
|
|
208
|
+
else if (topic === this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted) {
|
|
209
|
+
logger_1.logger.info(`Received secure tunnel deleteAccepted: ${message}`);
|
|
210
|
+
await this.secureTunnelHandler.destroy();
|
|
211
|
+
}
|
|
212
|
+
else {
|
|
213
|
+
logger_1.logger.error(`Unexpected topic, ignoring! ${topic}`);
|
|
202
214
|
}
|
|
203
215
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
//
|
|
207
|
-
|
|
216
|
+
async stop() {
|
|
217
|
+
// This method is currently only used by the CLI, and shadow messages can be
|
|
218
|
+
// lost since we aren't waiting for responses so sleep for a short time to
|
|
219
|
+
// receive them
|
|
220
|
+
await (0, sleep_1.default)(1000);
|
|
221
|
+
this.device.end();
|
|
222
|
+
}
|
|
223
|
+
/*=================================================================
|
|
224
|
+
Private interface
|
|
225
|
+
=================================================================*/
|
|
226
|
+
setupHandlers() {
|
|
227
|
+
this.device.on('connect', (connack) => {
|
|
228
|
+
logger_1.logger.info('Device Agent has connected to the cloud');
|
|
229
|
+
// FIXME: EI-709 Skip this request for now to prevent kicking off another
|
|
230
|
+
// shadow update process if IoT Core disconnect occurs during app config update
|
|
231
|
+
//this.shadowHandler.getShadowUpdates();
|
|
232
|
+
void this.shadowHandler.updateSystemInfoShadow();
|
|
233
|
+
});
|
|
234
|
+
this.device.on('disconnect', () => {
|
|
235
|
+
logger_1.logger.warn('Device Agent has been disconnected from the cloud');
|
|
236
|
+
});
|
|
237
|
+
this.device.on('reconnect', () => {
|
|
238
|
+
logger_1.logger.info(`Device Agent attempting to re-connect ${new Date().toLocaleString()}`);
|
|
239
|
+
});
|
|
240
|
+
this.device.on('error', function (e) {
|
|
241
|
+
logger_1.logger.error(`Error connecting to cloud!\n${(0, util_1.stringifyError)(e)}`);
|
|
242
|
+
});
|
|
243
|
+
this.device.on('message', async (topic, payload) => {
|
|
208
244
|
try {
|
|
209
|
-
|
|
245
|
+
const jsonPacket = JSON.parse(payload);
|
|
246
|
+
await this.handleMessage(topic, jsonPacket);
|
|
210
247
|
}
|
|
211
248
|
catch (e) {
|
|
212
|
-
logger_1.logger.error(`
|
|
249
|
+
logger_1.logger.error(`Error parsing message!\n${(0, util_1.stringifyError)(e)}`);
|
|
213
250
|
}
|
|
214
|
-
}
|
|
251
|
+
});
|
|
252
|
+
this.device.on('offline', () => {
|
|
253
|
+
logger_1.logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
|
|
254
|
+
void this.logConnectionInfo();
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
async logConnectionInfo() {
|
|
215
258
|
try {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
259
|
+
/**
|
|
260
|
+
* We're using the 'netcat' or 'nc' command to test the connection to the IoT Core endpoint.
|
|
261
|
+
* This command doesn't always exit (see below), so
|
|
262
|
+
* we use timeout to break out of the prompt
|
|
263
|
+
* and catch the resulting error/parse the resulting stderr
|
|
264
|
+
*
|
|
265
|
+
* Sample command for current host and port:
|
|
266
|
+
* nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
|
|
267
|
+
*
|
|
268
|
+
* Sample output when port is not blocked and host is reachable:
|
|
269
|
+
* $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443
|
|
270
|
+
* Connection to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443 port [tcp/https] succeeded!
|
|
271
|
+
*
|
|
272
|
+
*
|
|
273
|
+
* Sample output when port is blocked (will repeatedly try until ctrl-C out):
|
|
274
|
+
* $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
|
|
275
|
+
* nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
|
|
276
|
+
* nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
|
|
277
|
+
* nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
|
|
278
|
+
* ^C
|
|
279
|
+
*
|
|
280
|
+
*
|
|
281
|
+
* Sample command/output when the port isn't enable on that host:
|
|
282
|
+
* $ nc -zv -w 1 localhost 8883
|
|
283
|
+
* nc: connect to localhost port 8883 (tcp) failed: Connection refused
|
|
284
|
+
*/
|
|
285
|
+
await exec_promise(`nc -zv -w 1 ${this.host} ${this.port}`, {
|
|
286
|
+
timeout: 2000
|
|
287
|
+
});
|
|
220
288
|
}
|
|
221
|
-
catch (
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
await (0, backup_1.rollbackApp)({ projectId });
|
|
226
|
-
logger_1.logger.error(`Application update failed, rolled back to previous version: ${errorAppUpdate}`);
|
|
289
|
+
catch (err) {
|
|
290
|
+
const output = JSON.stringify(err['stderr']);
|
|
291
|
+
if (output.indexOf('not known') !== -1) {
|
|
292
|
+
logger_1.logger.warn('Iot Core endpoint appears to be unreachable, internet connection may be unstable or the host may be down.');
|
|
227
293
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
try {
|
|
231
|
-
await this.atomicApplicationUninstall(projectId);
|
|
232
|
-
}
|
|
233
|
-
catch (_a) {
|
|
234
|
-
// atomicApplicationUninstall handles failing, so there's nothing to handle here.
|
|
235
|
-
}
|
|
236
|
-
logger_1.logger.error(`Application update failed, rolled back to previous version: ${errorAppUpdate}`);
|
|
237
|
-
throw new Error(`Application update and rollback failed, uninstalled the application: ${errorAppUpdate}`);
|
|
294
|
+
else if (output.indexOf('timed out') !== -1) {
|
|
295
|
+
logger_1.logger.warn(`Internet connection appears fine, however the endpoint was not reachable on the current connection port: ${this.port}\nPlease check if a firewall is in place.`);
|
|
238
296
|
}
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
topic,
|
|
245
|
-
payload: message,
|
|
246
|
-
clientToken: message.clientToken
|
|
247
|
-
});
|
|
248
|
-
if (shadowUpdates.length) {
|
|
249
|
-
const shadowUpdatePromises = [];
|
|
250
|
-
for (const shadowUpdate of shadowUpdates) {
|
|
251
|
-
const projectId = shadowUpdate.projectId;
|
|
252
|
-
const txId = shadowUpdate.txId;
|
|
253
|
-
shadowUpdatePromises.push(this.txnMgr
|
|
254
|
-
.runTransactionStep({
|
|
255
|
-
func: () => this.handleProjectShadowConfigUpdate(shadowUpdate, txId),
|
|
256
|
-
projectId,
|
|
257
|
-
txId,
|
|
258
|
-
start: true,
|
|
259
|
-
stepName: topic
|
|
260
|
-
})
|
|
261
|
-
.catch((e) => {
|
|
262
|
-
logger_1.logger.error(`There was an issue updating project shadow config: ${JSON.stringify(e)}`);
|
|
263
|
-
}));
|
|
297
|
+
else if (output.indexOf('refused') !== -1) {
|
|
298
|
+
logger_1.logger.warn(`The connection was refused, likely ${this.host} is not running a service on ${this.port}.`);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
logger_1.logger.warn(`Output from checking connection to ${this.host} on ${this.port}: ${output}`);
|
|
264
302
|
}
|
|
265
|
-
await Promise.all(shadowUpdatePromises);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
async handleSecureTunnelMessage(payload) {
|
|
269
|
-
logger_1.logger.info(`Received secure tunnel update: ${JSON.stringify(payload)}`);
|
|
270
|
-
const state = payload.state;
|
|
271
|
-
if (!state) {
|
|
272
|
-
logger_1.logger.debug(`No state found in message: ${JSON.stringify(payload)}`);
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
const valid = (0, device_agent_schemas_1.validateSecureTunnelShadowUpdate)(state);
|
|
276
|
-
if (!valid) {
|
|
277
|
-
logger_1.logger.error(`Error validating message: ${JSON.stringify({ payload, errors: device_agent_schemas_1.validateSecureTunnelShadowUpdate.errors }, null, 2)}`);
|
|
278
|
-
return;
|
|
279
303
|
}
|
|
280
|
-
const secureTunnelUpdate = await this.secureTunnelHandler.syncShadowToDeviceState(payload);
|
|
281
|
-
await this.shadowHandler.updateSecureTunnelShadow(secureTunnelUpdate);
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
getClientId() {
|
|
285
|
-
return this.clientId;
|
|
286
|
-
}
|
|
287
|
-
getToDeviceTopic() {
|
|
288
|
-
return this.toDeviceTopic;
|
|
289
|
-
}
|
|
290
|
-
isCmdInProgress(projectId) {
|
|
291
|
-
return this.txnMgr.isOngoingTransactionForProjectID(projectId);
|
|
292
|
-
}
|
|
293
|
-
async updateProjectShadow(projectId) {
|
|
294
|
-
await this.shadowHandler.updateProjectShadow(projectId);
|
|
295
304
|
}
|
|
296
305
|
async handleDeviceAgentMessage({ topic, message }) {
|
|
297
306
|
const valid = (0, device_agent_schemas_1.validateToDeviceAgentMessage)(message);
|
|
@@ -313,11 +322,12 @@ class DeviceAgentCloudConnection {
|
|
|
313
322
|
projectId,
|
|
314
323
|
txId,
|
|
315
324
|
start: true,
|
|
325
|
+
liveUpdatesPublishFn: async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, { status: device_agent_schemas_1.keyMirrors.statusResponse.in_progress }, txId), logger_1.logger.silly),
|
|
316
326
|
stepName: payload.baseCommand
|
|
317
327
|
});
|
|
318
328
|
}
|
|
319
329
|
catch (e) {
|
|
320
|
-
logger_1.logger.error(`Error processing application state control request
|
|
330
|
+
logger_1.logger.error(`Error processing application state control request for ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
|
|
321
331
|
}
|
|
322
332
|
break;
|
|
323
333
|
}
|
|
@@ -331,18 +341,47 @@ class DeviceAgentCloudConnection {
|
|
|
331
341
|
projectId,
|
|
332
342
|
txId,
|
|
333
343
|
start: true,
|
|
344
|
+
liveUpdatesPublishFn: async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, { status: device_agent_schemas_1.keyMirrors.statusResponse.in_progress }, txId), logger_1.logger.silly),
|
|
334
345
|
stepName: payload.baseCommand
|
|
335
346
|
});
|
|
336
347
|
}
|
|
337
348
|
catch (e) {
|
|
338
|
-
logger_1.logger.error(`Error processing application install request
|
|
349
|
+
logger_1.logger.error(`Error processing application install request for ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
|
|
339
350
|
}
|
|
340
351
|
break;
|
|
341
352
|
}
|
|
342
353
|
case live_state_updates: {
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
354
|
+
const { deviceStats, appState, appLogs } = message.payload;
|
|
355
|
+
if (deviceStats !== undefined) {
|
|
356
|
+
if (deviceStats) {
|
|
357
|
+
await this.liveUpdatesHandler.enable(device_agent_schemas_1.keyMirrors.toClientMessageType.device_stats, async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildDeviceStatsMessage)(this.clientId, await (0, messages_1.getDeviceStatsPayload)(), txId), logger_1.logger.silly));
|
|
358
|
+
}
|
|
359
|
+
else {
|
|
360
|
+
this.liveUpdatesHandler.disable(device_agent_schemas_1.keyMirrors.toClientMessageType.device_stats);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
if (appState !== undefined) {
|
|
364
|
+
if (appState) {
|
|
365
|
+
await this.liveUpdatesHandler.enable(device_agent_schemas_1.keyMirrors.toClientMessageType.app_state, async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildAppStateMessage)(this.clientId, await (0, messages_1.getAppStatePayload)(), txId), logger_1.logger.silly));
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
this.liveUpdatesHandler.disable(device_agent_schemas_1.keyMirrors.toClientMessageType.app_state);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
if (appLogs !== undefined) {
|
|
372
|
+
if (appLogs.toggle) {
|
|
373
|
+
await this.liveUpdatesHandler.startStream(appLogs.projectId, async () => await (0, application_control_1.getAppLogs)({
|
|
374
|
+
projectId: appLogs.projectId,
|
|
375
|
+
args: ['--tail', '100', '--no-log-prefix']
|
|
376
|
+
}), async (logChunk) => this.publisher.publishToClient((0, device_agent_schemas_1.buildAppLogsMessage)(this.clientId, {
|
|
377
|
+
projectId: appLogs.projectId,
|
|
378
|
+
logChunk
|
|
379
|
+
}, txId), logger_1.logger.silly));
|
|
380
|
+
}
|
|
381
|
+
else {
|
|
382
|
+
this.liveUpdatesHandler.stopStream(appLogs.projectId);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
346
385
|
break;
|
|
347
386
|
}
|
|
348
387
|
case app_install_response: {
|
|
@@ -380,39 +419,29 @@ class DeviceAgentCloudConnection {
|
|
|
380
419
|
case status_response: {
|
|
381
420
|
const { failure } = device_agent_schemas_1.keyMirrors.statusResponse;
|
|
382
421
|
if (message.payload.status === failure) {
|
|
383
|
-
this.txnMgr.completeTransaction(txId)
|
|
384
|
-
const failureStatusResponsePayload = {
|
|
422
|
+
this.txnMgr.completeTransaction(txId, (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, {
|
|
385
423
|
status: device_agent_schemas_1.keyMirrors.statusResponse.failure,
|
|
386
424
|
message: message.payload.message
|
|
387
|
-
};
|
|
388
|
-
// Send final status message
|
|
389
|
-
const failureStatusResponseMessage = (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, failureStatusResponsePayload, txId);
|
|
390
|
-
this.publisher.publishToClient(failureStatusResponseMessage);
|
|
425
|
+
}, txId));
|
|
391
426
|
}
|
|
392
427
|
break;
|
|
393
428
|
}
|
|
394
429
|
case device_action: {
|
|
395
430
|
try {
|
|
396
|
-
|
|
431
|
+
this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, {
|
|
397
432
|
status: device_agent_schemas_1.keyMirrors.statusResponse.in_progress
|
|
398
|
-
};
|
|
399
|
-
const statusResponseMessage = (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, statusResponsePayload, txId);
|
|
400
|
-
this.publisher.publishToClient(statusResponseMessage);
|
|
433
|
+
}, txId));
|
|
401
434
|
await this.handleDeviceAction(message.payload);
|
|
402
|
-
|
|
435
|
+
this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, {
|
|
403
436
|
status: device_agent_schemas_1.keyMirrors.statusResponse.success
|
|
404
|
-
};
|
|
405
|
-
const successStatusResponseMessage = (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, successStatusResponsePayload, txId);
|
|
406
|
-
this.publisher.publishToClient(successStatusResponseMessage);
|
|
437
|
+
}, txId));
|
|
407
438
|
}
|
|
408
439
|
catch (e) {
|
|
409
|
-
logger_1.logger.error(`There was a problem performing device action '${message.payload.action}'
|
|
410
|
-
|
|
440
|
+
logger_1.logger.error(`There was a problem performing device action '${message.payload.action}'!\n${(0, util_1.stringifyError)(e)}`);
|
|
441
|
+
this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, {
|
|
411
442
|
status: device_agent_schemas_1.keyMirrors.statusResponse.failure,
|
|
412
443
|
message: e.message
|
|
413
|
-
};
|
|
414
|
-
const failureStatusResponseMessage = (0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, failureStatusResponsePayload, txId);
|
|
415
|
-
this.publisher.publishToClient(failureStatusResponseMessage);
|
|
444
|
+
}, txId));
|
|
416
445
|
}
|
|
417
446
|
break;
|
|
418
447
|
}
|
|
@@ -420,140 +449,140 @@ class DeviceAgentCloudConnection {
|
|
|
420
449
|
logger_1.logger.error(`Invalid client message: '${JSON.stringify({ topic, message, txId }, null, 2)}'`);
|
|
421
450
|
}
|
|
422
451
|
}
|
|
423
|
-
async
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
});
|
|
434
|
-
// SecureTunnelNotify messages
|
|
435
|
-
}
|
|
436
|
-
else if (topic === this.secureTunnelNotifyTopic) {
|
|
437
|
-
await this.secureTunnelHandler.secureTunnelNotifyHandler(message);
|
|
438
|
-
// SecureTunnel messages
|
|
439
|
-
}
|
|
440
|
-
else if (topic === this.shadowHandler.shadowTopics.secureTunnel.updateDelta) {
|
|
441
|
-
await this.handleSecureTunnelMessage(message);
|
|
452
|
+
async handleDeviceAction(payload) {
|
|
453
|
+
const { system_restart } = device_agent_schemas_1.keyMirrors.deviceAction;
|
|
454
|
+
switch (payload.action) {
|
|
455
|
+
case system_restart: {
|
|
456
|
+
await (0, device_control_1.reboot)();
|
|
457
|
+
break;
|
|
458
|
+
}
|
|
459
|
+
default: {
|
|
460
|
+
logger_1.logger.info(`Unrecognized device action requested: '${payload.action}'.`);
|
|
461
|
+
}
|
|
442
462
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
463
|
+
}
|
|
464
|
+
async publishCloudRequest(message) {
|
|
465
|
+
this.publisher.publishToCloud(message);
|
|
466
|
+
}
|
|
467
|
+
subscribe(topic) {
|
|
468
|
+
logger_1.logger.info(`Subscribing to ${topic}`);
|
|
469
|
+
this.device.subscribe(topic);
|
|
470
|
+
}
|
|
471
|
+
async atomicApplicationUninstall(projectId) {
|
|
472
|
+
try {
|
|
473
|
+
await (0, application_control_1.uninstallApp)({ projectId });
|
|
474
|
+
this.shadowHandler.clearProjectShadow(projectId);
|
|
446
475
|
}
|
|
447
|
-
|
|
448
|
-
logger_1.logger.error(`
|
|
476
|
+
catch (e) {
|
|
477
|
+
logger_1.logger.error(`Failed to uninstall ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
|
|
478
|
+
throw e;
|
|
449
479
|
}
|
|
450
480
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
//
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
this.device.on('disconnect', () => {
|
|
460
|
-
logger_1.logger.warn('Device Agent has been disconnected from the cloud');
|
|
461
|
-
});
|
|
462
|
-
this.device.on('reconnect', () => {
|
|
463
|
-
logger_1.logger.info(`Device Agent attempting to re-connect ${new Date().toLocaleString()}`);
|
|
464
|
-
});
|
|
465
|
-
this.device.on('error', function (error) {
|
|
466
|
-
const errorString = error.message.toString();
|
|
467
|
-
logger_1.logger.error(`${errorString}`);
|
|
468
|
-
});
|
|
469
|
-
this.device.on('message', async (topic, payload) => {
|
|
481
|
+
// eslint-disable-next-line
|
|
482
|
+
async atomicApplicationUpdate(func, projectId, skipUpdateShadow) {
|
|
483
|
+
if (await (0, agent_config_1.AgentConfigFile)().isAppPresent({ projectId })) {
|
|
484
|
+
// Reject the application update if app is present but not ready
|
|
485
|
+
if (!(await (0, agent_config_1.AgentConfigFile)().isAppReady({ projectId }))) {
|
|
486
|
+
throw new Error('Application already has installation in progress!');
|
|
487
|
+
}
|
|
488
|
+
// Try to create a backup, so that there is one available if something goes wrong in the next try:catch.
|
|
470
489
|
try {
|
|
471
|
-
|
|
472
|
-
await this.handleMessage(topic, jsonPacket);
|
|
490
|
+
await (0, backup_1.createAppBackup)({ projectId });
|
|
473
491
|
}
|
|
474
492
|
catch (e) {
|
|
475
|
-
logger_1.logger.error(`
|
|
493
|
+
logger_1.logger.error(`Could not create a backup for the project: ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
|
|
476
494
|
}
|
|
477
|
-
}
|
|
478
|
-
this.device.on('offline', () => {
|
|
479
|
-
logger_1.logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
|
|
480
|
-
void this.logConnectionInfo();
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
async logConnectionInfo() {
|
|
495
|
+
}
|
|
484
496
|
try {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
* and catch the resulting error/parse the resulting stderr
|
|
490
|
-
*
|
|
491
|
-
* Sample command for current host and port:
|
|
492
|
-
* nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
|
|
493
|
-
*
|
|
494
|
-
* Sample output when port is not blocked and host is reachable:
|
|
495
|
-
* $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443
|
|
496
|
-
* Connection to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 443 port [tcp/https] succeeded!
|
|
497
|
-
*
|
|
498
|
-
*
|
|
499
|
-
* Sample output when port is blocked (will repeatedly try until ctrl-C out):
|
|
500
|
-
* $ nc -zv -w 1 a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com 8883
|
|
501
|
-
* nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
|
|
502
|
-
* nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
|
|
503
|
-
* nc: connect to a3tzi5g7sq5zsj-ats.iot.us-west-2.amazonaws.com port 8883 (tcp) timed out: Operation now in progress
|
|
504
|
-
* ^C
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
* Sample command/output when the port isn't enable on that host:
|
|
508
|
-
* $ nc -zv -w 1 localhost 8883
|
|
509
|
-
* nc: connect to localhost port 8883 (tcp) failed: Connection refused
|
|
510
|
-
*/
|
|
511
|
-
await exec_promise(`nc -zv -w 1 ${this.host} ${this.port}`, {
|
|
512
|
-
timeout: 2000
|
|
513
|
-
});
|
|
497
|
+
const out = await func();
|
|
498
|
+
if (!skipUpdateShadow)
|
|
499
|
+
await this.shadowHandler.updateProjectShadow(projectId);
|
|
500
|
+
return out;
|
|
514
501
|
}
|
|
515
|
-
catch (
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
else if (output.indexOf('timed out') !== -1) {
|
|
521
|
-
logger_1.logger.warn(`Internet connection appears fine, however the endpoint was not reachable on the current connection port: ${this.port}\nPlease check if a firewall is in place.`);
|
|
502
|
+
catch (errorAppUpdate) {
|
|
503
|
+
logger_1.logger.error(`Failed to update ${projectId}!\n${(0, util_1.stringifyError)(errorAppUpdate)}`);
|
|
504
|
+
// If something goes wrong, first try to rollback
|
|
505
|
+
try {
|
|
506
|
+
await (0, backup_1.rollbackApp)({ projectId });
|
|
522
507
|
}
|
|
523
|
-
|
|
524
|
-
logger_1.logger.
|
|
508
|
+
catch (errorRollbackApp) {
|
|
509
|
+
logger_1.logger.error(`Application rollback failed for ${projectId}!\n${(0, util_1.stringifyError)(errorRollbackApp)}`);
|
|
510
|
+
// and if that fails, uninstall the app as a last resort.
|
|
511
|
+
try {
|
|
512
|
+
await this.atomicApplicationUninstall(projectId);
|
|
513
|
+
}
|
|
514
|
+
catch (_a) {
|
|
515
|
+
// atomicApplicationUninstall logs failure, so there's nothing to do here.
|
|
516
|
+
}
|
|
517
|
+
throw new aai_error_1.default('Application update and rollback failed, uninstalled the application!', { cause: errorAppUpdate });
|
|
525
518
|
}
|
|
526
|
-
|
|
527
|
-
|
|
519
|
+
throw new Error('Application update failed, rolled the application back!', { cause: errorAppUpdate });
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
async handleProjectShadowMessage(topic, message) {
|
|
523
|
+
const shadowUpdates = await this.shadowHandler.handleProjectShadow({
|
|
524
|
+
topic,
|
|
525
|
+
payload: message,
|
|
526
|
+
clientToken: message.clientToken
|
|
527
|
+
});
|
|
528
|
+
if (shadowUpdates.length) {
|
|
529
|
+
const shadowUpdatePromises = [];
|
|
530
|
+
for (const shadowUpdate of shadowUpdates) {
|
|
531
|
+
const projectId = shadowUpdate.projectId;
|
|
532
|
+
const txId = shadowUpdate.txId;
|
|
533
|
+
shadowUpdatePromises.push(this.txnMgr
|
|
534
|
+
.runTransactionStep({
|
|
535
|
+
func: () => this.handleProjectShadowConfigUpdate(shadowUpdate, txId),
|
|
536
|
+
projectId,
|
|
537
|
+
txId,
|
|
538
|
+
start: true,
|
|
539
|
+
liveUpdatesPublishFn: async () => this.publisher.publishToClient((0, device_agent_schemas_1.buildToClientStatusResponseMessage)(this.clientId, { status: device_agent_schemas_1.keyMirrors.statusResponse.in_progress }, txId), logger_1.logger.silly),
|
|
540
|
+
stepName: topic
|
|
541
|
+
})
|
|
542
|
+
.catch((e) => {
|
|
543
|
+
logger_1.logger.error(`There was an issue updating project shadow config for ${projectId}!\n${(0, util_1.stringifyError)(e)}`);
|
|
544
|
+
}));
|
|
528
545
|
}
|
|
546
|
+
await Promise.all(shadowUpdatePromises);
|
|
529
547
|
}
|
|
530
548
|
}
|
|
531
|
-
async
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
549
|
+
async handleSecureTunnelMessage(payload) {
|
|
550
|
+
logger_1.logger.info(`Received secure tunnel update: ${JSON.stringify(payload)}`);
|
|
551
|
+
const state = (0, device_agent_schemas_1.getUpdateDeltaStateFromMessage)(payload);
|
|
552
|
+
if (!state) {
|
|
553
|
+
logger_1.logger.debug(`No state found in message: ${JSON.stringify(payload)}`);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
const valid = (0, device_agent_schemas_1.validateSecureTunnelShadowUpdate)(state);
|
|
557
|
+
if (!valid) {
|
|
558
|
+
logger_1.logger.error(`Error validating message: ${JSON.stringify({ payload, errors: device_agent_schemas_1.validateSecureTunnelShadowUpdate.errors }, null, 2)}`);
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
const secureTunnelUpdate = await this.secureTunnelHandler.syncShadowToDeviceState(payload);
|
|
562
|
+
await this.shadowHandler.updateSecureTunnelShadow(secureTunnelUpdate);
|
|
537
563
|
}
|
|
538
564
|
}
|
|
539
565
|
exports.DeviceAgentCloudConnection = DeviceAgentCloudConnection;
|
|
540
566
|
async function runDeviceAgentCloudInterface() {
|
|
541
567
|
logger_1.logger.info(`Starting alwaysAI Device Agent v${await (0, check_for_updates_1.getDeviceAgentVersion)()}`);
|
|
542
|
-
if ((0,
|
|
568
|
+
if ((0, fs_1.existsSync)((0, device_certificate_1.getBootstrapPrivateKeyFilePath)())) {
|
|
569
|
+
await (0, bootstrap_provision_1.bootstrapProvision)();
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
const filesAlreadyMigrated = await (0, required_config_checks_1.requiredConfigFilesPresentAndValid)();
|
|
573
|
+
if (!filesAlreadyMigrated) {
|
|
574
|
+
logger_1.logger.debug('Attempting configuration file migration.');
|
|
575
|
+
await (0, legacy_migration_1.migrateFromLegacyCertsAndTokens)();
|
|
576
|
+
}
|
|
577
|
+
if (await (0, required_config_checks_1.requiredConfigFilesPresentAndValid)()) {
|
|
543
578
|
const deviceAgent = new DeviceAgentCloudConnection();
|
|
544
|
-
await deviceAgent.setupHandlers();
|
|
545
579
|
if (environment_1.ALWAYSAI_ANALYTICS_PASSTHROUGH === true) {
|
|
580
|
+
const shadowHandler = deviceAgent.shadowHandler;
|
|
546
581
|
const publisher = deviceAgent.publisher;
|
|
547
|
-
const passthroughHandler = new passthrough_handler_1.PassthroughHandler(publisher);
|
|
582
|
+
const passthroughHandler = new passthrough_handler_1.PassthroughHandler(publisher, shadowHandler);
|
|
548
583
|
await passthroughHandler.setup();
|
|
549
584
|
}
|
|
550
585
|
}
|
|
551
|
-
else if ((0, fs_1.existsSync)((0, directories_1.BOOTSTRAP_PRIVATE_KEY_FILE_PATH)())) {
|
|
552
|
-
await (0, bootstrap_provision_1.bootstrapProvision)();
|
|
553
|
-
}
|
|
554
|
-
else if ((0, fs_1.existsSync)((0, directories_1.BOOTSTRAP_CERTIFICATES_DIR_PATH)())) {
|
|
555
|
-
throw new Error("Device has not been created using 'aai-agent device init' or there has been an issue with device initialization");
|
|
556
|
-
}
|
|
557
586
|
else {
|
|
558
587
|
throw new Error("Set device agent to local mode and retry the 'aai-agent device init' command");
|
|
559
588
|
}
|