@alwaysai/device-agent 2.0.1 → 2.0.2

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 (67) hide show
  1. package/lib/application-control/install.d.ts.map +1 -1
  2. package/lib/application-control/install.js +5 -1
  3. package/lib/application-control/install.js.map +1 -1
  4. package/lib/cloud-connection/connection-manager.d.ts +4 -6
  5. package/lib/cloud-connection/connection-manager.d.ts.map +1 -1
  6. package/lib/cloud-connection/connection-manager.js +23 -35
  7. package/lib/cloud-connection/connection-manager.js.map +1 -1
  8. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +3 -1
  9. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  10. package/lib/cloud-connection/device-agent-cloud-connection.js +51 -40
  11. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  12. package/lib/cloud-connection/publisher.d.ts +3 -2
  13. package/lib/cloud-connection/publisher.d.ts.map +1 -1
  14. package/lib/cloud-connection/publisher.js +8 -4
  15. package/lib/cloud-connection/publisher.js.map +1 -1
  16. package/lib/cloud-connection/shadow-handler.d.ts +1 -0
  17. package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
  18. package/lib/cloud-connection/shadow-handler.js +3 -0
  19. package/lib/cloud-connection/shadow-handler.js.map +1 -1
  20. package/lib/cloud-connection/shadow-handler.test.js +5 -2
  21. package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
  22. package/lib/cloud-connection/transaction-manager.d.ts +1 -3
  23. package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
  24. package/lib/cloud-connection/transaction-manager.js +1 -2
  25. package/lib/cloud-connection/transaction-manager.js.map +1 -1
  26. package/lib/cloud-connection/transaction-manager.test.js +12 -24
  27. package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
  28. package/lib/environment.d.ts +3 -0
  29. package/lib/environment.d.ts.map +1 -1
  30. package/lib/environment.js +12 -1
  31. package/lib/environment.js.map +1 -1
  32. package/lib/jobs/job-handler.d.ts +1 -1
  33. package/lib/jobs/job-handler.d.ts.map +1 -1
  34. package/lib/jobs/job-handler.js +4 -4
  35. package/lib/jobs/job-handler.js.map +1 -1
  36. package/lib/subcommands/app/analytics.d.ts.map +1 -1
  37. package/lib/subcommands/app/analytics.js +2 -3
  38. package/lib/subcommands/app/analytics.js.map +1 -1
  39. package/lib/subcommands/app/env-vars.d.ts.map +1 -1
  40. package/lib/subcommands/app/env-vars.js +4 -6
  41. package/lib/subcommands/app/env-vars.js.map +1 -1
  42. package/lib/subcommands/app/models.d.ts.map +1 -1
  43. package/lib/subcommands/app/models.js +2 -3
  44. package/lib/subcommands/app/models.js.map +1 -1
  45. package/lib/subcommands/app/shadow.d.ts.map +1 -1
  46. package/lib/subcommands/app/shadow.js +4 -6
  47. package/lib/subcommands/app/shadow.js.map +1 -1
  48. package/lib/subcommands/app/version.d.ts.map +1 -1
  49. package/lib/subcommands/app/version.js +6 -9
  50. package/lib/subcommands/app/version.js.map +1 -1
  51. package/package.json +1 -1
  52. package/readme.md +16 -4
  53. package/src/application-control/install.ts +8 -3
  54. package/src/cloud-connection/connection-manager.ts +24 -37
  55. package/src/cloud-connection/device-agent-cloud-connection.ts +94 -88
  56. package/src/cloud-connection/publisher.ts +28 -23
  57. package/src/cloud-connection/shadow-handler.test.ts +6 -2
  58. package/src/cloud-connection/shadow-handler.ts +4 -0
  59. package/src/cloud-connection/transaction-manager.test.ts +13 -44
  60. package/src/cloud-connection/transaction-manager.ts +1 -4
  61. package/src/environment.ts +18 -0
  62. package/src/jobs/job-handler.ts +4 -4
  63. package/src/subcommands/app/analytics.ts +2 -3
  64. package/src/subcommands/app/env-vars.ts +4 -6
  65. package/src/subcommands/app/models.ts +2 -3
  66. package/src/subcommands/app/shadow.ts +4 -6
  67. package/src/subcommands/app/version.ts +7 -8
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/subcommands/app/version.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,eAAe,yKAQ1B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;4DAkE5B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;4DA6B9B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;4DAc7B,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../../src/subcommands/app/version.ts"],"names":[],"mappings":"AAcA,eAAO,MAAM,eAAe,yKAQ1B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;;;4DAiE5B,CAAC;AAEH,eAAO,MAAM,mBAAmB;;4DA4B9B,CAAC;AAEH,eAAO,MAAM,kBAAkB;;4DAc7B,CAAC"}
@@ -6,7 +6,6 @@ const device_agent_schemas_1 = require("@alwaysai/device-agent-schemas");
6
6
  const application_control_1 = require("../../application-control");
7
7
  const device_agent_cloud_connection_1 = require("../../cloud-connection/device-agent-cloud-connection");
8
8
  const agent_config_1 = require("../../infrastructure/agent-config");
9
- const sleep_1 = require("../../util/sleep");
10
9
  const logger_1 = require("../../util/logger");
11
10
  exports.listAppsCliLeaf = (0, alwayscli_1.CliLeaf)({
12
11
  name: 'list',
@@ -69,10 +68,9 @@ exports.installAppCliLeaf = (0, alwayscli_1.CliLeaf)({
69
68
  envVars
70
69
  }
71
70
  };
72
- await deviceAgent.handleMessage(topic, message);
73
- while (deviceAgent.isCmdInProgress(project)) {
74
- await (0, sleep_1.default)(1000);
75
- }
71
+ await deviceAgent.waitForConnection();
72
+ await deviceAgent.sendCliCmd(topic, message);
73
+ await deviceAgent.waitForCmd(project);
76
74
  await deviceAgent.stop();
77
75
  }
78
76
  });
@@ -99,10 +97,9 @@ exports.uninstallAppCliLeaf = (0, alwayscli_1.CliLeaf)({
99
97
  projectId: project
100
98
  }
101
99
  };
102
- await deviceAgent.handleMessage(topic, message);
103
- while (deviceAgent.isCmdInProgress(project)) {
104
- await (0, sleep_1.default)(1000);
105
- }
100
+ await deviceAgent.waitForConnection();
101
+ await deviceAgent.sendCliCmd(topic, message);
102
+ await deviceAgent.waitForCmd(project);
106
103
  await deviceAgent.stop();
107
104
  }
108
105
  });
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/subcommands/app/version.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/subcommands/app/version.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@alwaysai/device-agent",
3
3
  "description": "The alwaysAI Device Agent",
4
- "version": "2.0.1",
4
+ "version": "2.0.2",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
7
7
  "publishConfig": {
package/readme.md CHANGED
@@ -53,14 +53,23 @@ change.
53
53
  * Passwordless `sudo` for `/sbin/shutdown` for device restart functionality
54
54
 
55
55
  To enable passwordless `sudo` for `npm` and `sbin/shutdown` for the current
56
- user, run `sudo visudo` and add the following lines to the end of the file:
56
+ user, run `sudo visudo` and add the following lines, where `<username>` is replaced with your username on the device:
57
+
58
+ > **Note**: It is critical that these lines be added to the **end of the file**.
57
59
 
58
60
  ```bash
59
- <username> <hostname> = (root) NOPASSWD: /usr/bin/npm
60
- <username> <hostname> = (root) NOPASSWD: /sbin/shutdown
61
+ <username> ALL = NOPASSWD: /usr/bin/pm2
62
+ <username> ALL = NOPASSWD: /usr/lib/node_modules/pm2/bin/pm2
63
+ <username> ALL = NOPASSWD: /usr/bin/npm
64
+ <username> ALL = NOPASSWD: /sbin/shutdown
61
65
  ```
62
66
 
63
- On a linux system `username` can be obtained by typing `whoami` into the terminal. Similarly, if you don't know your `hostname` you can simply type `hostname`.
67
+ On a linux system, the username can be obtained by typing `whoami` into the terminal. For example:
68
+
69
+ ```bash
70
+ $ whoami
71
+ alwaysAI
72
+ ```
64
73
 
65
74
  ## Provision Device
66
75
 
@@ -429,6 +438,7 @@ $ pm2 delete 0
429
438
  $ pm2 flush
430
439
  $ pm2 unstartup
431
440
  ```
441
+
432
442
  ### Remove the device configuration
433
443
 
434
444
  Open a new terminal and run `aai-agent device clean`.
@@ -443,3 +453,5 @@ running `aai-agent`. You should see a response similar to
443
453
 
444
454
  Go to the [Devices](https://console.alwaysai.co/dashboard/devices) tab, find the
445
455
  device in question, and remove the device using the trashcan icon.
456
+
457
+
@@ -16,7 +16,8 @@ import {
16
16
  appCleanDocker,
17
17
  getPythonVenvPaths,
18
18
  createPythonVenv,
19
- installPythonReqs
19
+ installPythonReqs,
20
+ TargetHardware
20
21
  } from 'alwaysai/lib/core/app';
21
22
  import { DOCKER_IMAGE_ID_INITIAL_VALUE } from 'alwaysai/lib/constants';
22
23
  import { runInDir } from '../util/run-in-dir';
@@ -30,6 +31,7 @@ import {
30
31
  } from '../local-connection/constants';
31
32
  import { DOCKERFILE, PYTHON_REQUIREMENTS_FILE_NAME } from 'alwaysai/lib/paths';
32
33
  import { downloadToFile } from '../util/file';
34
+ import { ALWAYSAI_TARGET_HW_OVERRIDE, parseTargetHW } from '../environment';
33
35
  import { setEnvInternal } from './environment-variables';
34
36
  import { AppConfig } from '@alwaysai/app-configuration-schemas';
35
37
 
@@ -234,15 +236,18 @@ async function checkValidProjectFiles({ appDir }) {
234
236
  if (!AppJsonFile(appDir).readIfExists()) {
235
237
  throw new Error('App JSON file does not exist!');
236
238
  }
237
-
238
239
  // write target json
239
240
  if (!fs.existsSync(path.join(appDir, DOCKERFILE))) {
240
241
  throw new Error('No Dockerfile found for application!');
241
242
  }
243
+ const targetHw: TargetHardware =
244
+ parseTargetHW(ALWAYSAI_TARGET_HW_OVERRIDE) ??
245
+ (await getTargetHardwareType({}));
246
+ logger.debug(`Target Hardware selected to: ${targetHw}`);
242
247
  TargetJsonFile(appDir).write({
243
248
  targetProtocol: 'docker:',
244
249
  dockerImageId: DOCKER_IMAGE_ID_INITIAL_VALUE,
245
- targetHardware: await getTargetHardwareType({})
250
+ targetHardware: targetHw
246
251
  });
247
252
  }
248
253
 
@@ -16,40 +16,32 @@ export class ConnectionManager extends MessageDispatcher<any> {
16
16
  private clientId: string;
17
17
  private host: string;
18
18
  private port: number;
19
- private device = awsIot.device;
19
+ private device: awsIot.device;
20
20
  private subscribedTopics: Set<string> = new Set();
21
+ private connected = false;
21
22
 
22
23
  constructor(clientId: string, host: string, port: number) {
23
24
  super();
24
25
  this.clientId = clientId;
25
26
  this.host = host;
26
27
  this.port = port;
28
+ this.device = awsIot.device({
29
+ keyPath: DEVICE_PRIVATE_KEY_FILE_PATH,
30
+ certPath: DEVICE_CERTIFICATE_FILE_PATH,
31
+ caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
32
+ clientId: this.clientId,
33
+ host: this.host,
34
+ port: this.port,
35
+ keepalive: 10 // time before re-connect attempt on dropped connection, default is 400 seconds
36
+ });
27
37
  }
28
38
 
29
39
  public getIoTDevice() {
30
40
  return this.device;
31
41
  }
32
42
 
33
- public setupConnection(): void {
34
- this.connect();
35
- }
36
-
37
- public connect(): void {
38
- try {
39
- this.device = awsIot.device({
40
- keyPath: DEVICE_PRIVATE_KEY_FILE_PATH,
41
- certPath: DEVICE_CERTIFICATE_FILE_PATH,
42
- caPath: AWS_ROOT_CERTIFICATE_FILE_PATH,
43
- clientId: this.clientId,
44
- host: this.host,
45
- port: this.port,
46
- keepalive: 10 // time before re-connect attempt on dropped connection, default is 400 seconds
47
- });
48
- this.setupHandlers();
49
- } catch (error) {
50
- logger.error(`Error connecting to cloud!\n${stringifyError(error)}`);
51
- this.handleReconnection();
52
- }
43
+ public isConnected(): boolean {
44
+ return this.connected;
53
45
  }
54
46
 
55
47
  public registerHandler(topic: string, handler: MessageHandler) {
@@ -58,14 +50,12 @@ export class ConnectionManager extends MessageDispatcher<any> {
58
50
  }
59
51
 
60
52
  public disconnect(): void {
61
- if (this.device) {
62
- this.device.end();
63
- logger.debug(`Device Agent has been disconnected from the AWS IoT Core.`);
64
- }
53
+ this.device.end();
54
+ logger.debug(`Device Agent has been disconnected from the AWS IoT Core.`);
65
55
  }
66
56
 
67
57
  public subscribe(topic: string): void {
68
- if (this.device && !this.subscribedTopics.has(topic)) {
58
+ if (!this.subscribedTopics.has(topic)) {
69
59
  this.device.subscribe(topic);
70
60
  this.subscribedTopics.add(topic);
71
61
  logger.debug(`Subscribed to topic: ${topic}`);
@@ -73,29 +63,23 @@ export class ConnectionManager extends MessageDispatcher<any> {
73
63
  }
74
64
 
75
65
  public unsubscribe(topic: string): void {
76
- if (this.device && this.subscribedTopics.has(topic)) {
66
+ if (this.subscribedTopics.has(topic)) {
77
67
  this.device.unsubscribe(topic);
78
68
  this.subscribedTopics.delete(topic);
79
69
  logger.debug(`Unsubscribed from topic: ${topic}`);
80
70
  }
81
71
  }
82
72
 
83
- public isConnected(): boolean {
84
- return this.device ? this.device.connected : false;
85
- }
86
-
87
- private handleReconnection() {
88
- logger.debug(`Attempting to reconnect to AWS IoT Core...`);
89
- setTimeout(() => this.connect(), 5000); // try in 5 seconds.
90
- }
91
-
92
- private setupHandlers(): void {
73
+ public initConnectionHandlers(connectCallback: () => void): void {
93
74
  this.device.on('connect', (connack: any) => {
94
75
  logger.info('Device Agent has connected to the cloud.');
76
+ this.connected = true;
77
+ connectCallback();
95
78
  });
96
79
 
97
80
  this.device.on('disconnect', () => {
98
81
  logger.warn('Device Agent has been disconnected from the cloud');
82
+ this.connected = false;
99
83
  });
100
84
 
101
85
  this.device.on('reconnect', () => {
@@ -108,15 +92,18 @@ export class ConnectionManager extends MessageDispatcher<any> {
108
92
  logger.error(
109
93
  `Error connecting to the AWS IoT Core!\n${stringifyError(e)}`
110
94
  );
95
+ this.connected = false;
111
96
  });
112
97
 
113
98
  this.device.on('close', () => {
114
99
  logger.warn('Device Agent AWS IoT Core connection closed.');
100
+ this.connected = false;
115
101
  });
116
102
 
117
103
  this.device.on('offline', () => {
118
104
  logger.warn(`Device Agent is offline ${new Date().toLocaleString()}`);
119
105
  void this.logConnectionInfo();
106
+ this.connected = false;
120
107
  });
121
108
 
122
109
  this.device.on('message', async (topic: string, payload: string) => {
@@ -41,109 +41,100 @@ export class DeviceAgentCloudConnection {
41
41
  SecureTunnelHandlerSingleton.getInstance();
42
42
 
43
43
  constructor() {
44
- this.liveUpdatesHandler = new LiveUpdatesHandler();
45
-
46
44
  // Initialize & setup the connection
47
45
  this.connectionManager = new ConnectionManager(
48
46
  this.clientId,
49
47
  this.host,
50
48
  this.port
51
49
  );
52
- this.connectionManager.setupConnection();
53
50
 
54
- // Initialize the Publisher, ShadowHandler & Transaction Manager
55
- this.publisher = new Publisher(
56
- this.connectionManager.getIoTDevice(),
57
- this.clientId
58
- );
51
+ this.publisher = new Publisher(this.connectionManager, this.clientId);
59
52
  this.shadowHandler = new ShadowHandler(this.clientId, this.publisher);
60
-
61
- this.transactionManager = new TransactionManager(
62
- this.publisher,
63
- this.liveUpdatesHandler
64
- );
65
-
66
- // Construct a HandlerContext used by all the message handlers
67
- const handlerContext: HandlerContext = {
68
- clientId: this.clientId,
69
- txnMgr: this.transactionManager,
70
- publisher: this.publisher,
71
- shadowHandler: this.shadowHandler,
72
- liveUpdatesHandler: this.liveUpdatesHandler,
73
- secureTunnelHandler: this.secureTunnelHandler
74
- };
75
-
76
- // Instantiate & register message handlers for Project Shadow topics
77
- const projectShadowMessageHandler = new ProjectShadowMessageHandler(
78
- handlerContext
79
- );
80
- this.shadowHandler.projectShadowTopics.forEach((topic) => {
53
+ this.liveUpdatesHandler = new LiveUpdatesHandler();
54
+ this.transactionManager = new TransactionManager(this.liveUpdatesHandler);
55
+
56
+ this.connectionManager.initConnectionHandlers(() => {
57
+ // Construct a HandlerContext used by all the message handlers
58
+ const handlerContext: HandlerContext = {
59
+ clientId: this.clientId,
60
+ txnMgr: this.transactionManager,
61
+ publisher: this.publisher,
62
+ shadowHandler: this.shadowHandler,
63
+ liveUpdatesHandler: this.liveUpdatesHandler,
64
+ secureTunnelHandler: this.secureTunnelHandler
65
+ };
66
+
67
+ // Instantiate & register message handlers for Project Shadow topics
68
+ const projectShadowMessageHandler = new ProjectShadowMessageHandler(
69
+ handlerContext
70
+ );
71
+ this.shadowHandler.projectShadowTopics.forEach((topic) => {
72
+ this.connectionManager.registerHandler(
73
+ topic,
74
+ projectShadowMessageHandler
75
+ );
76
+ });
77
+
78
+ // Instantiate & register message handlers for to-device and secureTunnel topics
81
79
  this.connectionManager.registerHandler(
82
- topic,
83
- projectShadowMessageHandler
80
+ this.toDeviceTopic,
81
+ new DeviceAgentMessageHandler(
82
+ handlerContext,
83
+ (txId: string, errorMsg: string) => {
84
+ const msg = buildToClientStatusResponseMessage(
85
+ this.publisher.getClientId(),
86
+ {
87
+ status: keyMirrors.statusResponse.failure,
88
+ message: errorMsg
89
+ },
90
+ txId
91
+ );
92
+ this.publisher.publishToClient(msg);
93
+ },
94
+ (txId: string) => {
95
+ const msg = buildToClientStatusResponseMessage(
96
+ this.publisher.getClientId(),
97
+ { status: keyMirrors.statusResponse.success },
98
+ txId
99
+ );
100
+ this.publisher.publishToClient(msg);
101
+ }
102
+ )
84
103
  );
85
- });
86
104
 
87
- // Instantiate & register message handlers for to-device and secureTunnel topics
88
- this.connectionManager.registerHandler(
89
- this.toDeviceTopic,
90
- new DeviceAgentMessageHandler(
91
- handlerContext,
92
- (txId: string, errorMsg: string) => {
93
- const msg = buildToClientStatusResponseMessage(
94
- this.publisher.getClientId(),
95
- {
96
- status: keyMirrors.statusResponse.failure,
97
- message: errorMsg
98
- },
99
- txId
100
- );
101
- this.publisher.publishToClient(msg);
102
- },
103
- (txId: string) => {
104
- const msg = buildToClientStatusResponseMessage(
105
- this.publisher.getClientId(),
106
- { status: keyMirrors.statusResponse.success },
107
- txId
108
- );
109
- this.publisher.publishToClient(msg);
110
- }
111
- )
112
- );
113
-
114
- const secureTunnelMessageHandler = new SecureTunnelMessageHandler(
115
- handlerContext
116
- );
117
- this.connectionManager.registerHandler(
118
- secureTunnelMessageHandler.getNotifyTopic(),
119
- secureTunnelMessageHandler
120
- );
121
-
122
- this.connectionManager.registerHandler(
123
- this.shadowHandler.shadowTopics.secureTunnel.updateDelta,
124
- secureTunnelMessageHandler
125
- );
126
- this.connectionManager.registerHandler(
127
- this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted,
128
- secureTunnelMessageHandler
129
- );
105
+ const secureTunnelMessageHandler = new SecureTunnelMessageHandler(
106
+ handlerContext
107
+ );
108
+ this.connectionManager.registerHandler(
109
+ secureTunnelMessageHandler.getNotifyTopic(),
110
+ secureTunnelMessageHandler
111
+ );
130
112
 
131
- const jobHandler = new JobHandler(handlerContext);
113
+ this.connectionManager.registerHandler(
114
+ this.shadowHandler.shadowTopics.secureTunnel.updateDelta,
115
+ secureTunnelMessageHandler
116
+ );
117
+ this.connectionManager.registerHandler(
118
+ this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted,
119
+ secureTunnelMessageHandler
120
+ );
132
121
 
133
- const JOB_HANDLER_TOPICS = jobHandler.getJobTopic();
122
+ const jobHandler = new JobHandler(handlerContext);
123
+ const JOB_HANDLER_TOPICS = jobHandler.getJobTopics();
134
124
 
135
- this.connectionManager.registerHandler(
136
- JOB_HANDLER_TOPICS.NOTIFY_NEXT,
137
- jobHandler
138
- );
125
+ this.connectionManager.registerHandler(
126
+ JOB_HANDLER_TOPICS.NOTIFY_NEXT,
127
+ jobHandler
128
+ );
139
129
 
140
- this.connectionManager.registerHandler(
141
- JOB_HANDLER_TOPICS.START_NEXT_ACCEPTED,
142
- jobHandler
143
- );
130
+ this.connectionManager.registerHandler(
131
+ JOB_HANDLER_TOPICS.START_NEXT_ACCEPTED,
132
+ jobHandler
133
+ );
134
+ this.publisher.publish(JOB_HANDLER_TOPICS.START_NEXT, JSON.stringify({}));
144
135
 
145
- // Initialize job
146
- this.publisher.publish(JOB_HANDLER_TOPICS.START_NEXT, JSON.stringify({}));
136
+ void this.shadowHandler.initShadows();
137
+ });
147
138
  }
148
139
 
149
140
  /*=================================================================
@@ -164,7 +155,22 @@ export class DeviceAgentCloudConnection {
164
155
  await sleep(1000);
165
156
  this.connectionManager.disconnect();
166
157
  }
167
- public async handleMessage(topic: string, message: any) {
158
+
159
+ // CLI methods
160
+
161
+ public async waitForConnection() {
162
+ while (!this.connectionManager.isConnected()) {
163
+ await sleep(1000);
164
+ }
165
+ }
166
+
167
+ public async waitForCmd(projectId: string) {
168
+ while (this.isCmdInProgress(projectId)) {
169
+ await sleep(1000);
170
+ }
171
+ }
172
+
173
+ public async sendCliCmd(topic: string, message: any) {
168
174
  this.connectionManager.dispatch(topic, message);
169
175
  }
170
176
  }
@@ -6,15 +6,16 @@ import {
6
6
  getToCloudTopic
7
7
  } from '@alwaysai/device-agent-schemas';
8
8
  import * as winston from 'winston';
9
+ import { ConnectionManager } from './connection-manager';
9
10
 
10
11
  export class Publisher {
11
- private client: any;
12
+ private connectionManager: ConnectionManager;
12
13
  private clientId: string;
13
14
  private readonly toClientTopic: string;
14
15
  private readonly toCloudTopic: string;
15
16
 
16
- constructor(client: any, clientId: string) {
17
- this.client = client;
17
+ constructor(connectionManager: ConnectionManager, clientId: string) {
18
+ this.connectionManager = connectionManager;
18
19
  this.clientId = clientId;
19
20
  this.toClientTopic = getToClientTopic(this.clientId);
20
21
  this.toCloudTopic = getToCloudTopic(this.clientId);
@@ -34,13 +35,15 @@ export class Publisher {
34
35
  2
35
36
  )}`
36
37
  );
37
- this.client.publish(topic, payload, (err: any) => {
38
- if (err) {
39
- logger.error(
40
- `Error publishing message: \nTopic: ${topic}\nMessage: ${payload}\nError: ${err}`
41
- );
42
- }
43
- });
38
+ this.connectionManager
39
+ .getIoTDevice()
40
+ .publish(topic, payload, (err: any) => {
41
+ if (err) {
42
+ logger.error(
43
+ `Error publishing message: \nTopic: ${topic}\nMessage: ${payload}\nError: ${err}`
44
+ );
45
+ }
46
+ });
44
47
  }
45
48
 
46
49
  public publishToCloudWithAck(
@@ -48,19 +51,21 @@ export class Publisher {
48
51
  ackNackCallback: CallableFunction
49
52
  ) {
50
53
  const topic = this.toCloudTopic;
51
- this.client.publish(topic, payload, { qos: 1 }, (err: any, resp: any) => {
52
- if (err) {
53
- logger.error(
54
- `Error publishing message: \nTopic: ${topic}\nMessage: ${payload}\nError: ${err}`
55
- );
56
- ackNackCallback(false);
57
- } else if (resp) {
58
- logger.debug(
59
- `Successfully published message: \nTopic: ${topic}\nMessage: ${payload}`
60
- );
61
- ackNackCallback(true);
62
- }
63
- });
54
+ this.connectionManager
55
+ .getIoTDevice()
56
+ .publish(topic, payload, { qos: 1 }, (err: any, resp: any) => {
57
+ if (err) {
58
+ logger.error(
59
+ `Error publishing message: \nTopic: ${topic}\nMessage: ${payload}\nError: ${err}`
60
+ );
61
+ ackNackCallback(false);
62
+ } else if (resp) {
63
+ logger.debug(
64
+ `Successfully published message: \nTopic: ${topic}\nMessage: ${payload}`
65
+ );
66
+ ackNackCallback(true);
67
+ }
68
+ });
64
69
  }
65
70
 
66
71
  public publishDeviceAgentMessage(
@@ -5,10 +5,14 @@ import { ShadowHandler } from './shadow-handler';
5
5
  import { Logger } from 'winston';
6
6
  import { logger } from '../util/logger';
7
7
  import { getShadowTopic } from '@alwaysai/device-agent-schemas';
8
+ import { ConnectionManager } from './connection-manager';
8
9
 
9
10
  jest.mock('../application-control');
10
11
  jest.mock('./publisher');
11
- const mockClient = jest.fn();
12
+ jest.mock('./connection-manager');
13
+ const mockConnectionManager = {
14
+ getIotDevice: jest.fn()
15
+ } as any as ConnectionManager;
12
16
  const clientId = 'test-client';
13
17
  const projectId1 = 'test-project';
14
18
  const projectId2 = 'test-project-2';
@@ -18,7 +22,7 @@ describe('Test Shadow Handler', () => {
18
22
  let shadowHandler: ShadowHandler;
19
23
 
20
24
  beforeEach(() => {
21
- publisher = new Publisher(mockClient, clientId);
25
+ publisher = new Publisher(mockConnectionManager, clientId);
22
26
  shadowHandler = new ShadowHandler(clientId, publisher);
23
27
  });
24
28
 
@@ -346,6 +346,10 @@ export class ShadowHandler {
346
346
  return [];
347
347
  }
348
348
 
349
+ public async initShadows() {
350
+ await this.updateSystemInfoShadow();
351
+ }
352
+
349
353
  public async updateSystemInfoShadow() {
350
354
  const systemInfo = await getSystemInformation();
351
355
  this.publisher.publish(