@alwaysai/device-agent 0.0.9 → 0.0.11

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 -3
  17. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  18. package/lib/cloud-connection/device-agent-cloud-connection.js +90 -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 +2 -1
  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 +175 -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,22 @@ 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
+ } from "@alwaysai/device-agent-schemas";
50
+ import { getDeviceId } from "../util/get-device-id";
51
+ import { JsSpawner, logger } from "alwaysai/lib/util";
52
+ import {
53
+ getCpuUtil,
54
+ getDiskUtil,
55
+ getMemUtil,
56
+ } from "../device-control/device-control";
57
+ import { AgentConfigFile } from "../infrastructure/agent-config";
58
+ import {
59
+ buildApp,
60
+ getAppConfig,
61
+ getAppDir,
62
+ } from "../application-control/utils";
63
+ import { updateModelsWithPresignedUrls } from "../application-control/models";
64
+ import { updateAppConfig } from "../application-control/config";
48
65
 
49
66
  export class DeviceAgentCloudConnection {
50
67
  private clientId = getDeviceId();
@@ -63,7 +80,7 @@ export class DeviceAgentCloudConnection {
63
80
  [keyMirrors.agentMessageType.app_install_status]: 5000,
64
81
  };
65
82
  private appLogStreams = new Set<string>();
66
- private deviceType = 'aai-device';
83
+ private deviceType = "aai-device";
67
84
  private readonly shadowPrefix = `$aws/things/${this.clientId}/shadow/name/`;
68
85
  private readonly shadowTopics = {
69
86
  projects: {
@@ -71,9 +88,9 @@ export class DeviceAgentCloudConnection {
71
88
  getAccepted: `${this.shadowPrefix}projects/get/accepted`,
72
89
  },
73
90
  };
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}`;
91
+ private readonly toCloudTopic = `to-cloud/${this.deviceType}/${this.clientId}`;
92
+ private readonly toClientTopic = `to-client/${this.deviceType}/${this.clientId}`;
93
+ private readonly toDeviceTopic = `to-device/${this.deviceType}/${this.clientId}`;
77
94
 
78
95
  // device shadow utils
79
96
 
@@ -123,9 +140,9 @@ export class DeviceAgentCloudConnection {
123
140
  this.appLogStreams.add(projectId);
124
141
  const readable = await getAppLogs({
125
142
  projectId,
126
- args: ['--tail', '100', '--no-log-prefix'],
143
+ args: ["--tail", "100", "--no-log-prefix"],
127
144
  });
128
- readable.on('data', (chunk: Buffer) => {
145
+ readable.on("data", (chunk: Buffer) => {
129
146
  if (!this.appLogStreams.has(projectId)) {
130
147
  // why doesn't typescript know about this function?
131
148
  // @ts-ignore
@@ -144,16 +161,18 @@ export class DeviceAgentCloudConnection {
144
161
  const packet = this.buildMessagePacket(
145
162
  this.getClientId(),
146
163
  this.toClientTopic,
147
- message,
164
+ message
148
165
  );
149
166
  this.publishMessage(this.toClientTopic, JSON.stringify(packet));
150
167
  });
151
168
 
152
- readable.on('error', (error) => {
153
- logger.error(`App log stream terminated for project ${projectId}: ${error}`);
169
+ readable.on("error", (error) => {
170
+ logger.error(
171
+ `App log stream terminated for project ${projectId}: ${error}`
172
+ );
154
173
  });
155
174
 
156
- readable.on('finished', () => {
175
+ readable.on("finished", () => {
157
176
  logger.info(`App logs finished piping for project ${projectId}`);
158
177
  });
159
178
  }
@@ -164,7 +183,7 @@ export class DeviceAgentCloudConnection {
164
183
  }
165
184
 
166
185
  private updateAppInstallStatus(
167
- installationStatus: Omit<AppInstallStatusPacket, 'appReleaseHash'>,
186
+ installationStatus: Omit<AppInstallStatusPacket, "appReleaseHash">
168
187
  ) {
169
188
  this.appInstallStatus.status = installationStatus.status;
170
189
  this.appInstallStatus.message = installationStatus.message;
@@ -178,7 +197,7 @@ export class DeviceAgentCloudConnection {
178
197
  private buildMessagePacket(
179
198
  deviceId: string,
180
199
  topic: string,
181
- payload: DeviceAgentMessagePayload,
200
+ payload: DeviceAgentMessagePayload
182
201
  ): DeviceAgentMessage {
183
202
  const packet = {
184
203
  timestamp: new Date().toUTCString(),
@@ -221,27 +240,34 @@ export class DeviceAgentCloudConnection {
221
240
  }
222
241
 
223
242
  // 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,
243
+ private getAppInstallStatusMessage =
244
+ async (): Promise<AppInstallStatusMessage> => {
245
+ const appInstallStatus = this.getAppInstallStatus();
246
+ const appInstallStatusMessage = {
247
+ messageType: keyMirrors.agentMessageType.app_install_status,
248
+ appInstallStatus,
249
+ };
250
+ return appInstallStatusMessage;
229
251
  };
230
- return appInstallStatusMessage;
231
- };
232
252
 
233
253
  private async startPublishingLiveUpdates(
234
254
  topic: string,
235
255
  messageType: string,
236
- getMessageData: () => Promise<DeviceAgentMessagePayload>,
256
+ getMessageData: () => Promise<DeviceAgentMessagePayload>
237
257
  ) {
238
258
  while (true) {
239
259
  try {
240
260
  const message = await getMessageData();
241
- const packet = this.buildMessagePacket(this.getClientId(), topic, message);
261
+ const packet = this.buildMessagePacket(
262
+ this.getClientId(),
263
+ topic,
264
+ message
265
+ );
242
266
  this.publishMessage(topic, JSON.stringify(packet));
243
267
  } catch (e) {
244
- logger.error(`Error publishing live updates for ${messageType}: ${e.message}`);
268
+ logger.error(
269
+ `Error publishing live updates for ${messageType}: ${e.message}`
270
+ );
245
271
  break;
246
272
  }
247
273
  if (!this.continuePublishing(messageType)) {
@@ -258,7 +284,10 @@ export class DeviceAgentCloudConnection {
258
284
  case keyMirrors.agentMessageType.app_state:
259
285
  return this.liveUpdatesAlive[flag];
260
286
  case keyMirrors.agentMessageType.app_install_status:
261
- return this.appInstallStatus.status === keyMirrors.appInstallStatus.in_progress;
287
+ return (
288
+ this.appInstallStatus.status ===
289
+ keyMirrors.appInstallStatus.in_progress
290
+ );
262
291
  default:
263
292
  logger.error(`Unrecognized publishable flag ${flag}`);
264
293
  return false;
@@ -317,7 +346,9 @@ export class DeviceAgentCloudConnection {
317
346
  this.liveUpdatesBroker(message.liveUpdatesToggles);
318
347
  break;
319
348
  default:
320
- logger.error(`Invalid agent action message type from message '${message}'`);
349
+ logger.error(
350
+ `Invalid agent action message type from message '${message}'`
351
+ );
321
352
  }
322
353
  }
323
354
 
@@ -352,7 +383,7 @@ export class DeviceAgentCloudConnection {
352
383
  this.startPublishingLiveUpdates(
353
384
  this.toClientTopic,
354
385
  keyMirrors.agentMessageType.device_stats,
355
- this.getDeviceStatsMessage,
386
+ this.getDeviceStatsMessage
356
387
  );
357
388
  }
358
389
  }
@@ -363,7 +394,7 @@ export class DeviceAgentCloudConnection {
363
394
  this.startPublishingLiveUpdates(
364
395
  this.toClientTopic,
365
396
  keyMirrors.agentMessageType.app_state,
366
- this.getAppStateMessage,
397
+ this.getAppStateMessage
367
398
  );
368
399
  }
369
400
  }
@@ -386,7 +417,10 @@ export class DeviceAgentCloudConnection {
386
417
  },
387
418
  },
388
419
  };
389
- this.publishMessage(`${this.shadowPrefix}projects/update`, JSON.stringify(packet));
420
+ this.publishMessage(
421
+ `${this.shadowPrefix}projects/update`,
422
+ JSON.stringify(packet)
423
+ );
390
424
  }
391
425
 
392
426
  private async publishCloudRequest(payload: SignedUrlsRequestMessage) {
@@ -394,7 +428,7 @@ export class DeviceAgentCloudConnection {
394
428
  const deviceRequestPacket = this.buildMessagePacket(
395
429
  this.getClientId(),
396
430
  topic,
397
- payload,
431
+ payload
398
432
  );
399
433
  this.publishMessage(topic, JSON.stringify({ deviceRequestPacket }));
400
434
  }
@@ -407,9 +441,10 @@ export class DeviceAgentCloudConnection {
407
441
  this.device = awsIot.device({
408
442
  keyPath: getPrivateKeyFilePath(),
409
443
  certPath: getCertificateFilePath(),
410
- caPath: getRootCertificateFilePath(),
444
+ caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
411
445
  clientId: this.clientId,
412
446
  host: this.host,
447
+ port: 8883,
413
448
  });
414
449
 
415
450
  this.device.subscribe(this.toDeviceTopic);
@@ -423,7 +458,7 @@ export class DeviceAgentCloudConnection {
423
458
 
424
459
  public publishMessage(topic: string, message: string) {
425
460
  // TODO: topic validation
426
- this.device.publish(topic, message);
461
+ this.device.publish(topic, message, (err: any) => {});
427
462
  }
428
463
 
429
464
  public async handleClientMessage({
@@ -448,8 +483,12 @@ export class DeviceAgentCloudConnection {
448
483
  break;
449
484
  }
450
485
  case keyMirrors.clientMessageType.app_install_cloud_response: {
451
- const { projectId, appReleaseHash, appInstallPayload, modelsInstallPayload } =
452
- payload.appInstallCloudResponse;
486
+ const {
487
+ projectId,
488
+ appReleaseHash,
489
+ appInstallPayload,
490
+ modelsInstallPayload,
491
+ } = payload.appInstallCloudResponse;
453
492
 
454
493
  this.initAppInstallStatus({
455
494
  status: keyMirrors.appInstallStatus.in_progress,
@@ -459,7 +498,7 @@ export class DeviceAgentCloudConnection {
459
498
  this.startPublishingLiveUpdates(
460
499
  this.toClientTopic,
461
500
  keyMirrors.agentMessageType.app_install_status,
462
- this.getAppInstallStatusMessage,
501
+ this.getAppInstallStatusMessage
463
502
  );
464
503
 
465
504
  // Install the app and models
@@ -480,7 +519,7 @@ export class DeviceAgentCloudConnection {
480
519
  // update app config shadow for project
481
520
  await this.publishReportedState(projectId);
482
521
  } catch (e) {
483
- console.error(e);
522
+ logger.error(e);
484
523
  const message: string = e.message;
485
524
 
486
525
  // uninstall the failed app to put system back in good state
@@ -491,7 +530,7 @@ export class DeviceAgentCloudConnection {
491
530
  });
492
531
 
493
532
  // delete shadow for project
494
- this.publishMessage(`${this.shadowPrefix}${projectId}/delete`, '');
533
+ this.publishMessage(`${this.shadowPrefix}${projectId}/delete`, "");
495
534
  }
496
535
  break;
497
536
  }
@@ -503,7 +542,7 @@ export class DeviceAgentCloudConnection {
503
542
 
504
543
  await this.publishReportedState(projectId);
505
544
  } catch (e) {
506
- console.error(e);
545
+ logger.error(e);
507
546
  }
508
547
  break;
509
548
  }
@@ -512,8 +551,14 @@ export class DeviceAgentCloudConnection {
512
551
  }
513
552
  }
514
553
 
515
- public async handleShadowTopic({ topic, payload }: { topic: string; payload: string }) {
516
- const shadowName = topic.split('/')[5];
554
+ public async handleShadowTopic({
555
+ topic,
556
+ payload,
557
+ }: {
558
+ topic: string;
559
+ payload: string;
560
+ }) {
561
+ const shadowName = topic.split("/")[5];
517
562
  const message = JSON.parse(payload);
518
563
  if (topic === this.shadowTopics.projects.updateDelta) {
519
564
  this.handleNamedShadowUpdate({ payload });
@@ -523,45 +568,94 @@ export class DeviceAgentCloudConnection {
523
568
  payload: JSON.stringify(message.delta),
524
569
  });
525
570
  } else {
526
- console.log(`No delta updates in shadow ${shadowName}`);
571
+ logger.info(`No delta updates in shadow ${shadowName}`);
527
572
  }
528
573
  }
529
574
  }
530
575
  }
531
576
 
532
- export function runDeviceAgentCloudInterface() {
533
- const deviceAgent = new DeviceAgentCloudConnection();
577
+ export async function runDeviceAgentCloudInterface() {
578
+ switch (existsSync(getCertificateFilePath())) {
579
+ case true:
580
+ {
581
+ const deviceAgent = new DeviceAgentCloudConnection();
534
582
 
535
- deviceAgent.device.on('connect', function () {
536
- deviceAgent.publishMessage('connection', deviceAgent.getClientId());
537
- console.log('Device Agent has connected to the cloud');
583
+ deviceAgent.device.on("connect", function (connack: any) {
584
+ logger.info("Device Agent has connected to the cloud");
538
585
 
539
- // Get shadow updates
540
- deviceAgent.publishMessage(`${deviceAgent.getShadowPrefix()}projects/get`, '');
541
- });
586
+ // Get shadow updates
587
+ deviceAgent.publishMessage(
588
+ `${deviceAgent.getShadowPrefix()}projects/get`,
589
+ ""
590
+ );
591
+ });
542
592
 
543
- deviceAgent.device.on('disconnect', function () {
544
- console.log('Device Agent has been disconnected from the cloud');
545
- });
593
+ deviceAgent.device.on("disconnect", function () {
594
+ logger.info("Device Agent has been disconnected from the cloud");
595
+ });
546
596
 
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),
597
+ deviceAgent.device.on(
598
+ "message",
599
+ function (topic: string, payload: string) {
600
+ console.log(topic);
601
+ console.log(JSON.parse(payload));
602
+ try {
603
+ const jsonPacket = JSON.parse(payload);
604
+ if (jsonPacket.hasOwnProperty("state")) {
605
+ deviceAgent.handleShadowTopic({
606
+ topic,
607
+ payload: JSON.stringify(jsonPacket.state),
608
+ });
609
+ } else {
610
+ const valid = validateClientMessage(jsonPacket);
611
+ if (!valid) {
612
+ console.error(JSON.stringify(validateClientMessage.errors));
613
+ } else {
614
+ deviceAgent.handleClientMessage({
615
+ topic,
616
+ message: jsonPacket,
617
+ });
618
+ }
619
+ }
620
+ } catch (error) {
621
+ logger.error(error);
622
+ }
623
+ }
624
+ );
625
+
626
+ deviceAgent.device.on("packetsend", (packet: any) => {
627
+ //console.log({ packet: packet });
554
628
  });
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
629
  }
563
- } catch (error) {
564
- console.error(error);
630
+
631
+ break;
632
+ case false: {
633
+ //set timer
634
+ const clientId = getDeviceId();
635
+ const bootstrapConfig = {
636
+ keyPath: BOOTSTRAP_DEVICE_PRIVATE_KEY_FILE_PATH,
637
+ certPath: BOOTSTRAP_DEVICE_CERTIFICATE_FILE_PATH,
638
+ caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
639
+ clientId,
640
+ host: getIoTCoreEndpointUrl(),
641
+ };
642
+
643
+ const bootstrapAgent = new BootstrapAgent(bootstrapConfig);
644
+ bootstrapAgent.subscribeToAllTopics();
645
+
646
+ bootstrapAgent.publishMessage("$aws/certificates/create/json", "");
647
+
648
+ bootstrapAgent.device.on("connect", () => {
649
+ console.log("Your device is being provisioned");
650
+ });
651
+
652
+ bootstrapAgent.device.on("message", (topic: string, payload: string) => {
653
+ bootstrapAgent.handleAwsCertificateTopics(topic, payload);
654
+ });
655
+
656
+ bootstrapAgent.device.on("packetsend", (packet: any) => {
657
+ console.log({ packet: packet.subscriptions });
658
+ });
565
659
  }
566
- });
660
+ }
567
661
  }
@@ -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
  }