@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,318 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
// eslint-disable-next-line
|
|
2
|
+
const awsIot = require('aws-iot-device-sdk');
|
|
3
|
+
import { getIoTCoreEndpointUrl } from '../infrastructure/urls';
|
|
4
|
+
import { existsSync } from 'fs';
|
|
4
5
|
import {
|
|
5
6
|
getPrivateKeyFilePath,
|
|
6
7
|
getCertificateFilePath,
|
|
7
|
-
getRootCertificateFilePath,
|
|
8
|
-
BOOTSTRAP_CLAIM_ID_FILE_PATH,
|
|
9
|
-
DEVICE_CLAIM_ID_FILE_PATH,
|
|
10
|
-
BOOTSTRAP_DEVICE_CERTIFICATE_FILE_PATH,
|
|
11
8
|
BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH,
|
|
12
9
|
AWS_ROOT_CERTIFICATE_FILE_PATH,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
import { BootstrapAgent } from "./device-agent";
|
|
16
|
-
|
|
17
|
-
import sleep from "../util/sleep";
|
|
18
|
-
import {
|
|
19
|
-
startApp,
|
|
20
|
-
stopApp,
|
|
21
|
-
restartApp,
|
|
22
|
-
getAppLogs,
|
|
23
|
-
getAppStatus,
|
|
24
|
-
} from "../application-control/status";
|
|
25
|
-
import {
|
|
26
|
-
getInstalledApps,
|
|
27
|
-
installApp,
|
|
28
|
-
uninstallApp,
|
|
29
|
-
} from "../application-control/install";
|
|
10
|
+
BOOTSTRAP_CERTIFICATES_DIR_PATH
|
|
11
|
+
} from '../util/directories';
|
|
30
12
|
import {
|
|
31
13
|
keyMirrors,
|
|
32
14
|
validateClientMessage,
|
|
33
|
-
DeviceAgentMessagePayload,
|
|
34
|
-
AppInstallStatusPacket,
|
|
35
15
|
AppStateControlPacket,
|
|
36
16
|
AppVersionControlPacket,
|
|
37
|
-
LiveUpdatesToggles,
|
|
38
|
-
AppLogsPacket,
|
|
39
|
-
AppStatePacket,
|
|
40
17
|
LiveUpdatesToggleMessage,
|
|
41
|
-
DeviceStatsMessage,
|
|
42
|
-
AppStateMessage,
|
|
43
|
-
AppLogsMessage,
|
|
44
|
-
AppInstallStatusMessage,
|
|
45
18
|
SignedUrlsRequestMessage,
|
|
46
|
-
DeviceAgentMessage,
|
|
47
19
|
ClientMessage,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
} from
|
|
53
|
-
import { getDeviceId } from "../util/get-device-id";
|
|
54
|
-
import { JsSpawner, logger } from "alwaysai/lib/util";
|
|
55
|
-
import {
|
|
56
|
-
getCpuUtil,
|
|
57
|
-
getDiskUtil,
|
|
58
|
-
getMemUtil,
|
|
59
|
-
} from "../device-control/device-control";
|
|
60
|
-
import { AgentConfigFile } from "../infrastructure/agent-config";
|
|
20
|
+
getDeviceTopic
|
|
21
|
+
} from '@alwaysai/device-agent-schemas';
|
|
22
|
+
import { getDeviceUuid } from '../util/get-device-id';
|
|
23
|
+
import { logger } from '../util/logger';
|
|
24
|
+
import { AgentConfigFile } from '../infrastructure/agent-config';
|
|
61
25
|
import {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
26
|
+
startApp,
|
|
27
|
+
stopApp,
|
|
28
|
+
restartApp,
|
|
29
|
+
updateModelsWithPresignedUrls,
|
|
30
|
+
installApp,
|
|
31
|
+
uninstallApp,
|
|
32
|
+
updateAppCfg
|
|
33
|
+
} from '../application-control';
|
|
34
|
+
import { AppConfigUpdate, ShadowHandler } from './shadow-handler';
|
|
35
|
+
import { Publisher } from './publisher';
|
|
36
|
+
import { LiveUpdatesHandler } from './live-updates-handler';
|
|
37
|
+
import { bootstrapProvision } from './bootstrap-provision';
|
|
38
|
+
import { AppInstallStatusManager } from './app-install-status';
|
|
39
|
+
import { AppConfig } from '@alwaysai/app-configuration-schemas';
|
|
68
40
|
|
|
69
41
|
export class DeviceAgentCloudConnection {
|
|
70
|
-
private
|
|
42
|
+
private shadowHandler: ShadowHandler;
|
|
43
|
+
private publisher: Publisher;
|
|
44
|
+
private liveUpdatesHandler: LiveUpdatesHandler;
|
|
45
|
+
private appInstallStatusMgr: AppInstallStatusManager;
|
|
46
|
+
private device = awsIot.device;
|
|
47
|
+
|
|
48
|
+
private clientId = getDeviceUuid();
|
|
71
49
|
private host = getIoTCoreEndpointUrl();
|
|
72
|
-
private appInstallStatus: AppInstallStatusPacket;
|
|
73
|
-
private liveUpdatesTimeout: ReturnType<typeof setTimeout>;
|
|
74
|
-
private liveUpdatesAlive = {
|
|
75
|
-
[keyMirrors.agentMessageType.device_stats]: false,
|
|
76
|
-
[keyMirrors.agentMessageType.app_state]: false,
|
|
77
|
-
[keyMirrors.agentMessageType.app_logs]: false,
|
|
78
|
-
};
|
|
79
|
-
private liveUpdatesSleepIntervals = {
|
|
80
|
-
[keyMirrors.agentMessageType.device_stats]: 5000,
|
|
81
|
-
[keyMirrors.agentMessageType.app_state]: 5000,
|
|
82
|
-
[keyMirrors.agentMessageType.app_logs]: 5000,
|
|
83
|
-
[keyMirrors.agentMessageType.app_install_status]: 5000,
|
|
84
|
-
};
|
|
85
|
-
private appLogStreams = new Set<string>();
|
|
86
|
-
private readonly shadowPrefix = `$aws/things/${this.clientId}/shadow/name/`;
|
|
87
|
-
private readonly shadowTopics = {
|
|
88
|
-
projects: {
|
|
89
|
-
updateDelta: `${this.shadowPrefix}projects/update/delta`,
|
|
90
|
-
getAccepted: `${this.shadowPrefix}projects/get/accepted`,
|
|
91
|
-
},
|
|
92
|
-
};
|
|
93
|
-
private readonly toCloudTopic = getCloudTopic(this.clientId);
|
|
94
|
-
private readonly toClientTopic = getClientTopic(this.clientId);
|
|
95
50
|
private readonly toDeviceTopic = getDeviceTopic(this.clientId);
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
public getShadowPrefix() {
|
|
100
|
-
return this.shadowPrefix;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private async handleNamedShadowUpdate({ payload }: { payload: string }) {
|
|
104
|
-
const delta = JSON.parse(payload);
|
|
105
|
-
const deltaKeys = Object.keys(delta);
|
|
106
|
-
|
|
107
|
-
for (const projectId of deltaKeys) {
|
|
108
|
-
const projectShadow = delta[projectId];
|
|
109
|
-
if (projectShadow.appConfig) {
|
|
110
|
-
const appConfig = projectShadow.appConfig;
|
|
111
|
-
const appDir = getAppDir(projectId);
|
|
112
|
-
await updateAppConfig(projectId, appConfig);
|
|
113
|
-
|
|
114
|
-
if (appConfig.models) {
|
|
115
|
-
this.publishCloudRequest({
|
|
116
|
-
messageType: keyMirrors.agentMessageType.signed_urls_request,
|
|
117
|
-
modelsOnlyUrlsRequest: {
|
|
118
|
-
projectId,
|
|
119
|
-
models: appConfig.models,
|
|
120
|
-
},
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
if (appConfig.scripts && !appConfig.models) {
|
|
125
|
-
const appState = await getAppStatus({ projectId });
|
|
126
|
-
|
|
127
|
-
await buildApp({ appDir });
|
|
128
|
-
|
|
129
|
-
if (
|
|
130
|
-
appState.services.length &&
|
|
131
|
-
appState.services[0].state !== keyMirrors.appState.stopped
|
|
132
|
-
) {
|
|
133
|
-
restartApp({ projectId });
|
|
134
|
-
}
|
|
135
|
-
await this.publishReportedState(projectId);
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
private async startAppLogStream(projectId: string) {
|
|
142
|
-
this.appLogStreams.add(projectId);
|
|
143
|
-
const readable = await getAppLogs({
|
|
144
|
-
projectId,
|
|
145
|
-
args: ["--tail", "100", "--no-log-prefix"],
|
|
146
|
-
});
|
|
147
|
-
readable.on("data", (chunk: Buffer) => {
|
|
148
|
-
if (!this.appLogStreams.has(projectId)) {
|
|
149
|
-
// why doesn't typescript know about this function?
|
|
150
|
-
// @ts-ignore
|
|
151
|
-
readable.destroy();
|
|
152
|
-
logger.info(`App log stream terminated for project ${projectId}`);
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const logStr = chunk.toString();
|
|
156
|
-
const message = {
|
|
157
|
-
messageType: keyMirrors.agentMessageType.app_logs,
|
|
158
|
-
appLogs: {
|
|
159
|
-
projectId,
|
|
160
|
-
logChunk: logStr,
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
const packet = this.buildMessagePacket(
|
|
164
|
-
this.getClientId(),
|
|
165
|
-
this.toClientTopic,
|
|
166
|
-
message
|
|
167
|
-
);
|
|
168
|
-
this.publishMessage(this.toClientTopic, JSON.stringify(packet));
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
readable.on("error", (error) => {
|
|
172
|
-
logger.error(
|
|
173
|
-
`App log stream terminated for project ${projectId}: ${error}`
|
|
174
|
-
);
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
readable.on("finished", () => {
|
|
178
|
-
logger.info(`App logs finished piping for project ${projectId}`);
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
// must contain app release hash
|
|
183
|
-
private initAppInstallStatus(installationStatus: AppInstallStatusPacket) {
|
|
184
|
-
this.appInstallStatus = installationStatus;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
private updateAppInstallStatus(
|
|
188
|
-
installationStatus: Omit<AppInstallStatusPacket, "appReleaseHash">
|
|
189
|
-
) {
|
|
190
|
-
this.appInstallStatus.status = installationStatus.status;
|
|
191
|
-
this.appInstallStatus.message = installationStatus.message;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
private getAppInstallStatus(): AppInstallStatusPacket {
|
|
195
|
-
return this.appInstallStatus;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Message Builders
|
|
199
|
-
private buildMessagePacket(
|
|
200
|
-
deviceId: string,
|
|
201
|
-
topic: string,
|
|
202
|
-
payload: DeviceAgentMessagePayload
|
|
203
|
-
): DeviceAgentMessage {
|
|
204
|
-
const packet = {
|
|
205
|
-
timestamp: new Date().toUTCString(),
|
|
206
|
-
deviceId,
|
|
207
|
-
topic,
|
|
208
|
-
payload,
|
|
209
|
-
};
|
|
210
|
-
return packet;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
private async getAppStateMessage(): Promise<AppStateMessage> {
|
|
214
|
-
const appStateMessage: AppStatePacket[] = [];
|
|
215
|
-
const apps = await AgentConfigFile().getReadyApps();
|
|
216
|
-
for (const app of apps) {
|
|
217
|
-
const projectId = app.projectId;
|
|
218
|
-
const status = await getAppStatus({ projectId });
|
|
219
|
-
appStateMessage.push(status);
|
|
220
|
-
}
|
|
221
|
-
const appStatePackage = {
|
|
222
|
-
messageType: keyMirrors.agentMessageType.app_state,
|
|
223
|
-
appState: appStateMessage,
|
|
224
|
-
};
|
|
225
|
-
return appStatePackage;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
private async getDeviceStatsMessage(): Promise<DeviceStatsMessage> {
|
|
229
|
-
const cpuUsage = await getCpuUtil();
|
|
230
|
-
const diskUtil = await getDiskUtil();
|
|
231
|
-
const memUtil = await getMemUtil();
|
|
232
|
-
|
|
233
|
-
const deviceStatsMessage = {
|
|
234
|
-
messageType: keyMirrors.agentMessageType.device_stats,
|
|
235
|
-
deviceStats: {
|
|
236
|
-
cpuUsage,
|
|
237
|
-
diskUtil,
|
|
238
|
-
usedMemoryPercentage: memUtil,
|
|
239
|
-
},
|
|
240
|
-
};
|
|
241
|
-
return deviceStatsMessage;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// must be arrow function due to this context when function is passed as param
|
|
245
|
-
private getAppInstallStatusMessage =
|
|
246
|
-
async (): Promise<AppInstallStatusMessage> => {
|
|
247
|
-
const appInstallStatus = this.getAppInstallStatus();
|
|
248
|
-
const appInstallStatusMessage = {
|
|
249
|
-
messageType: keyMirrors.agentMessageType.app_install_status,
|
|
250
|
-
appInstallStatus,
|
|
251
|
-
};
|
|
252
|
-
return appInstallStatusMessage;
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
private async startPublishingLiveUpdates(
|
|
256
|
-
topic: string,
|
|
257
|
-
messageType: string,
|
|
258
|
-
getMessageData: () => Promise<DeviceAgentMessagePayload>
|
|
259
|
-
) {
|
|
260
|
-
while (true) {
|
|
261
|
-
try {
|
|
262
|
-
const message = await getMessageData();
|
|
263
|
-
const packet = this.buildMessagePacket(
|
|
264
|
-
this.getClientId(),
|
|
265
|
-
topic,
|
|
266
|
-
message
|
|
267
|
-
);
|
|
268
|
-
this.publishMessage(topic, JSON.stringify(packet));
|
|
269
|
-
} catch (e) {
|
|
270
|
-
logger.error(
|
|
271
|
-
`Error publishing live updates for ${messageType}: ${e.message}`
|
|
272
|
-
);
|
|
273
|
-
break;
|
|
274
|
-
}
|
|
275
|
-
if (!this.continuePublishing(messageType)) {
|
|
276
|
-
logger.info(`Turned off live updates for ${messageType}`);
|
|
277
|
-
break;
|
|
278
|
-
}
|
|
279
|
-
await sleep(this.getLiveUpdatesInterval(messageType));
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
private continuePublishing(flag: string): boolean {
|
|
284
|
-
switch (flag) {
|
|
285
|
-
case keyMirrors.agentMessageType.device_stats:
|
|
286
|
-
case keyMirrors.agentMessageType.app_state:
|
|
287
|
-
return this.liveUpdatesAlive[flag];
|
|
288
|
-
case keyMirrors.agentMessageType.app_install_status:
|
|
289
|
-
return (
|
|
290
|
-
this.appInstallStatus.status ===
|
|
291
|
-
keyMirrors.appInstallStatus.in_progress
|
|
292
|
-
);
|
|
293
|
-
default:
|
|
294
|
-
logger.error(`Unrecognized publishable flag ${flag}`);
|
|
295
|
-
return false;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
private getLiveUpdatesInterval(flag: string): number {
|
|
300
|
-
const exists = this.liveUpdatesSleepIntervals[flag];
|
|
301
|
-
if (exists) {
|
|
302
|
-
return exists;
|
|
303
|
-
}
|
|
304
|
-
logger.error(`Unrecognized live updates flag ${flag}`);
|
|
305
|
-
return -1;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
private setLiveUpdates(toggles: LiveUpdatesToggles) {
|
|
309
|
-
if (toggles.deviceStats) {
|
|
310
|
-
this.liveUpdatesAlive.device_stats = toggles.deviceStats;
|
|
311
|
-
}
|
|
312
|
-
if (toggles.appState) {
|
|
313
|
-
this.liveUpdatesAlive.app_state = toggles.appState;
|
|
314
|
-
}
|
|
315
|
-
}
|
|
51
|
+
// FIXME: Add support for multiple simultaneous project updates
|
|
52
|
+
private newAppCfgQueue: AppConfig[] = [];
|
|
316
53
|
|
|
317
54
|
private handleAppStateControl(payload: AppStateControlPacket) {
|
|
318
55
|
const { baseCommand, projectId } = payload;
|
|
@@ -334,7 +71,7 @@ export class DeviceAgentCloudConnection {
|
|
|
334
71
|
const signedUrlsRequest = { projectId, appReleaseHash };
|
|
335
72
|
this.publishCloudRequest({
|
|
336
73
|
messageType: keyMirrors.agentMessageType.signed_urls_request,
|
|
337
|
-
signedUrlsRequest
|
|
74
|
+
signedUrlsRequest
|
|
338
75
|
});
|
|
339
76
|
}
|
|
340
77
|
|
|
@@ -345,7 +82,7 @@ export class DeviceAgentCloudConnection {
|
|
|
345
82
|
private handleAgentCommand(message: LiveUpdatesToggleMessage) {
|
|
346
83
|
switch (message.messageType) {
|
|
347
84
|
case keyMirrors.clientMessageType.live_state_updates:
|
|
348
|
-
this.
|
|
85
|
+
this.liveUpdatesHandler.update(message.liveUpdatesToggles);
|
|
349
86
|
break;
|
|
350
87
|
default:
|
|
351
88
|
logger.error(
|
|
@@ -354,91 +91,110 @@ export class DeviceAgentCloudConnection {
|
|
|
354
91
|
}
|
|
355
92
|
}
|
|
356
93
|
|
|
357
|
-
private
|
|
358
|
-
|
|
359
|
-
this.liveUpdatesTimeout = setTimeout(() => {
|
|
360
|
-
this.setLiveUpdates({
|
|
361
|
-
deviceStats: false,
|
|
362
|
-
appState: false,
|
|
363
|
-
});
|
|
364
|
-
this.appLogStreams.clear();
|
|
365
|
-
// TODO: Make constant, not hard coded
|
|
366
|
-
}, 600000); // 10 min
|
|
94
|
+
private async publishCloudRequest(payload: SignedUrlsRequestMessage) {
|
|
95
|
+
this.publisher.publishToCloud(payload);
|
|
367
96
|
}
|
|
368
97
|
|
|
369
|
-
private
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
}: {
|
|
374
|
-
deviceStats?: boolean;
|
|
375
|
-
appState?: boolean;
|
|
376
|
-
appLogs?: {
|
|
377
|
-
projectId: string;
|
|
378
|
-
toggle: boolean;
|
|
379
|
-
};
|
|
380
|
-
}) {
|
|
381
|
-
this.restartLiveUpdatesTimeout();
|
|
382
|
-
if (deviceStats !== undefined) {
|
|
383
|
-
this.liveUpdatesAlive.device_stats = deviceStats;
|
|
384
|
-
if (deviceStats) {
|
|
385
|
-
this.startPublishingLiveUpdates(
|
|
386
|
-
this.toClientTopic,
|
|
387
|
-
keyMirrors.agentMessageType.device_stats,
|
|
388
|
-
this.getDeviceStatsMessage
|
|
389
|
-
);
|
|
390
|
-
}
|
|
391
|
-
}
|
|
98
|
+
private subscribe(topic: string) {
|
|
99
|
+
logger.info(`Subscribing to ${topic}`);
|
|
100
|
+
this.device.subscribe(topic);
|
|
101
|
+
}
|
|
392
102
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
103
|
+
// eslint-disable-next-line
|
|
104
|
+
private async atomicApplicationUpdate<T extends any[], R extends any>(
|
|
105
|
+
func: (...args: T) => R,
|
|
106
|
+
args: T,
|
|
107
|
+
projectId: string,
|
|
108
|
+
appReleaseHash: string
|
|
109
|
+
) {
|
|
110
|
+
this.appInstallStatusMgr.update(
|
|
111
|
+
appReleaseHash,
|
|
112
|
+
keyMirrors.appInstallStatus.in_progress
|
|
113
|
+
);
|
|
403
114
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
115
|
+
this.liveUpdatesHandler.update({
|
|
116
|
+
appInstallStatus: { toggle: true, appReleaseHash }
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// Install the app and models
|
|
120
|
+
try {
|
|
121
|
+
const out: R = await func(...args);
|
|
122
|
+
this.appInstallStatusMgr.update(
|
|
123
|
+
appReleaseHash,
|
|
124
|
+
keyMirrors.appInstallStatus.success
|
|
125
|
+
);
|
|
126
|
+
this.liveUpdatesHandler.update({
|
|
127
|
+
appInstallStatus: { toggle: false, appReleaseHash }
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// update app config shadow for project
|
|
131
|
+
await this.shadowHandler.publishAppState(projectId);
|
|
132
|
+
return out;
|
|
133
|
+
} catch (e) {
|
|
134
|
+
logger.error(e);
|
|
135
|
+
const message: string = e.message;
|
|
136
|
+
|
|
137
|
+
// uninstall the failed app to put system back in good state
|
|
138
|
+
await uninstallApp({ projectId });
|
|
139
|
+
this.appInstallStatusMgr.update(
|
|
140
|
+
appReleaseHash,
|
|
141
|
+
keyMirrors.appInstallStatus.failure,
|
|
142
|
+
message
|
|
143
|
+
);
|
|
144
|
+
this.liveUpdatesHandler.update({
|
|
145
|
+
appInstallStatus: { toggle: false, appReleaseHash }
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// delete shadow for project
|
|
149
|
+
// FIXME: Why do we delete the shadow? Doesn't this delete it for all projects?
|
|
150
|
+
this.shadowHandler.deleteProjectShadow();
|
|
410
151
|
}
|
|
411
152
|
}
|
|
412
153
|
|
|
413
|
-
private async
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
154
|
+
private async handleAppConfigUpdates(appConfgUpdates: AppConfigUpdate[]) {
|
|
155
|
+
for (const appConfigUpdate of appConfgUpdates) {
|
|
156
|
+
const { projectId, newAppCfg, updatedModels } = appConfigUpdate;
|
|
157
|
+
if (updatedModels && Object.keys(updatedModels).length) {
|
|
158
|
+
// Publish request for model urls
|
|
159
|
+
this.newAppCfgQueue.push(newAppCfg);
|
|
160
|
+
|
|
161
|
+
logger.debug(
|
|
162
|
+
`Requesting presigned urls from cloud for model versions: ${JSON.stringify(
|
|
163
|
+
updatedModels
|
|
164
|
+
)}`
|
|
165
|
+
);
|
|
166
|
+
this.publisher.publishToCloud({
|
|
167
|
+
messageType: keyMirrors.agentMessageType.signed_urls_request,
|
|
168
|
+
modelsOnlyUrlsRequest: {
|
|
169
|
+
projectId,
|
|
170
|
+
models: updatedModels
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
} else {
|
|
174
|
+
// FIXME: do we need to send this up to the cloud?
|
|
175
|
+
// should it be something other than appReleaseHash?
|
|
176
|
+
const appReleaseHash = await AgentConfigFile().getAppVersion({
|
|
177
|
+
projectId
|
|
178
|
+
});
|
|
427
179
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
180
|
+
await this.atomicApplicationUpdate(
|
|
181
|
+
updateAppCfg,
|
|
182
|
+
[
|
|
183
|
+
{
|
|
184
|
+
projectId,
|
|
185
|
+
appReleaseHash,
|
|
186
|
+
newAppCfg
|
|
187
|
+
}
|
|
188
|
+
],
|
|
189
|
+
projectId,
|
|
190
|
+
appReleaseHash
|
|
191
|
+
);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
436
194
|
}
|
|
437
195
|
|
|
438
196
|
// Public Methods
|
|
439
197
|
|
|
440
|
-
public device = awsIot.device;
|
|
441
|
-
|
|
442
198
|
constructor() {
|
|
443
199
|
this.device = awsIot.device({
|
|
444
200
|
keyPath: getPrivateKeyFilePath(),
|
|
@@ -447,25 +203,28 @@ export class DeviceAgentCloudConnection {
|
|
|
447
203
|
clientId: this.clientId,
|
|
448
204
|
host: this.host,
|
|
449
205
|
port: 8883,
|
|
206
|
+
keepalive: 1 // time before re-connect attempt on dropped connection, default is 400 seconds
|
|
450
207
|
});
|
|
208
|
+
this.publisher = new Publisher(this.device, this.clientId);
|
|
209
|
+
this.shadowHandler = new ShadowHandler(this.clientId, this.publisher);
|
|
210
|
+
this.appInstallStatusMgr = new AppInstallStatusManager();
|
|
211
|
+
this.liveUpdatesHandler = new LiveUpdatesHandler(
|
|
212
|
+
this.publisher,
|
|
213
|
+
this.appInstallStatusMgr
|
|
214
|
+
);
|
|
451
215
|
|
|
452
|
-
this.
|
|
453
|
-
this.
|
|
454
|
-
this.
|
|
216
|
+
this.subscribe(this.toDeviceTopic);
|
|
217
|
+
this.subscribe(this.shadowHandler.shadowTopics.projects.getAccepted);
|
|
218
|
+
this.subscribe(this.shadowHandler.shadowTopics.projects.updateDelta);
|
|
455
219
|
}
|
|
456
220
|
|
|
457
221
|
public getClientId(): string {
|
|
458
222
|
return this.clientId;
|
|
459
223
|
}
|
|
460
224
|
|
|
461
|
-
public publishMessage(topic: string, message: string) {
|
|
462
|
-
// TODO: topic validation
|
|
463
|
-
this.device.publish(topic, message, (err: any) => {});
|
|
464
|
-
}
|
|
465
|
-
|
|
466
225
|
public async handleClientMessage({
|
|
467
226
|
topic,
|
|
468
|
-
message
|
|
227
|
+
message
|
|
469
228
|
}: {
|
|
470
229
|
topic: string;
|
|
471
230
|
message: ClientMessage;
|
|
@@ -489,175 +248,145 @@ export class DeviceAgentCloudConnection {
|
|
|
489
248
|
projectId,
|
|
490
249
|
appReleaseHash,
|
|
491
250
|
appInstallPayload,
|
|
492
|
-
modelsInstallPayload
|
|
251
|
+
modelsInstallPayload
|
|
493
252
|
} = payload.appInstallCloudResponse;
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
this.getAppInstallStatusMessage
|
|
253
|
+
const signedUrlsPayload = {
|
|
254
|
+
appInstallPayload,
|
|
255
|
+
modelsInstallPayload
|
|
256
|
+
};
|
|
257
|
+
await this.atomicApplicationUpdate(
|
|
258
|
+
installApp,
|
|
259
|
+
[{ projectId, appReleaseHash, signedUrlsPayload }],
|
|
260
|
+
projectId,
|
|
261
|
+
appReleaseHash
|
|
504
262
|
);
|
|
505
263
|
|
|
506
|
-
// Install the app and models
|
|
507
|
-
try {
|
|
508
|
-
const signedUrlsPayload = {
|
|
509
|
-
appInstallPayload,
|
|
510
|
-
modelsInstallPayload,
|
|
511
|
-
};
|
|
512
|
-
await installApp({
|
|
513
|
-
projectId,
|
|
514
|
-
appReleaseHash,
|
|
515
|
-
signedUrlsPayload,
|
|
516
|
-
});
|
|
517
|
-
this.updateAppInstallStatus({
|
|
518
|
-
status: keyMirrors.appInstallStatus.success,
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
// update app config shadow for project
|
|
522
|
-
await this.publishReportedState(projectId);
|
|
523
|
-
} catch (e) {
|
|
524
|
-
logger.error(e);
|
|
525
|
-
const message: string = e.message;
|
|
526
|
-
|
|
527
|
-
// uninstall the failed app to put system back in good state
|
|
528
|
-
await uninstallApp({ projectId });
|
|
529
|
-
this.updateAppInstallStatus({
|
|
530
|
-
status: keyMirrors.appInstallStatus.failure,
|
|
531
|
-
message,
|
|
532
|
-
});
|
|
533
|
-
|
|
534
|
-
// delete shadow for project
|
|
535
|
-
this.publishMessage(`${this.shadowPrefix}${projectId}/delete`, "");
|
|
536
|
-
}
|
|
537
264
|
break;
|
|
538
265
|
}
|
|
539
266
|
case keyMirrors.clientMessageType.models_install_cloud_response: {
|
|
540
267
|
const { projectId, newModels } = payload.modelsInstallCloudResponse;
|
|
268
|
+
const appReleaseHash = await AgentConfigFile().getAppVersion({
|
|
269
|
+
projectId
|
|
270
|
+
});
|
|
541
271
|
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
logger.error(e);
|
|
272
|
+
const newAppCfg = this.newAppCfgQueue.shift();
|
|
273
|
+
if (newAppCfg === undefined) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
'Unknown error while updating models via application config! No config present for model update.'
|
|
276
|
+
);
|
|
548
277
|
}
|
|
278
|
+
|
|
279
|
+
await this.atomicApplicationUpdate(
|
|
280
|
+
updateModelsWithPresignedUrls,
|
|
281
|
+
[
|
|
282
|
+
{
|
|
283
|
+
projectId,
|
|
284
|
+
modelInstallPayloads: newModels,
|
|
285
|
+
newAppCfg,
|
|
286
|
+
appReleaseHash
|
|
287
|
+
}
|
|
288
|
+
],
|
|
289
|
+
projectId,
|
|
290
|
+
appReleaseHash
|
|
291
|
+
);
|
|
292
|
+
|
|
549
293
|
break;
|
|
550
294
|
}
|
|
551
295
|
default:
|
|
552
|
-
logger.error(
|
|
296
|
+
logger.error(
|
|
297
|
+
`Invalid client message: '${JSON.stringify(
|
|
298
|
+
{ topic, message },
|
|
299
|
+
null,
|
|
300
|
+
2
|
|
301
|
+
)}'`
|
|
302
|
+
);
|
|
553
303
|
}
|
|
554
304
|
}
|
|
555
305
|
|
|
556
|
-
public async
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
}: {
|
|
560
|
-
topic: string;
|
|
561
|
-
payload: string;
|
|
562
|
-
}) {
|
|
563
|
-
const shadowName = topic.split("/")[5];
|
|
564
|
-
const message = JSON.parse(payload);
|
|
565
|
-
if (topic === this.shadowTopics.projects.updateDelta) {
|
|
566
|
-
this.handleNamedShadowUpdate({ payload });
|
|
567
|
-
} else if (topic === this.shadowTopics.projects.getAccepted) {
|
|
568
|
-
if (message.delta) {
|
|
569
|
-
this.handleNamedShadowUpdate({
|
|
570
|
-
payload: JSON.stringify(message.delta),
|
|
571
|
-
});
|
|
572
|
-
} else {
|
|
573
|
-
logger.info(`No delta updates in shadow ${shadowName}`);
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
306
|
+
public async setupHandlers() {
|
|
307
|
+
this.device.on('connect', (connack: any) => {
|
|
308
|
+
logger.info('Device Agent has connected to the cloud');
|
|
578
309
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
{
|
|
583
|
-
const deviceAgent = new DeviceAgentCloudConnection();
|
|
584
|
-
|
|
585
|
-
deviceAgent.device.on("connect", function (connack: any) {
|
|
586
|
-
logger.info("Device Agent has connected to the cloud");
|
|
587
|
-
|
|
588
|
-
// Get shadow updates
|
|
589
|
-
deviceAgent.publishMessage(
|
|
590
|
-
`${deviceAgent.getShadowPrefix()}projects/get`,
|
|
591
|
-
""
|
|
592
|
-
);
|
|
593
|
-
});
|
|
310
|
+
// Get shadow updates
|
|
311
|
+
this.shadowHandler.getShadowUpdates();
|
|
312
|
+
});
|
|
594
313
|
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
314
|
+
this.device.on('disconnect', () => {
|
|
315
|
+
logger.warn('Device Agent has been disconnected from the cloud');
|
|
316
|
+
});
|
|
598
317
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
});
|
|
611
|
-
} else {
|
|
612
|
-
const valid = validateClientMessage(jsonPacket);
|
|
613
|
-
if (!valid) {
|
|
614
|
-
console.error(JSON.stringify(validateClientMessage.errors));
|
|
615
|
-
} else {
|
|
616
|
-
deviceAgent.handleClientMessage({
|
|
617
|
-
topic,
|
|
618
|
-
message: jsonPacket,
|
|
619
|
-
});
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
} catch (error) {
|
|
623
|
-
logger.error(error);
|
|
624
|
-
}
|
|
625
|
-
}
|
|
318
|
+
this.device.on('reconnect', () => {
|
|
319
|
+
logger.info(
|
|
320
|
+
`Device Agent attempting to re-connect ${new Date().toLocaleString()}`
|
|
321
|
+
);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
this.device.on('message', async (topic: string, payload: string) => {
|
|
325
|
+
try {
|
|
326
|
+
const jsonPacket = JSON.parse(payload);
|
|
327
|
+
logger.debug(
|
|
328
|
+
`Received message: ${JSON.stringify({ topic, jsonPacket }, null, 2)}`
|
|
626
329
|
);
|
|
627
330
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
331
|
+
if (Object.prototype.hasOwnProperty.call(jsonPacket, 'state')) {
|
|
332
|
+
if (jsonPacket.clientToken === this.getClientId()) {
|
|
333
|
+
logger.debug(
|
|
334
|
+
`Ignoring message sent from self: ${JSON.stringify(
|
|
335
|
+
{ topic, jsonPacket },
|
|
336
|
+
null,
|
|
337
|
+
2
|
|
338
|
+
)}`
|
|
339
|
+
);
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
632
342
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
343
|
+
const appConfigUpdates = await this.shadowHandler.handleShadowTopic({
|
|
344
|
+
topic,
|
|
345
|
+
payload: jsonPacket.state
|
|
346
|
+
});
|
|
347
|
+
await this.handleAppConfigUpdates(appConfigUpdates);
|
|
348
|
+
} else {
|
|
349
|
+
const valid = validateClientMessage(jsonPacket);
|
|
350
|
+
if (!valid) {
|
|
351
|
+
logger.error(
|
|
352
|
+
`Error validating message: ${JSON.stringify(
|
|
353
|
+
validateClientMessage.errors,
|
|
354
|
+
null,
|
|
355
|
+
2
|
|
356
|
+
)}`
|
|
357
|
+
);
|
|
358
|
+
} else {
|
|
359
|
+
this.handleClientMessage({
|
|
360
|
+
topic,
|
|
361
|
+
message: jsonPacket
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
} catch (error) {
|
|
366
|
+
logger.error(`Error parsing message: ${error}`);
|
|
367
|
+
}
|
|
368
|
+
});
|
|
653
369
|
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
370
|
+
this.device.on('offline', () => {
|
|
371
|
+
logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
}
|
|
657
375
|
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
376
|
+
export async function runDeviceAgentCloudInterface() {
|
|
377
|
+
// FIXME: Check for KeyPath as well
|
|
378
|
+
if (existsSync(getCertificateFilePath())) {
|
|
379
|
+
const deviceAgent = new DeviceAgentCloudConnection();
|
|
380
|
+
await deviceAgent.setupHandlers();
|
|
381
|
+
} else if (existsSync(BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH())) {
|
|
382
|
+
bootstrapProvision();
|
|
383
|
+
} else if (existsSync(BOOTSTRAP_CERTIFICATES_DIR_PATH())) {
|
|
384
|
+
throw new Error(
|
|
385
|
+
"Device has not been created using 'aai-agent device init' or there has been an issue with device initialization"
|
|
386
|
+
);
|
|
387
|
+
} else {
|
|
388
|
+
throw new Error(
|
|
389
|
+
"Set device agent to local mode and retry the 'aai-agent device init' command"
|
|
390
|
+
);
|
|
662
391
|
}
|
|
663
392
|
}
|