@alwaysai/device-agent 0.0.12 → 0.0.13
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/backup.d.ts.map +1 -1
- package/lib/application-control/backup.js +8 -2
- package/lib/application-control/backup.js.map +1 -1
- package/lib/application-control/config.d.ts +12 -4
- package/lib/application-control/config.d.ts.map +1 -1
- package/lib/application-control/config.js +59 -16
- package/lib/application-control/config.js.map +1 -1
- package/lib/application-control/environment-variables.d.ts.map +1 -1
- package/lib/application-control/environment-variables.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 +4 -3
- 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 +28 -14
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/models.d.ts +7 -1
- package/lib/application-control/models.d.ts.map +1 -1
- package/lib/application-control/models.js +69 -39
- 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 +18 -14
- package/lib/application-control/status.js.map +1 -1
- package/lib/application-control/utils.d.ts +0 -2
- package/lib/application-control/utils.d.ts.map +1 -1
- package/lib/application-control/utils.js +7 -16
- package/lib/application-control/utils.js.map +1 -1
- package/lib/cloud-connection/app-install-status.d.ts +16 -0
- package/lib/cloud-connection/app-install-status.d.ts.map +1 -0
- package/lib/cloud-connection/app-install-status.js +53 -0
- package/lib/cloud-connection/app-install-status.js.map +1 -0
- package/lib/cloud-connection/bootstrap-provision.d.ts +2 -0
- package/lib/cloud-connection/bootstrap-provision.d.ts.map +1 -0
- package/lib/cloud-connection/bootstrap-provision.js +34 -0
- package/lib/cloud-connection/bootstrap-provision.js.map +1 -0
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts +12 -34
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +169 -385
- 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 +22 -26
- package/lib/cloud-connection/device-agent.js.map +1 -1
- package/lib/cloud-connection/live-updates-handler.d.ts +34 -0
- package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -0
- package/lib/cloud-connection/live-updates-handler.js +167 -0
- package/lib/cloud-connection/live-updates-handler.js.map +1 -0
- package/lib/cloud-connection/messages.d.ts +14 -0
- package/lib/cloud-connection/messages.d.ts.map +1 -0
- package/lib/cloud-connection/messages.js +38 -0
- package/lib/cloud-connection/messages.js.map +1 -0
- package/lib/cloud-connection/publisher.d.ts +14 -0
- package/lib/cloud-connection/publisher.d.ts.map +1 -0
- package/lib/cloud-connection/publisher.js +44 -0
- package/lib/cloud-connection/publisher.js.map +1 -0
- package/lib/cloud-connection/shadow-handler.d.ts +34 -0
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -0
- package/lib/cloud-connection/shadow-handler.js +94 -0
- package/lib/cloud-connection/shadow-handler.js.map +1 -0
- package/lib/cloud-connection/shadow.d.ts +16 -0
- package/lib/cloud-connection/shadow.d.ts.map +1 -0
- package/lib/cloud-connection/shadow.js +36 -0
- package/lib/cloud-connection/shadow.js.map +1 -0
- package/lib/device-control/device-control.d.ts.map +1 -1
- package/lib/device-control/device-control.js +1 -0
- package/lib/device-control/device-control.js.map +1 -1
- package/lib/docker/docker-cmd.js +1 -1
- package/lib/docker/docker-compose-cmd.d.ts.map +1 -1
- package/lib/docker/docker-compose-cmd.js +1 -1
- package/lib/docker/docker-compose-cmd.js.map +1 -1
- package/lib/endpoints.js +10 -10
- package/lib/endpoints.js.map +1 -1
- package/lib/environment.d.ts.map +1 -1
- package/lib/environment.js.map +1 -1
- package/lib/infrastructure/agent-config.d.ts +4 -14
- package/lib/infrastructure/agent-config.d.ts.map +1 -1
- package/lib/infrastructure/agent-config.js +22 -15
- package/lib/infrastructure/agent-config.js.map +1 -1
- package/lib/infrastructure/agent-config.test.js +26 -18
- package/lib/infrastructure/agent-config.test.js.map +1 -1
- package/lib/infrastructure/system-id.d.ts +2 -0
- package/lib/infrastructure/system-id.d.ts.map +1 -0
- package/lib/infrastructure/system-id.js +21 -0
- package/lib/infrastructure/system-id.js.map +1 -0
- package/lib/infrastructure/tokens-and-device-cfg.d.ts +4 -0
- package/lib/infrastructure/tokens-and-device-cfg.d.ts.map +1 -0
- package/lib/infrastructure/tokens-and-device-cfg.js +31 -0
- package/lib/infrastructure/tokens-and-device-cfg.js.map +1 -0
- package/lib/infrastructure/urls.d.ts.map +1 -1
- package/lib/infrastructure/urls.js +3 -3
- package/lib/infrastructure/urls.js.map +1 -1
- package/lib/root.d.ts.map +1 -1
- package/lib/root.js +2 -7
- package/lib/root.js.map +1 -1
- package/lib/subcommands/app/app.d.ts.map +1 -1
- package/lib/subcommands/app/app.js +62 -60
- package/lib/subcommands/app/app.js.map +1 -1
- package/lib/subcommands/app/index.js +2 -2
- package/lib/subcommands/device/clean.d.ts +2 -0
- package/lib/subcommands/device/clean.d.ts.map +1 -0
- package/lib/subcommands/device/clean.js +29 -0
- package/lib/subcommands/device/clean.js.map +1 -0
- package/lib/subcommands/device/device.d.ts.map +1 -1
- package/lib/subcommands/device/device.js +40 -27
- package/lib/subcommands/device/device.js.map +1 -1
- package/lib/subcommands/device/index.d.ts.map +1 -1
- package/lib/subcommands/device/index.js +2 -1
- package/lib/subcommands/device/index.js.map +1 -1
- package/lib/subcommands/get-model-package.js +5 -5
- package/lib/subcommands/index.js +1 -1
- package/lib/subcommands/login.js +8 -8
- package/lib/subcommands/login.js.map +1 -1
- package/lib/util/clean-certs.d.ts +2 -0
- package/lib/util/clean-certs.d.ts.map +1 -0
- package/lib/util/clean-certs.js +16 -0
- package/lib/util/clean-certs.js.map +1 -0
- package/lib/util/directories.d.ts +16 -15
- package/lib/util/directories.d.ts.map +1 -1
- package/lib/util/directories.js +45 -26
- package/lib/util/directories.js.map +1 -1
- package/lib/util/get-device-id.d.ts +1 -1
- package/lib/util/get-device-id.d.ts.map +1 -1
- package/lib/util/get-device-id.js +14 -19
- package/lib/util/get-device-id.js.map +1 -1
- package/lib/util/http-client.d.ts +1 -1
- package/lib/util/http-client.d.ts.map +1 -1
- package/lib/util/http-client.js +10 -8
- package/lib/util/http-client.js.map +1 -1
- package/lib/util/logger.d.ts.map +1 -1
- package/lib/util/logger.js +4 -5
- package/lib/util/logger.js.map +1 -1
- package/lib/util/run-in-dir.d.ts.map +1 -1
- package/lib/util/run-in-dir.js +1 -0
- package/lib/util/run-in-dir.js.map +1 -1
- package/package.json +17 -8
- package/src/application-control/backup.ts +8 -3
- package/src/application-control/config.ts +75 -13
- package/src/application-control/environment-variables.ts +3 -3
- package/src/application-control/index.ts +19 -6
- package/src/application-control/install.ts +52 -28
- package/src/application-control/models.ts +100 -56
- package/src/application-control/status.ts +26 -21
- package/src/application-control/utils.ts +9 -20
- package/src/cloud-connection/app-install-status.ts +62 -0
- package/src/cloud-connection/bootstrap-provision.ts +40 -0
- package/src/cloud-connection/device-agent-cloud-connection.ts +257 -528
- package/src/cloud-connection/device-agent.ts +31 -38
- package/src/cloud-connection/live-updates-handler.ts +226 -0
- package/src/cloud-connection/messages.ts +39 -0
- package/src/cloud-connection/publisher.ts +65 -0
- package/src/cloud-connection/shadow-handler.ts +154 -0
- package/src/cloud-connection/shadow.ts +50 -0
- package/src/device-control/device-control.ts +1 -0
- package/src/docker/docker-cmd.ts +1 -1
- package/src/docker/docker-compose-cmd.ts +5 -2
- package/src/endpoints.ts +9 -9
- package/src/environment.ts +8 -3
- package/src/infrastructure/agent-config.test.ts +34 -23
- package/src/infrastructure/agent-config.ts +33 -20
- package/src/infrastructure/system-id.ts +18 -0
- package/src/infrastructure/tokens-and-device-cfg.ts +39 -0
- package/src/infrastructure/urls.ts +4 -2
- package/src/root.ts +2 -8
- package/src/subcommands/app/app.ts +64 -62
- package/src/subcommands/app/index.ts +3 -3
- package/src/subcommands/device/clean.ts +26 -0
- package/src/subcommands/device/device.ts +66 -50
- package/src/subcommands/device/index.ts +2 -1
- package/src/subcommands/get-model-package.ts +5 -5
- package/src/subcommands/index.ts +1 -1
- package/src/subcommands/login.ts +8 -8
- package/src/util/clean-certs.ts +12 -0
- package/src/util/directories.ts +68 -52
- package/src/util/get-device-id.ts +16 -18
- package/src/util/http-client.ts +18 -13
- package/src/util/logger.ts +6 -6
- package/src/util/run-in-dir.ts +2 -1
- package/lib/infrastructure/certificates-and-tokens.d.ts +0 -6
- package/lib/infrastructure/certificates-and-tokens.d.ts.map +0 -1
- package/lib/infrastructure/certificates-and-tokens.js +0 -43
- package/lib/infrastructure/certificates-and-tokens.js.map +0 -1
- package/src/infrastructure/certificates-and-tokens.ts +0 -53
|
@@ -1,62 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.runDeviceAgentCloudInterface = exports.DeviceAgentCloudConnection = void 0;
|
|
4
|
-
|
|
4
|
+
// eslint-disable-next-line
|
|
5
|
+
const awsIot = require('aws-iot-device-sdk');
|
|
5
6
|
const urls_1 = require("../infrastructure/urls");
|
|
6
7
|
const fs_1 = require("fs");
|
|
7
8
|
const directories_1 = require("../util/directories");
|
|
8
|
-
const device_agent_1 = require("./device-agent");
|
|
9
|
-
const sleep_1 = require("../util/sleep");
|
|
10
|
-
const status_1 = require("../application-control/status");
|
|
11
|
-
const install_1 = require("../application-control/install");
|
|
12
9
|
const device_agent_schemas_1 = require("@alwaysai/device-agent-schemas");
|
|
13
10
|
const get_device_id_1 = require("../util/get-device-id");
|
|
14
|
-
const
|
|
15
|
-
const device_control_1 = require("../device-control/device-control");
|
|
11
|
+
const logger_1 = require("../util/logger");
|
|
16
12
|
const agent_config_1 = require("../infrastructure/agent-config");
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
const
|
|
13
|
+
const application_control_1 = require("../application-control");
|
|
14
|
+
const shadow_handler_1 = require("./shadow-handler");
|
|
15
|
+
const publisher_1 = require("./publisher");
|
|
16
|
+
const live_updates_handler_1 = require("./live-updates-handler");
|
|
17
|
+
const bootstrap_provision_1 = require("./bootstrap-provision");
|
|
18
|
+
const app_install_status_1 = require("./app-install-status");
|
|
20
19
|
class DeviceAgentCloudConnection {
|
|
20
|
+
// Public Methods
|
|
21
21
|
constructor() {
|
|
22
|
-
this.
|
|
22
|
+
this.device = awsIot.device;
|
|
23
|
+
this.clientId = (0, get_device_id_1.getDeviceUuid)();
|
|
23
24
|
this.host = (0, urls_1.getIoTCoreEndpointUrl)();
|
|
24
|
-
this.liveUpdatesAlive = {
|
|
25
|
-
[device_agent_schemas_1.keyMirrors.agentMessageType.device_stats]: false,
|
|
26
|
-
[device_agent_schemas_1.keyMirrors.agentMessageType.app_state]: false,
|
|
27
|
-
[device_agent_schemas_1.keyMirrors.agentMessageType.app_logs]: false,
|
|
28
|
-
};
|
|
29
|
-
this.liveUpdatesSleepIntervals = {
|
|
30
|
-
[device_agent_schemas_1.keyMirrors.agentMessageType.device_stats]: 5000,
|
|
31
|
-
[device_agent_schemas_1.keyMirrors.agentMessageType.app_state]: 5000,
|
|
32
|
-
[device_agent_schemas_1.keyMirrors.agentMessageType.app_logs]: 5000,
|
|
33
|
-
[device_agent_schemas_1.keyMirrors.agentMessageType.app_install_status]: 5000,
|
|
34
|
-
};
|
|
35
|
-
this.appLogStreams = new Set();
|
|
36
|
-
this.shadowPrefix = `$aws/things/${this.clientId}/shadow/name/`;
|
|
37
|
-
this.shadowTopics = {
|
|
38
|
-
projects: {
|
|
39
|
-
updateDelta: `${this.shadowPrefix}projects/update/delta`,
|
|
40
|
-
getAccepted: `${this.shadowPrefix}projects/get/accepted`,
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
this.toCloudTopic = (0, device_agent_schemas_1.getCloudTopic)(this.clientId);
|
|
44
|
-
this.toClientTopic = (0, device_agent_schemas_1.getClientTopic)(this.clientId);
|
|
45
25
|
this.toDeviceTopic = (0, device_agent_schemas_1.getDeviceTopic)(this.clientId);
|
|
46
|
-
//
|
|
47
|
-
this.
|
|
48
|
-
const appInstallStatus = this.getAppInstallStatus();
|
|
49
|
-
const appInstallStatusMessage = {
|
|
50
|
-
messageType: device_agent_schemas_1.keyMirrors.agentMessageType.app_install_status,
|
|
51
|
-
appInstallStatus,
|
|
52
|
-
};
|
|
53
|
-
return appInstallStatusMessage;
|
|
54
|
-
};
|
|
26
|
+
// FIXME: Add support for multiple simultaneous project updates
|
|
27
|
+
this.newAppCfgQueue = [];
|
|
55
28
|
this.handleDeviceCommand = async (packet) => {
|
|
56
29
|
// TODO
|
|
57
30
|
};
|
|
58
|
-
// Public Methods
|
|
59
|
-
this.device = awsIot.device;
|
|
60
31
|
this.device = awsIot.device({
|
|
61
32
|
keyPath: (0, directories_1.getPrivateKeyFilePath)(),
|
|
62
33
|
certPath: (0, directories_1.getCertificateFilePath)(),
|
|
@@ -64,184 +35,27 @@ class DeviceAgentCloudConnection {
|
|
|
64
35
|
clientId: this.clientId,
|
|
65
36
|
host: this.host,
|
|
66
37
|
port: 8883,
|
|
38
|
+
keepalive: 1 // time before re-connect attempt on dropped connection, default is 400 seconds
|
|
67
39
|
});
|
|
68
|
-
this.
|
|
69
|
-
this.
|
|
70
|
-
this.
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
async handleNamedShadowUpdate({ payload }) {
|
|
77
|
-
const delta = JSON.parse(payload);
|
|
78
|
-
const deltaKeys = Object.keys(delta);
|
|
79
|
-
for (const projectId of deltaKeys) {
|
|
80
|
-
const projectShadow = delta[projectId];
|
|
81
|
-
if (projectShadow.appConfig) {
|
|
82
|
-
const appConfig = projectShadow.appConfig;
|
|
83
|
-
const appDir = (0, utils_1.getAppDir)(projectId);
|
|
84
|
-
await (0, config_1.updateAppConfig)(projectId, appConfig);
|
|
85
|
-
if (appConfig.models) {
|
|
86
|
-
this.publishCloudRequest({
|
|
87
|
-
messageType: device_agent_schemas_1.keyMirrors.agentMessageType.signed_urls_request,
|
|
88
|
-
modelsOnlyUrlsRequest: {
|
|
89
|
-
projectId,
|
|
90
|
-
models: appConfig.models,
|
|
91
|
-
},
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
if (appConfig.scripts && !appConfig.models) {
|
|
95
|
-
const appState = await (0, status_1.getAppStatus)({ projectId });
|
|
96
|
-
await (0, utils_1.buildApp)({ appDir });
|
|
97
|
-
if (appState.services.length &&
|
|
98
|
-
appState.services[0].state !== device_agent_schemas_1.keyMirrors.appState.stopped) {
|
|
99
|
-
(0, status_1.restartApp)({ projectId });
|
|
100
|
-
}
|
|
101
|
-
await this.publishReportedState(projectId);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
async startAppLogStream(projectId) {
|
|
107
|
-
this.appLogStreams.add(projectId);
|
|
108
|
-
const readable = await (0, status_1.getAppLogs)({
|
|
109
|
-
projectId,
|
|
110
|
-
args: ["--tail", "100", "--no-log-prefix"],
|
|
111
|
-
});
|
|
112
|
-
readable.on("data", (chunk) => {
|
|
113
|
-
if (!this.appLogStreams.has(projectId)) {
|
|
114
|
-
// why doesn't typescript know about this function?
|
|
115
|
-
// @ts-ignore
|
|
116
|
-
readable.destroy();
|
|
117
|
-
util_1.logger.info(`App log stream terminated for project ${projectId}`);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
const logStr = chunk.toString();
|
|
121
|
-
const message = {
|
|
122
|
-
messageType: device_agent_schemas_1.keyMirrors.agentMessageType.app_logs,
|
|
123
|
-
appLogs: {
|
|
124
|
-
projectId,
|
|
125
|
-
logChunk: logStr,
|
|
126
|
-
},
|
|
127
|
-
};
|
|
128
|
-
const packet = this.buildMessagePacket(this.getClientId(), this.toClientTopic, message);
|
|
129
|
-
this.publishMessage(this.toClientTopic, JSON.stringify(packet));
|
|
130
|
-
});
|
|
131
|
-
readable.on("error", (error) => {
|
|
132
|
-
util_1.logger.error(`App log stream terminated for project ${projectId}: ${error}`);
|
|
133
|
-
});
|
|
134
|
-
readable.on("finished", () => {
|
|
135
|
-
util_1.logger.info(`App logs finished piping for project ${projectId}`);
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
// must contain app release hash
|
|
139
|
-
initAppInstallStatus(installationStatus) {
|
|
140
|
-
this.appInstallStatus = installationStatus;
|
|
141
|
-
}
|
|
142
|
-
updateAppInstallStatus(installationStatus) {
|
|
143
|
-
this.appInstallStatus.status = installationStatus.status;
|
|
144
|
-
this.appInstallStatus.message = installationStatus.message;
|
|
145
|
-
}
|
|
146
|
-
getAppInstallStatus() {
|
|
147
|
-
return this.appInstallStatus;
|
|
148
|
-
}
|
|
149
|
-
// Message Builders
|
|
150
|
-
buildMessagePacket(deviceId, topic, payload) {
|
|
151
|
-
const packet = {
|
|
152
|
-
timestamp: new Date().toUTCString(),
|
|
153
|
-
deviceId,
|
|
154
|
-
topic,
|
|
155
|
-
payload,
|
|
156
|
-
};
|
|
157
|
-
return packet;
|
|
158
|
-
}
|
|
159
|
-
async getAppStateMessage() {
|
|
160
|
-
const appStateMessage = [];
|
|
161
|
-
const apps = await (0, agent_config_1.AgentConfigFile)().getReadyApps();
|
|
162
|
-
for (const app of apps) {
|
|
163
|
-
const projectId = app.projectId;
|
|
164
|
-
const status = await (0, status_1.getAppStatus)({ projectId });
|
|
165
|
-
appStateMessage.push(status);
|
|
166
|
-
}
|
|
167
|
-
const appStatePackage = {
|
|
168
|
-
messageType: device_agent_schemas_1.keyMirrors.agentMessageType.app_state,
|
|
169
|
-
appState: appStateMessage,
|
|
170
|
-
};
|
|
171
|
-
return appStatePackage;
|
|
172
|
-
}
|
|
173
|
-
async getDeviceStatsMessage() {
|
|
174
|
-
const cpuUsage = await (0, device_control_1.getCpuUtil)();
|
|
175
|
-
const diskUtil = await (0, device_control_1.getDiskUtil)();
|
|
176
|
-
const memUtil = await (0, device_control_1.getMemUtil)();
|
|
177
|
-
const deviceStatsMessage = {
|
|
178
|
-
messageType: device_agent_schemas_1.keyMirrors.agentMessageType.device_stats,
|
|
179
|
-
deviceStats: {
|
|
180
|
-
cpuUsage,
|
|
181
|
-
diskUtil,
|
|
182
|
-
usedMemoryPercentage: memUtil,
|
|
183
|
-
},
|
|
184
|
-
};
|
|
185
|
-
return deviceStatsMessage;
|
|
186
|
-
}
|
|
187
|
-
async startPublishingLiveUpdates(topic, messageType, getMessageData) {
|
|
188
|
-
while (true) {
|
|
189
|
-
try {
|
|
190
|
-
const message = await getMessageData();
|
|
191
|
-
const packet = this.buildMessagePacket(this.getClientId(), topic, message);
|
|
192
|
-
this.publishMessage(topic, JSON.stringify(packet));
|
|
193
|
-
}
|
|
194
|
-
catch (e) {
|
|
195
|
-
util_1.logger.error(`Error publishing live updates for ${messageType}: ${e.message}`);
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
if (!this.continuePublishing(messageType)) {
|
|
199
|
-
util_1.logger.info(`Turned off live updates for ${messageType}`);
|
|
200
|
-
break;
|
|
201
|
-
}
|
|
202
|
-
await (0, sleep_1.default)(this.getLiveUpdatesInterval(messageType));
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
continuePublishing(flag) {
|
|
206
|
-
switch (flag) {
|
|
207
|
-
case device_agent_schemas_1.keyMirrors.agentMessageType.device_stats:
|
|
208
|
-
case device_agent_schemas_1.keyMirrors.agentMessageType.app_state:
|
|
209
|
-
return this.liveUpdatesAlive[flag];
|
|
210
|
-
case device_agent_schemas_1.keyMirrors.agentMessageType.app_install_status:
|
|
211
|
-
return (this.appInstallStatus.status ===
|
|
212
|
-
device_agent_schemas_1.keyMirrors.appInstallStatus.in_progress);
|
|
213
|
-
default:
|
|
214
|
-
util_1.logger.error(`Unrecognized publishable flag ${flag}`);
|
|
215
|
-
return false;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
getLiveUpdatesInterval(flag) {
|
|
219
|
-
const exists = this.liveUpdatesSleepIntervals[flag];
|
|
220
|
-
if (exists) {
|
|
221
|
-
return exists;
|
|
222
|
-
}
|
|
223
|
-
util_1.logger.error(`Unrecognized live updates flag ${flag}`);
|
|
224
|
-
return -1;
|
|
225
|
-
}
|
|
226
|
-
setLiveUpdates(toggles) {
|
|
227
|
-
if (toggles.deviceStats) {
|
|
228
|
-
this.liveUpdatesAlive.device_stats = toggles.deviceStats;
|
|
229
|
-
}
|
|
230
|
-
if (toggles.appState) {
|
|
231
|
-
this.liveUpdatesAlive.app_state = toggles.appState;
|
|
232
|
-
}
|
|
40
|
+
this.publisher = new publisher_1.Publisher(this.device, this.clientId);
|
|
41
|
+
this.shadowHandler = new shadow_handler_1.ShadowHandler(this.clientId, this.publisher);
|
|
42
|
+
this.appInstallStatusMgr = new app_install_status_1.AppInstallStatusManager();
|
|
43
|
+
this.liveUpdatesHandler = new live_updates_handler_1.LiveUpdatesHandler(this.publisher, this.appInstallStatusMgr);
|
|
44
|
+
this.subscribe(this.toDeviceTopic);
|
|
45
|
+
this.subscribe(this.shadowHandler.shadowTopics.projects.getAccepted);
|
|
46
|
+
this.subscribe(this.shadowHandler.shadowTopics.projects.updateDelta);
|
|
233
47
|
}
|
|
234
48
|
handleAppStateControl(payload) {
|
|
235
49
|
const { baseCommand, projectId } = payload;
|
|
236
50
|
switch (baseCommand) {
|
|
237
51
|
case device_agent_schemas_1.keyMirrors.appStateControl.start:
|
|
238
|
-
(0,
|
|
52
|
+
(0, application_control_1.startApp)({ projectId });
|
|
239
53
|
break;
|
|
240
54
|
case device_agent_schemas_1.keyMirrors.appStateControl.stop:
|
|
241
|
-
(0,
|
|
55
|
+
(0, application_control_1.stopApp)({ projectId });
|
|
242
56
|
break;
|
|
243
57
|
case device_agent_schemas_1.keyMirrors.appStateControl.restart:
|
|
244
|
-
(0,
|
|
58
|
+
(0, application_control_1.restartApp)({ projectId });
|
|
245
59
|
break;
|
|
246
60
|
}
|
|
247
61
|
}
|
|
@@ -250,76 +64,91 @@ class DeviceAgentCloudConnection {
|
|
|
250
64
|
const signedUrlsRequest = { projectId, appReleaseHash };
|
|
251
65
|
this.publishCloudRequest({
|
|
252
66
|
messageType: device_agent_schemas_1.keyMirrors.agentMessageType.signed_urls_request,
|
|
253
|
-
signedUrlsRequest
|
|
67
|
+
signedUrlsRequest
|
|
254
68
|
});
|
|
255
69
|
}
|
|
256
70
|
handleAgentCommand(message) {
|
|
257
71
|
switch (message.messageType) {
|
|
258
72
|
case device_agent_schemas_1.keyMirrors.clientMessageType.live_state_updates:
|
|
259
|
-
this.
|
|
73
|
+
this.liveUpdatesHandler.update(message.liveUpdatesToggles);
|
|
260
74
|
break;
|
|
261
75
|
default:
|
|
262
|
-
|
|
76
|
+
logger_1.logger.error(`Invalid agent action message type from message '${message}'`);
|
|
263
77
|
}
|
|
264
78
|
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
this.liveUpdatesTimeout = setTimeout(() => {
|
|
268
|
-
this.setLiveUpdates({
|
|
269
|
-
deviceStats: false,
|
|
270
|
-
appState: false,
|
|
271
|
-
});
|
|
272
|
-
this.appLogStreams.clear();
|
|
273
|
-
// TODO: Make constant, not hard coded
|
|
274
|
-
}, 600000); // 10 min
|
|
79
|
+
async publishCloudRequest(payload) {
|
|
80
|
+
this.publisher.publishToCloud(payload);
|
|
275
81
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
82
|
+
subscribe(topic) {
|
|
83
|
+
logger_1.logger.info(`Subscribing to ${topic}`);
|
|
84
|
+
this.device.subscribe(topic);
|
|
85
|
+
}
|
|
86
|
+
// eslint-disable-next-line
|
|
87
|
+
async atomicApplicationUpdate(func, args, projectId, appReleaseHash) {
|
|
88
|
+
this.appInstallStatusMgr.update(appReleaseHash, device_agent_schemas_1.keyMirrors.appInstallStatus.in_progress);
|
|
89
|
+
this.liveUpdatesHandler.update({
|
|
90
|
+
appInstallStatus: { toggle: true, appReleaseHash }
|
|
91
|
+
});
|
|
92
|
+
// Install the app and models
|
|
93
|
+
try {
|
|
94
|
+
const out = await func(...args);
|
|
95
|
+
this.appInstallStatusMgr.update(appReleaseHash, device_agent_schemas_1.keyMirrors.appInstallStatus.success);
|
|
96
|
+
this.liveUpdatesHandler.update({
|
|
97
|
+
appInstallStatus: { toggle: false, appReleaseHash }
|
|
98
|
+
});
|
|
99
|
+
// update app config shadow for project
|
|
100
|
+
await this.shadowHandler.publishAppState(projectId);
|
|
101
|
+
return out;
|
|
283
102
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
103
|
+
catch (e) {
|
|
104
|
+
logger_1.logger.error(e);
|
|
105
|
+
const message = e.message;
|
|
106
|
+
// uninstall the failed app to put system back in good state
|
|
107
|
+
await (0, application_control_1.uninstallApp)({ projectId });
|
|
108
|
+
this.appInstallStatusMgr.update(appReleaseHash, device_agent_schemas_1.keyMirrors.appInstallStatus.failure, message);
|
|
109
|
+
this.liveUpdatesHandler.update({
|
|
110
|
+
appInstallStatus: { toggle: false, appReleaseHash }
|
|
111
|
+
});
|
|
112
|
+
// delete shadow for project
|
|
113
|
+
// FIXME: Why do we delete the shadow? Doesn't this delete it for all projects?
|
|
114
|
+
this.shadowHandler.deleteProjectShadow();
|
|
289
115
|
}
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
116
|
+
}
|
|
117
|
+
async handleAppConfigUpdates(appConfgUpdates) {
|
|
118
|
+
for (const appConfigUpdate of appConfgUpdates) {
|
|
119
|
+
const { projectId, newAppCfg, updatedModels } = appConfigUpdate;
|
|
120
|
+
if (updatedModels && Object.keys(updatedModels).length) {
|
|
121
|
+
// Publish request for model urls
|
|
122
|
+
this.newAppCfgQueue.push(newAppCfg);
|
|
123
|
+
logger_1.logger.debug(`Requesting presigned urls from cloud for model versions: ${JSON.stringify(updatedModels)}`);
|
|
124
|
+
this.publisher.publishToCloud({
|
|
125
|
+
messageType: device_agent_schemas_1.keyMirrors.agentMessageType.signed_urls_request,
|
|
126
|
+
modelsOnlyUrlsRequest: {
|
|
127
|
+
projectId,
|
|
128
|
+
models: updatedModels
|
|
129
|
+
}
|
|
130
|
+
});
|
|
293
131
|
}
|
|
294
132
|
else {
|
|
295
|
-
this
|
|
133
|
+
// FIXME: do we need to send this up to the cloud?
|
|
134
|
+
// should it be something other than appReleaseHash?
|
|
135
|
+
const appReleaseHash = await (0, agent_config_1.AgentConfigFile)().getAppVersion({
|
|
136
|
+
projectId
|
|
137
|
+
});
|
|
138
|
+
await this.atomicApplicationUpdate(application_control_1.updateAppCfg, [
|
|
139
|
+
{
|
|
140
|
+
projectId,
|
|
141
|
+
appReleaseHash,
|
|
142
|
+
newAppCfg
|
|
143
|
+
}
|
|
144
|
+
], projectId, appReleaseHash);
|
|
296
145
|
}
|
|
297
146
|
}
|
|
298
147
|
}
|
|
299
|
-
async publishReportedState(projectId) {
|
|
300
|
-
const newAppCfg = await (0, utils_1.getAppConfig)(projectId);
|
|
301
|
-
const packet = {
|
|
302
|
-
state: {
|
|
303
|
-
reported: {
|
|
304
|
-
[projectId]: { appConfig: newAppCfg },
|
|
305
|
-
},
|
|
306
|
-
},
|
|
307
|
-
};
|
|
308
|
-
this.publishMessage(`${this.shadowPrefix}projects/update`, JSON.stringify(packet));
|
|
309
|
-
}
|
|
310
|
-
async publishCloudRequest(payload) {
|
|
311
|
-
const topic = this.toCloudTopic;
|
|
312
|
-
const deviceRequestPacket = this.buildMessagePacket(this.getClientId(), topic, payload);
|
|
313
|
-
this.publishMessage(topic, JSON.stringify({ deviceRequestPacket }));
|
|
314
|
-
}
|
|
315
148
|
getClientId() {
|
|
316
149
|
return this.clientId;
|
|
317
150
|
}
|
|
318
|
-
|
|
319
|
-
// TODO: topic validation
|
|
320
|
-
this.device.publish(topic, message, (err) => { });
|
|
321
|
-
}
|
|
322
|
-
async handleClientMessage({ topic, message, }) {
|
|
151
|
+
async handleClientMessage({ topic, message }) {
|
|
323
152
|
const payload = message.payload;
|
|
324
153
|
switch (payload.messageType) {
|
|
325
154
|
case device_agent_schemas_1.keyMirrors.clientMessageType.app_state_control: {
|
|
@@ -335,146 +164,101 @@ class DeviceAgentCloudConnection {
|
|
|
335
164
|
break;
|
|
336
165
|
}
|
|
337
166
|
case device_agent_schemas_1.keyMirrors.clientMessageType.app_install_cloud_response: {
|
|
338
|
-
const { projectId, appReleaseHash, appInstallPayload, modelsInstallPayload
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
this.
|
|
344
|
-
// Install the app and models
|
|
345
|
-
try {
|
|
346
|
-
const signedUrlsPayload = {
|
|
347
|
-
appInstallPayload,
|
|
348
|
-
modelsInstallPayload,
|
|
349
|
-
};
|
|
350
|
-
await (0, install_1.installApp)({
|
|
351
|
-
projectId,
|
|
352
|
-
appReleaseHash,
|
|
353
|
-
signedUrlsPayload,
|
|
354
|
-
});
|
|
355
|
-
this.updateAppInstallStatus({
|
|
356
|
-
status: device_agent_schemas_1.keyMirrors.appInstallStatus.success,
|
|
357
|
-
});
|
|
358
|
-
// update app config shadow for project
|
|
359
|
-
await this.publishReportedState(projectId);
|
|
360
|
-
}
|
|
361
|
-
catch (e) {
|
|
362
|
-
util_1.logger.error(e);
|
|
363
|
-
const message = e.message;
|
|
364
|
-
// uninstall the failed app to put system back in good state
|
|
365
|
-
await (0, install_1.uninstallApp)({ projectId });
|
|
366
|
-
this.updateAppInstallStatus({
|
|
367
|
-
status: device_agent_schemas_1.keyMirrors.appInstallStatus.failure,
|
|
368
|
-
message,
|
|
369
|
-
});
|
|
370
|
-
// delete shadow for project
|
|
371
|
-
this.publishMessage(`${this.shadowPrefix}${projectId}/delete`, "");
|
|
372
|
-
}
|
|
167
|
+
const { projectId, appReleaseHash, appInstallPayload, modelsInstallPayload } = payload.appInstallCloudResponse;
|
|
168
|
+
const signedUrlsPayload = {
|
|
169
|
+
appInstallPayload,
|
|
170
|
+
modelsInstallPayload
|
|
171
|
+
};
|
|
172
|
+
await this.atomicApplicationUpdate(application_control_1.installApp, [{ projectId, appReleaseHash, signedUrlsPayload }], projectId, appReleaseHash);
|
|
373
173
|
break;
|
|
374
174
|
}
|
|
375
175
|
case device_agent_schemas_1.keyMirrors.clientMessageType.models_install_cloud_response: {
|
|
376
176
|
const { projectId, newModels } = payload.modelsInstallCloudResponse;
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
177
|
+
const appReleaseHash = await (0, agent_config_1.AgentConfigFile)().getAppVersion({
|
|
178
|
+
projectId
|
|
179
|
+
});
|
|
180
|
+
const newAppCfg = this.newAppCfgQueue.shift();
|
|
181
|
+
if (newAppCfg === undefined) {
|
|
182
|
+
throw new Error('Unknown error while updating models via application config! No config present for model update.');
|
|
383
183
|
}
|
|
184
|
+
await this.atomicApplicationUpdate(application_control_1.updateModelsWithPresignedUrls, [
|
|
185
|
+
{
|
|
186
|
+
projectId,
|
|
187
|
+
modelInstallPayloads: newModels,
|
|
188
|
+
newAppCfg,
|
|
189
|
+
appReleaseHash
|
|
190
|
+
}
|
|
191
|
+
], projectId, appReleaseHash);
|
|
384
192
|
break;
|
|
385
193
|
}
|
|
386
194
|
default:
|
|
387
|
-
|
|
195
|
+
logger_1.logger.error(`Invalid client message: '${JSON.stringify({ topic, message }, null, 2)}'`);
|
|
388
196
|
}
|
|
389
197
|
}
|
|
390
|
-
async
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
this.
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
198
|
+
async setupHandlers() {
|
|
199
|
+
this.device.on('connect', (connack) => {
|
|
200
|
+
logger_1.logger.info('Device Agent has connected to the cloud');
|
|
201
|
+
// Get shadow updates
|
|
202
|
+
this.shadowHandler.getShadowUpdates();
|
|
203
|
+
});
|
|
204
|
+
this.device.on('disconnect', () => {
|
|
205
|
+
logger_1.logger.warn('Device Agent has been disconnected from the cloud');
|
|
206
|
+
});
|
|
207
|
+
this.device.on('reconnect', () => {
|
|
208
|
+
logger_1.logger.info(`Device Agent attempting to re-connect ${new Date().toLocaleString()}`);
|
|
209
|
+
});
|
|
210
|
+
this.device.on('message', async (topic, payload) => {
|
|
211
|
+
try {
|
|
212
|
+
const jsonPacket = JSON.parse(payload);
|
|
213
|
+
logger_1.logger.debug(`Received message: ${JSON.stringify({ topic, jsonPacket }, null, 2)}`);
|
|
214
|
+
if (Object.prototype.hasOwnProperty.call(jsonPacket, 'state')) {
|
|
215
|
+
if (jsonPacket.clientToken === this.getClientId()) {
|
|
216
|
+
logger_1.logger.debug(`Ignoring message sent from self: ${JSON.stringify({ topic, jsonPacket }, null, 2)}`);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
const appConfigUpdates = await this.shadowHandler.handleShadowTopic({
|
|
220
|
+
topic,
|
|
221
|
+
payload: jsonPacket.state
|
|
222
|
+
});
|
|
223
|
+
await this.handleAppConfigUpdates(appConfigUpdates);
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
const valid = (0, device_agent_schemas_1.validateClientMessage)(jsonPacket);
|
|
227
|
+
if (!valid) {
|
|
228
|
+
logger_1.logger.error(`Error validating message: ${JSON.stringify(device_agent_schemas_1.validateClientMessage.errors, null, 2)}`);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
this.handleClientMessage({
|
|
232
|
+
topic,
|
|
233
|
+
message: jsonPacket
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
401
237
|
}
|
|
402
|
-
|
|
403
|
-
|
|
238
|
+
catch (error) {
|
|
239
|
+
logger_1.logger.error(`Error parsing message: ${error}`);
|
|
404
240
|
}
|
|
405
|
-
}
|
|
241
|
+
});
|
|
242
|
+
this.device.on('offline', () => {
|
|
243
|
+
logger_1.logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
|
|
244
|
+
});
|
|
406
245
|
}
|
|
407
246
|
}
|
|
408
247
|
exports.DeviceAgentCloudConnection = DeviceAgentCloudConnection;
|
|
409
248
|
async function runDeviceAgentCloudInterface() {
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
console.log(topic);
|
|
424
|
-
console.log(JSON.parse(payload));
|
|
425
|
-
try {
|
|
426
|
-
const jsonPacket = JSON.parse(payload);
|
|
427
|
-
if (jsonPacket.hasOwnProperty("state")) {
|
|
428
|
-
deviceAgent.handleShadowTopic({
|
|
429
|
-
topic,
|
|
430
|
-
payload: JSON.stringify(jsonPacket.state),
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
else {
|
|
434
|
-
const valid = (0, device_agent_schemas_1.validateClientMessage)(jsonPacket);
|
|
435
|
-
if (!valid) {
|
|
436
|
-
console.error(JSON.stringify(device_agent_schemas_1.validateClientMessage.errors));
|
|
437
|
-
}
|
|
438
|
-
else {
|
|
439
|
-
deviceAgent.handleClientMessage({
|
|
440
|
-
topic,
|
|
441
|
-
message: jsonPacket,
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
catch (error) {
|
|
447
|
-
util_1.logger.error(error);
|
|
448
|
-
}
|
|
449
|
-
});
|
|
450
|
-
deviceAgent.device.on("packetsend", (packet) => {
|
|
451
|
-
console.log({ packet: packet });
|
|
452
|
-
});
|
|
453
|
-
}
|
|
454
|
-
break;
|
|
455
|
-
case false: {
|
|
456
|
-
//set timer
|
|
457
|
-
const clientId = (0, get_device_id_1.getDeviceId)();
|
|
458
|
-
const bootstrapConfig = {
|
|
459
|
-
keyPath: directories_1.BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH,
|
|
460
|
-
certPath: directories_1.BOOTSTRAP_DEVICE_CERTIFICATE_FILE_PATH,
|
|
461
|
-
caPath: directories_1.AWS_ROOT_CERTIFICATE_FILE_PATH,
|
|
462
|
-
clientId,
|
|
463
|
-
host: (0, urls_1.getIoTCoreEndpointUrl)(),
|
|
464
|
-
};
|
|
465
|
-
const bootstrapAgent = new device_agent_1.BootstrapAgent(bootstrapConfig);
|
|
466
|
-
bootstrapAgent.subscribeToAllTopics();
|
|
467
|
-
bootstrapAgent.publishMessage("$aws/certificates/create/json", "");
|
|
468
|
-
bootstrapAgent.device.on("connect", () => {
|
|
469
|
-
console.log("Your device is being provisioned");
|
|
470
|
-
});
|
|
471
|
-
bootstrapAgent.device.on("message", (topic, payload) => {
|
|
472
|
-
bootstrapAgent.handleAwsCertificateTopics(topic, payload);
|
|
473
|
-
});
|
|
474
|
-
bootstrapAgent.device.on("packetsend", (packet) => {
|
|
475
|
-
console.log({ packet: packet.subscriptions });
|
|
476
|
-
});
|
|
477
|
-
}
|
|
249
|
+
// FIXME: Check for KeyPath as well
|
|
250
|
+
if ((0, fs_1.existsSync)((0, directories_1.getCertificateFilePath)())) {
|
|
251
|
+
const deviceAgent = new DeviceAgentCloudConnection();
|
|
252
|
+
await deviceAgent.setupHandlers();
|
|
253
|
+
}
|
|
254
|
+
else if ((0, fs_1.existsSync)((0, directories_1.BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH)())) {
|
|
255
|
+
(0, bootstrap_provision_1.bootstrapProvision)();
|
|
256
|
+
}
|
|
257
|
+
else if ((0, fs_1.existsSync)((0, directories_1.BOOTSTRAP_CERTIFICATES_DIR_PATH)())) {
|
|
258
|
+
throw new Error("Device has not been created using 'aai-agent device init' or there has been an issue with device initialization");
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
throw new Error("Set device agent to local mode and retry the 'aai-agent device init' command");
|
|
478
262
|
}
|
|
479
263
|
}
|
|
480
264
|
exports.runDeviceAgentCloudInterface = runDeviceAgentCloudInterface;
|