@alwaysai/device-agent 0.0.10 → 0.0.12

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.
Files changed (76) hide show
  1. package/lib/application-control/backup.d.ts.map +1 -1
  2. package/lib/application-control/backup.js +4 -3
  3. package/lib/application-control/backup.js.map +1 -1
  4. package/lib/application-control/install.d.ts.map +1 -1
  5. package/lib/application-control/install.js +6 -5
  6. package/lib/application-control/install.js.map +1 -1
  7. package/lib/application-control/models.d.ts.map +1 -1
  8. package/lib/application-control/models.js +3 -2
  9. package/lib/application-control/models.js.map +1 -1
  10. package/lib/application-control/status.d.ts.map +1 -1
  11. package/lib/application-control/status.js +6 -5
  12. package/lib/application-control/status.js.map +1 -1
  13. package/lib/application-control/utils.d.ts.map +1 -1
  14. package/lib/application-control/utils.js +3 -2
  15. package/lib/application-control/utils.js.map +1 -1
  16. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +3 -4
  17. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  18. package/lib/cloud-connection/device-agent-cloud-connection.js +89 -50
  19. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  20. package/lib/cloud-connection/device-agent.d.ts +21 -0
  21. package/lib/cloud-connection/device-agent.d.ts.map +1 -0
  22. package/lib/cloud-connection/device-agent.js +69 -0
  23. package/lib/cloud-connection/device-agent.js.map +1 -0
  24. package/lib/endpoints.d.ts +3 -0
  25. package/lib/endpoints.d.ts.map +1 -0
  26. package/lib/endpoints.js +28 -0
  27. package/lib/endpoints.js.map +1 -0
  28. package/lib/environment.d.ts +1 -0
  29. package/lib/environment.d.ts.map +1 -1
  30. package/lib/environment.js +2 -1
  31. package/lib/environment.js.map +1 -1
  32. package/lib/index.js +2 -1
  33. package/lib/index.js.map +1 -1
  34. package/lib/infrastructure/certificates-and-tokens.d.ts +1 -1
  35. package/lib/infrastructure/certificates-and-tokens.d.ts.map +1 -1
  36. package/lib/infrastructure/certificates-and-tokens.js +13 -39
  37. package/lib/infrastructure/certificates-and-tokens.js.map +1 -1
  38. package/lib/subcommands/app/app.d.ts.map +1 -1
  39. package/lib/subcommands/app/app.js +6 -5
  40. package/lib/subcommands/app/app.js.map +1 -1
  41. package/lib/subcommands/device/device.d.ts.map +1 -1
  42. package/lib/subcommands/device/device.js +31 -22
  43. package/lib/subcommands/device/device.js.map +1 -1
  44. package/lib/subcommands/get-model-package.d.ts.map +1 -1
  45. package/lib/subcommands/get-model-package.js +2 -1
  46. package/lib/subcommands/get-model-package.js.map +1 -1
  47. package/lib/util/directories.d.ts +15 -0
  48. package/lib/util/directories.d.ts.map +1 -1
  49. package/lib/util/directories.js +19 -4
  50. package/lib/util/directories.js.map +1 -1
  51. package/lib/util/http-client.d.ts +3 -0
  52. package/lib/util/http-client.d.ts.map +1 -0
  53. package/lib/util/http-client.js +30 -0
  54. package/lib/util/http-client.js.map +1 -0
  55. package/lib/util/logger.d.ts +4 -0
  56. package/lib/util/logger.d.ts.map +1 -0
  57. package/lib/util/logger.js +25 -0
  58. package/lib/util/logger.js.map +1 -0
  59. package/package.json +3 -2
  60. package/src/application-control/backup.ts +4 -3
  61. package/src/application-control/install.ts +6 -5
  62. package/src/application-control/models.ts +4 -3
  63. package/src/application-control/status.ts +6 -5
  64. package/src/application-control/utils.ts +3 -2
  65. package/src/cloud-connection/device-agent-cloud-connection.ts +177 -81
  66. package/src/cloud-connection/device-agent.ts +122 -0
  67. package/src/endpoints.ts +24 -0
  68. package/src/environment.ts +1 -0
  69. package/src/index.ts +2 -1
  70. package/src/infrastructure/certificates-and-tokens.ts +31 -49
  71. package/src/subcommands/app/app.ts +6 -5
  72. package/src/subcommands/device/device.ts +67 -30
  73. package/src/subcommands/get-model-package.ts +2 -1
  74. package/src/util/directories.ts +49 -6
  75. package/src/util/http-client.ts +35 -0
  76. package/src/util/logger.ts +28 -0
@@ -1,23 +1,32 @@
1
- const awsIot = require('aws-iot-device-sdk');
2
- import { getIoTCoreEndpointUrl } from '../infrastructure/urls';
1
+ const awsIot = require("aws-iot-device-sdk");
2
+ import { getIoTCoreEndpointUrl } from "../infrastructure/urls";
3
+ import { existsSync, createReadStream } from "fs";
3
4
  import {
4
5
  getPrivateKeyFilePath,
5
6
  getCertificateFilePath,
6
7
  getRootCertificateFilePath,
7
- } from '../util/directories';
8
- import sleep from '../util/sleep';
8
+ BOOTSTRAP_CLAIM_ID_FILE_PATH,
9
+ DEVICE_CLAIM_ID_FILE_PATH,
10
+ BOOTSTRAP_DEVICE_CERTIFICATE_FILE_PATH,
11
+ BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH,
12
+ AWS_ROOT_CERTIFICATE_FILE_PATH,
13
+ } from "../util/directories";
14
+
15
+ import { BootstrapAgent } from "./device-agent";
16
+
17
+ import sleep from "../util/sleep";
9
18
  import {
10
19
  startApp,
11
20
  stopApp,
12
21
  restartApp,
13
22
  getAppLogs,
14
23
  getAppStatus,
15
- } from '../application-control/status';
24
+ } from "../application-control/status";
16
25
  import {
17
26
  getInstalledApps,
18
27
  installApp,
19
28
  uninstallApp,
20
- } from '../application-control/install';
29
+ } from "../application-control/install";
21
30
  import {
22
31
  keyMirrors,
23
32
  validateClientMessage,
@@ -37,14 +46,25 @@ import {
37
46
  DeviceAgentMessage,
38
47
  ClientMessage,
39
48
  AppDetailsPacket,
40
- } from '@alwaysai/device-agent-schemas';
41
- import { getDeviceId } from '../util/get-device-id';
42
- import { JsSpawner, logger } from 'alwaysai/lib/util';
43
- import { getCpuUtil, getDiskUtil, getMemUtil } from '../device-control/device-control';
44
- import { AgentConfigFile } from '../infrastructure/agent-config';
45
- import { buildApp, getAppConfig, getAppDir } from '../application-control/utils';
46
- import { updateModelsWithPresignedUrls } from '../application-control/models';
47
- import { updateAppConfig } from '../application-control/config';
49
+ getClientTopic,
50
+ getCloudTopic,
51
+ getDeviceTopic,
52
+ } from "@alwaysai/device-agent-schemas";
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";
61
+ import {
62
+ buildApp,
63
+ getAppConfig,
64
+ getAppDir,
65
+ } from "../application-control/utils";
66
+ import { updateModelsWithPresignedUrls } from "../application-control/models";
67
+ import { updateAppConfig } from "../application-control/config";
48
68
 
49
69
  export class DeviceAgentCloudConnection {
50
70
  private clientId = getDeviceId();
@@ -63,7 +83,6 @@ export class DeviceAgentCloudConnection {
63
83
  [keyMirrors.agentMessageType.app_install_status]: 5000,
64
84
  };
65
85
  private appLogStreams = new Set<string>();
66
- private deviceType = 'aai-device';
67
86
  private readonly shadowPrefix = `$aws/things/${this.clientId}/shadow/name/`;
68
87
  private readonly shadowTopics = {
69
88
  projects: {
@@ -71,9 +90,9 @@ export class DeviceAgentCloudConnection {
71
90
  getAccepted: `${this.shadowPrefix}projects/get/accepted`,
72
91
  },
73
92
  };
74
- private readonly toCloudTopic = `topic/to_cloud/${this.deviceType}/${this.clientId}`;
75
- private readonly toClientTopic = `topic/to_client/${this.deviceType}/${this.clientId}`;
76
- private readonly toDeviceTopic = `topic/to_device/${this.deviceType}/${this.clientId}`;
93
+ private readonly toCloudTopic = getCloudTopic(this.clientId);
94
+ private readonly toClientTopic = getClientTopic(this.clientId);
95
+ private readonly toDeviceTopic = getDeviceTopic(this.clientId);
77
96
 
78
97
  // device shadow utils
79
98
 
@@ -123,9 +142,9 @@ export class DeviceAgentCloudConnection {
123
142
  this.appLogStreams.add(projectId);
124
143
  const readable = await getAppLogs({
125
144
  projectId,
126
- args: ['--tail', '100', '--no-log-prefix'],
145
+ args: ["--tail", "100", "--no-log-prefix"],
127
146
  });
128
- readable.on('data', (chunk: Buffer) => {
147
+ readable.on("data", (chunk: Buffer) => {
129
148
  if (!this.appLogStreams.has(projectId)) {
130
149
  // why doesn't typescript know about this function?
131
150
  // @ts-ignore
@@ -144,16 +163,18 @@ export class DeviceAgentCloudConnection {
144
163
  const packet = this.buildMessagePacket(
145
164
  this.getClientId(),
146
165
  this.toClientTopic,
147
- message,
166
+ message
148
167
  );
149
168
  this.publishMessage(this.toClientTopic, JSON.stringify(packet));
150
169
  });
151
170
 
152
- readable.on('error', (error) => {
153
- logger.error(`App log stream terminated for project ${projectId}: ${error}`);
171
+ readable.on("error", (error) => {
172
+ logger.error(
173
+ `App log stream terminated for project ${projectId}: ${error}`
174
+ );
154
175
  });
155
176
 
156
- readable.on('finished', () => {
177
+ readable.on("finished", () => {
157
178
  logger.info(`App logs finished piping for project ${projectId}`);
158
179
  });
159
180
  }
@@ -164,7 +185,7 @@ export class DeviceAgentCloudConnection {
164
185
  }
165
186
 
166
187
  private updateAppInstallStatus(
167
- installationStatus: Omit<AppInstallStatusPacket, 'appReleaseHash'>,
188
+ installationStatus: Omit<AppInstallStatusPacket, "appReleaseHash">
168
189
  ) {
169
190
  this.appInstallStatus.status = installationStatus.status;
170
191
  this.appInstallStatus.message = installationStatus.message;
@@ -178,7 +199,7 @@ export class DeviceAgentCloudConnection {
178
199
  private buildMessagePacket(
179
200
  deviceId: string,
180
201
  topic: string,
181
- payload: DeviceAgentMessagePayload,
202
+ payload: DeviceAgentMessagePayload
182
203
  ): DeviceAgentMessage {
183
204
  const packet = {
184
205
  timestamp: new Date().toUTCString(),
@@ -221,27 +242,34 @@ export class DeviceAgentCloudConnection {
221
242
  }
222
243
 
223
244
  // must be arrow function due to this context when function is passed as param
224
- private getAppInstallStatusMessage = async (): Promise<AppInstallStatusMessage> => {
225
- const appInstallStatus = this.getAppInstallStatus();
226
- const appInstallStatusMessage = {
227
- messageType: keyMirrors.agentMessageType.app_install_status,
228
- appInstallStatus,
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;
229
253
  };
230
- return appInstallStatusMessage;
231
- };
232
254
 
233
255
  private async startPublishingLiveUpdates(
234
256
  topic: string,
235
257
  messageType: string,
236
- getMessageData: () => Promise<DeviceAgentMessagePayload>,
258
+ getMessageData: () => Promise<DeviceAgentMessagePayload>
237
259
  ) {
238
260
  while (true) {
239
261
  try {
240
262
  const message = await getMessageData();
241
- const packet = this.buildMessagePacket(this.getClientId(), topic, message);
263
+ const packet = this.buildMessagePacket(
264
+ this.getClientId(),
265
+ topic,
266
+ message
267
+ );
242
268
  this.publishMessage(topic, JSON.stringify(packet));
243
269
  } catch (e) {
244
- logger.error(`Error publishing live updates for ${messageType}: ${e.message}`);
270
+ logger.error(
271
+ `Error publishing live updates for ${messageType}: ${e.message}`
272
+ );
245
273
  break;
246
274
  }
247
275
  if (!this.continuePublishing(messageType)) {
@@ -258,7 +286,10 @@ export class DeviceAgentCloudConnection {
258
286
  case keyMirrors.agentMessageType.app_state:
259
287
  return this.liveUpdatesAlive[flag];
260
288
  case keyMirrors.agentMessageType.app_install_status:
261
- return this.appInstallStatus.status === keyMirrors.appInstallStatus.in_progress;
289
+ return (
290
+ this.appInstallStatus.status ===
291
+ keyMirrors.appInstallStatus.in_progress
292
+ );
262
293
  default:
263
294
  logger.error(`Unrecognized publishable flag ${flag}`);
264
295
  return false;
@@ -317,7 +348,9 @@ export class DeviceAgentCloudConnection {
317
348
  this.liveUpdatesBroker(message.liveUpdatesToggles);
318
349
  break;
319
350
  default:
320
- logger.error(`Invalid agent action message type from message '${message}'`);
351
+ logger.error(
352
+ `Invalid agent action message type from message '${message}'`
353
+ );
321
354
  }
322
355
  }
323
356
 
@@ -352,7 +385,7 @@ export class DeviceAgentCloudConnection {
352
385
  this.startPublishingLiveUpdates(
353
386
  this.toClientTopic,
354
387
  keyMirrors.agentMessageType.device_stats,
355
- this.getDeviceStatsMessage,
388
+ this.getDeviceStatsMessage
356
389
  );
357
390
  }
358
391
  }
@@ -363,7 +396,7 @@ export class DeviceAgentCloudConnection {
363
396
  this.startPublishingLiveUpdates(
364
397
  this.toClientTopic,
365
398
  keyMirrors.agentMessageType.app_state,
366
- this.getAppStateMessage,
399
+ this.getAppStateMessage
367
400
  );
368
401
  }
369
402
  }
@@ -386,7 +419,10 @@ export class DeviceAgentCloudConnection {
386
419
  },
387
420
  },
388
421
  };
389
- this.publishMessage(`${this.shadowPrefix}projects/update`, JSON.stringify(packet));
422
+ this.publishMessage(
423
+ `${this.shadowPrefix}projects/update`,
424
+ JSON.stringify(packet)
425
+ );
390
426
  }
391
427
 
392
428
  private async publishCloudRequest(payload: SignedUrlsRequestMessage) {
@@ -394,7 +430,7 @@ export class DeviceAgentCloudConnection {
394
430
  const deviceRequestPacket = this.buildMessagePacket(
395
431
  this.getClientId(),
396
432
  topic,
397
- payload,
433
+ payload
398
434
  );
399
435
  this.publishMessage(topic, JSON.stringify({ deviceRequestPacket }));
400
436
  }
@@ -407,9 +443,10 @@ export class DeviceAgentCloudConnection {
407
443
  this.device = awsIot.device({
408
444
  keyPath: getPrivateKeyFilePath(),
409
445
  certPath: getCertificateFilePath(),
410
- caPath: getRootCertificateFilePath(),
446
+ caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
411
447
  clientId: this.clientId,
412
448
  host: this.host,
449
+ port: 8883,
413
450
  });
414
451
 
415
452
  this.device.subscribe(this.toDeviceTopic);
@@ -423,7 +460,7 @@ export class DeviceAgentCloudConnection {
423
460
 
424
461
  public publishMessage(topic: string, message: string) {
425
462
  // TODO: topic validation
426
- this.device.publish(topic, message);
463
+ this.device.publish(topic, message, (err: any) => {});
427
464
  }
428
465
 
429
466
  public async handleClientMessage({
@@ -448,8 +485,12 @@ export class DeviceAgentCloudConnection {
448
485
  break;
449
486
  }
450
487
  case keyMirrors.clientMessageType.app_install_cloud_response: {
451
- const { projectId, appReleaseHash, appInstallPayload, modelsInstallPayload } =
452
- payload.appInstallCloudResponse;
488
+ const {
489
+ projectId,
490
+ appReleaseHash,
491
+ appInstallPayload,
492
+ modelsInstallPayload,
493
+ } = payload.appInstallCloudResponse;
453
494
 
454
495
  this.initAppInstallStatus({
455
496
  status: keyMirrors.appInstallStatus.in_progress,
@@ -459,7 +500,7 @@ export class DeviceAgentCloudConnection {
459
500
  this.startPublishingLiveUpdates(
460
501
  this.toClientTopic,
461
502
  keyMirrors.agentMessageType.app_install_status,
462
- this.getAppInstallStatusMessage,
503
+ this.getAppInstallStatusMessage
463
504
  );
464
505
 
465
506
  // Install the app and models
@@ -480,7 +521,7 @@ export class DeviceAgentCloudConnection {
480
521
  // update app config shadow for project
481
522
  await this.publishReportedState(projectId);
482
523
  } catch (e) {
483
- console.error(e);
524
+ logger.error(e);
484
525
  const message: string = e.message;
485
526
 
486
527
  // uninstall the failed app to put system back in good state
@@ -491,7 +532,7 @@ export class DeviceAgentCloudConnection {
491
532
  });
492
533
 
493
534
  // delete shadow for project
494
- this.publishMessage(`${this.shadowPrefix}${projectId}/delete`, '');
535
+ this.publishMessage(`${this.shadowPrefix}${projectId}/delete`, "");
495
536
  }
496
537
  break;
497
538
  }
@@ -503,7 +544,7 @@ export class DeviceAgentCloudConnection {
503
544
 
504
545
  await this.publishReportedState(projectId);
505
546
  } catch (e) {
506
- console.error(e);
547
+ logger.error(e);
507
548
  }
508
549
  break;
509
550
  }
@@ -512,8 +553,14 @@ export class DeviceAgentCloudConnection {
512
553
  }
513
554
  }
514
555
 
515
- public async handleShadowTopic({ topic, payload }: { topic: string; payload: string }) {
516
- const shadowName = topic.split('/')[5];
556
+ public async handleShadowTopic({
557
+ topic,
558
+ payload,
559
+ }: {
560
+ topic: string;
561
+ payload: string;
562
+ }) {
563
+ const shadowName = topic.split("/")[5];
517
564
  const message = JSON.parse(payload);
518
565
  if (topic === this.shadowTopics.projects.updateDelta) {
519
566
  this.handleNamedShadowUpdate({ payload });
@@ -523,45 +570,94 @@ export class DeviceAgentCloudConnection {
523
570
  payload: JSON.stringify(message.delta),
524
571
  });
525
572
  } else {
526
- console.log(`No delta updates in shadow ${shadowName}`);
573
+ logger.info(`No delta updates in shadow ${shadowName}`);
527
574
  }
528
575
  }
529
576
  }
530
577
  }
531
578
 
532
- export function runDeviceAgentCloudInterface() {
533
- const deviceAgent = new DeviceAgentCloudConnection();
579
+ export async function runDeviceAgentCloudInterface() {
580
+ switch (existsSync(getCertificateFilePath())) {
581
+ case true:
582
+ {
583
+ const deviceAgent = new DeviceAgentCloudConnection();
534
584
 
535
- deviceAgent.device.on('connect', function () {
536
- deviceAgent.publishMessage('connection', deviceAgent.getClientId());
537
- console.log('Device Agent has connected to the cloud');
585
+ deviceAgent.device.on("connect", function (connack: any) {
586
+ logger.info("Device Agent has connected to the cloud");
538
587
 
539
- // Get shadow updates
540
- deviceAgent.publishMessage(`${deviceAgent.getShadowPrefix()}projects/get`, '');
541
- });
588
+ // Get shadow updates
589
+ deviceAgent.publishMessage(
590
+ `${deviceAgent.getShadowPrefix()}projects/get`,
591
+ ""
592
+ );
593
+ });
542
594
 
543
- deviceAgent.device.on('disconnect', function () {
544
- console.log('Device Agent has been disconnected from the cloud');
545
- });
595
+ deviceAgent.device.on("disconnect", function () {
596
+ logger.info("Device Agent has been disconnected from the cloud");
597
+ });
546
598
 
547
- deviceAgent.device.on('message', function (topic: string, payload: string) {
548
- try {
549
- const jsonPacket = JSON.parse(payload);
550
- if (jsonPacket.hasOwnProperty('state')) {
551
- deviceAgent.handleShadowTopic({
552
- topic,
553
- payload: JSON.stringify(jsonPacket.state),
599
+ deviceAgent.device.on(
600
+ "message",
601
+ function (topic: string, payload: string) {
602
+ console.log(topic);
603
+ console.log(JSON.parse(payload));
604
+ try {
605
+ const jsonPacket = JSON.parse(payload);
606
+ if (jsonPacket.hasOwnProperty("state")) {
607
+ deviceAgent.handleShadowTopic({
608
+ topic,
609
+ payload: JSON.stringify(jsonPacket.state),
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
+ }
626
+ );
627
+
628
+ deviceAgent.device.on("packetsend", (packet: any) => {
629
+ console.log({ packet: packet });
554
630
  });
555
- } else {
556
- const valid = validateClientMessage(jsonPacket);
557
- if (!valid) {
558
- console.error(JSON.stringify(validateClientMessage.errors));
559
- } else {
560
- deviceAgent.handleClientMessage({ topic, message: jsonPacket });
561
- }
562
631
  }
563
- } catch (error) {
564
- console.error(error);
632
+
633
+ break;
634
+ case false: {
635
+ //set timer
636
+ const clientId = getDeviceId();
637
+ const bootstrapConfig = {
638
+ keyPath: BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH,
639
+ certPath: BOOTSTRAP_DEVICE_CERTIFICATE_FILE_PATH,
640
+ caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
641
+ clientId,
642
+ host: getIoTCoreEndpointUrl(),
643
+ };
644
+
645
+ const bootstrapAgent = new BootstrapAgent(bootstrapConfig);
646
+ bootstrapAgent.subscribeToAllTopics();
647
+
648
+ bootstrapAgent.publishMessage("$aws/certificates/create/json", "");
649
+
650
+ bootstrapAgent.device.on("connect", () => {
651
+ console.log("Your device is being provisioned");
652
+ });
653
+
654
+ bootstrapAgent.device.on("message", (topic: string, payload: string) => {
655
+ bootstrapAgent.handleAwsCertificateTopics(topic, payload);
656
+ });
657
+
658
+ bootstrapAgent.device.on("packetsend", (packet: any) => {
659
+ console.log({ packet: packet.subscriptions });
660
+ });
565
661
  }
566
- });
662
+ }
567
663
  }
@@ -0,0 +1,122 @@
1
+ const awsIot = require("aws-iot-device-sdk");
2
+ import {
3
+ BOOTSTRAP_CLAIM_ID_FILE_NAME,
4
+ BOOTSTRAP_CLAIM_ID_FILE_PATH,
5
+ DEVICE_PRIVATE_KEY_FILE_NAME,
6
+ CERTIFICATE_OWNERSHIP_TOKEN_FILE_NAME,
7
+ DEVICE_CLAIM_ID_FILE_NAME,
8
+ DEVICE_CERTIFICATE_FILE_NAME,
9
+ } from "../util/directories";
10
+ import { getTargetHardwareUuid } from "../infrastructure/certificates-and-tokens";
11
+ import { getDeviceId } from "../util/get-device-id";
12
+ import { LOCAL_CERT_AND_KEY_DIR } from "alwaysai/lib/constants";
13
+ import { JsSpawner } from "alwaysai/lib/util";
14
+ import { logger } from "alwaysai/lib/util/logger";
15
+ import { DeviceAgentCloudConnection } from "./device-agent-cloud-connection";
16
+ const process = require("process");
17
+
18
+ interface DeviceAgentConfigType {
19
+ keyPath: string;
20
+ certPath: string;
21
+ caPath: string;
22
+ clientId: string;
23
+ host: string;
24
+ }
25
+
26
+ interface FleetProvisionTemplateMessageType {
27
+ certificateOwnershipToken: String;
28
+ parameters: {
29
+ hardwareId: String;
30
+ deviceUuid: String;
31
+ certificateId: String;
32
+ deviceType: String;
33
+ };
34
+ }
35
+
36
+ export class DeviceAgent {
37
+ constructor(config: DeviceAgentConfigType) {
38
+ this.device = awsIot.device(config);
39
+ }
40
+
41
+ public deviceType = "aai-device";
42
+ public device = awsIot.device;
43
+ public hardwareId = async () => await getTargetHardwareUuid(JsSpawner());
44
+ public deviceId = getDeviceId();
45
+
46
+ public publishMessage(topic: string, message: string) {
47
+ this.device.publish(topic, message);
48
+ }
49
+ }
50
+
51
+ export class BootstrapAgent extends DeviceAgent {
52
+ public async subscribeToAllTopics() {
53
+ const AWS_CERTIFICATE_ACCEPT_TOPIC =
54
+ "$aws/certificates/create/json/accepted";
55
+ const PROVISIONING_ACCEPTED_TOPIC =
56
+ "$aws/provisioning-templates/FleetProvisionTemplate/provision/json/accepted";
57
+
58
+ const topics = [AWS_CERTIFICATE_ACCEPT_TOPIC, PROVISIONING_ACCEPTED_TOPIC];
59
+ const resp = this.device.subscribe(
60
+ topics,
61
+ function (err: any, granted: { topic: string; qos: number }[]) {
62
+ logger.debug(granted);
63
+ }
64
+ );
65
+ }
66
+
67
+ public async handleAwsCertificateTopics(topic: string, payload: any) {
68
+ switch (topic) {
69
+ case "$aws/certificates/create/json/accepted": {
70
+ const {
71
+ certificateId,
72
+ certificatePem,
73
+ privateKey,
74
+ certificateOwnershipToken,
75
+ } = JSON.parse(payload);
76
+ console.log(certificateId);
77
+
78
+ const certSpawner = JsSpawner({ path: LOCAL_CERT_AND_KEY_DIR });
79
+
80
+ await certSpawner.writeFile(
81
+ DEVICE_CERTIFICATE_FILE_NAME,
82
+ certificatePem
83
+ );
84
+
85
+ await certSpawner.writeFile(DEVICE_PRIVATE_KEY_FILE_NAME, privateKey);
86
+
87
+ await certSpawner.writeFile(DEVICE_CLAIM_ID_FILE_NAME, certificateId);
88
+
89
+ await certSpawner.writeFile(
90
+ CERTIFICATE_OWNERSHIP_TOKEN_FILE_NAME,
91
+ certificateOwnershipToken
92
+ );
93
+
94
+ const content: FleetProvisionTemplateMessageType = {
95
+ certificateOwnershipToken,
96
+ parameters: {
97
+ hardwareId: await this.hardwareId(),
98
+ deviceUuid: this.deviceId,
99
+ certificateId,
100
+ deviceType: this.deviceType,
101
+ },
102
+ };
103
+ console.log(content);
104
+
105
+ this.publishMessage(
106
+ "$aws/provisioning-templates/FleetProvisionTemplate/provision/json",
107
+ JSON.stringify(content)
108
+ );
109
+
110
+ break;
111
+ }
112
+ case "$aws/provisioning-templates/FleetProvisionTemplate/provision/json/accepted": {
113
+ console.log("success");
114
+ // Resolve the `child_process` module, and `spawn`
115
+ // a new process.
116
+ // The `child_process` module lets us
117
+ // access OS functionalities by running any bash command.`.
118
+ process.exit();
119
+ }
120
+ }
121
+ }
122
+ }
@@ -0,0 +1,24 @@
1
+ import { getSystemId } from "alwaysai/lib/infrastructure";
2
+
3
+ export const getSecondLevelDomain = () => {
4
+ let domain = "";
5
+ switch (getSystemId()) {
6
+ case "development":
7
+ domain = "a6i0.net";
8
+ break;
9
+ case "qa":
10
+ domain = "a6i1.net";
11
+ break;
12
+ case "production":
13
+ domain = "alwaysai.co";
14
+ break;
15
+ default:
16
+ domain = "alwaysai.co";
17
+ break;
18
+ }
19
+ return domain;
20
+ };
21
+
22
+ export const serviceEndpointBuilder = (service: string, path: string) => {
23
+ return `https://${service}.${getSecondLevelDomain()}/${path}`;
24
+ };
@@ -4,6 +4,7 @@ export const ALWAYSAI_OS_PLATFORM = parseOsPlatform(process.env.ALWAYSAI_OS_PLAT
4
4
  export const ALWAYSAI_SHOW_HIDDEN = parseBoolean(process.env.ALWAYSAI_SHOW_HIDDEN);
5
5
  export const ALWAYSAI_DEVICE_AGENT_MODE = process.env.ALWAYSAI_DEVICE_AGENT_MODE;
6
6
  export const ALWAYSAI_LOG_LEVEL = process.env.AAI_LOG_LEVEL;
7
+ export const ALWAYSAI_LOG_TO_CONSOLE = process.env.ALWAYSAI_LOG_TO_CONSOLE;
7
8
 
8
9
  function parseOsPlatform(str: string | undefined): NodeJS.Platform {
9
10
  switch (str) {
package/src/index.ts CHANGED
@@ -10,9 +10,10 @@ import { root } from './root';
10
10
  import { runDeviceAgentCloudInterface } from './cloud-connection/device-agent-cloud-connection';
11
11
  import { AgentConfigFile } from './infrastructure/agent-config';
12
12
  import { ALWAYSAI_DEVICE_AGENT_MODE } from './environment';
13
+ import { logger } from './util/logger';
13
14
 
14
15
  if (module === require.main) {
15
- console.log('Starting alwaysAI Device Agent');
16
+ logger.info('Starting alwaysAI Device Agent');
16
17
  if (!AgentConfigFile().exists()) {
17
18
  AgentConfigFile().initialize();
18
19
  }