@alwaysai/device-agent 0.2.0 → 1.0.0

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 (84) hide show
  1. package/LICENSE +12 -0
  2. package/lib/application-control/config.d.ts.map +1 -1
  3. package/lib/application-control/config.js +6 -1
  4. package/lib/application-control/config.js.map +1 -1
  5. package/lib/application-control/index.d.ts +2 -2
  6. package/lib/application-control/index.d.ts.map +1 -1
  7. package/lib/application-control/index.js +2 -2
  8. package/lib/application-control/index.js.map +1 -1
  9. package/lib/application-control/install.d.ts +2 -2
  10. package/lib/application-control/install.d.ts.map +1 -1
  11. package/lib/application-control/install.js +10 -0
  12. package/lib/application-control/install.js.map +1 -1
  13. package/lib/application-control/status.d.ts +3 -3
  14. package/lib/application-control/status.d.ts.map +1 -1
  15. package/lib/application-control/status.js +4 -4
  16. package/lib/application-control/status.js.map +1 -1
  17. package/lib/cloud-connection/device-agent-cloud-connection.d.ts +7 -7
  18. package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
  19. package/lib/cloud-connection/device-agent-cloud-connection.js +158 -100
  20. package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
  21. package/lib/cloud-connection/live-updates-handler.d.ts +9 -9
  22. package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
  23. package/lib/cloud-connection/live-updates-handler.js +45 -42
  24. package/lib/cloud-connection/live-updates-handler.js.map +1 -1
  25. package/lib/cloud-connection/live-updates-handler.test.js +6 -5
  26. package/lib/cloud-connection/live-updates-handler.test.js.map +1 -1
  27. package/lib/cloud-connection/message-builder.d.ts +7 -0
  28. package/lib/cloud-connection/message-builder.d.ts.map +1 -0
  29. package/lib/cloud-connection/message-builder.js +63 -0
  30. package/lib/cloud-connection/message-builder.js.map +1 -0
  31. package/lib/cloud-connection/messages.d.ts +5 -15
  32. package/lib/cloud-connection/messages.d.ts.map +1 -1
  33. package/lib/cloud-connection/messages.js +22 -31
  34. package/lib/cloud-connection/messages.js.map +1 -1
  35. package/lib/cloud-connection/publisher.d.ts +4 -5
  36. package/lib/cloud-connection/publisher.d.ts.map +1 -1
  37. package/lib/cloud-connection/publisher.js +12 -21
  38. package/lib/cloud-connection/publisher.js.map +1 -1
  39. package/lib/cloud-connection/transaction-queue.d.ts +12 -0
  40. package/lib/cloud-connection/transaction-queue.d.ts.map +1 -0
  41. package/lib/cloud-connection/transaction-queue.js +38 -0
  42. package/lib/cloud-connection/transaction-queue.js.map +1 -0
  43. package/lib/cloud-connection/transaction-queue.test.d.ts +2 -0
  44. package/lib/cloud-connection/transaction-queue.test.d.ts.map +1 -0
  45. package/lib/cloud-connection/transaction-queue.test.js +46 -0
  46. package/lib/cloud-connection/transaction-queue.test.js.map +1 -0
  47. package/lib/local-connection/rabbitmq-connection.d.ts.map +1 -1
  48. package/lib/local-connection/rabbitmq-connection.js +5 -1
  49. package/lib/local-connection/rabbitmq-connection.js.map +1 -1
  50. package/lib/subcommands/app/index.d.ts.map +1 -1
  51. package/lib/subcommands/app/index.js +1 -0
  52. package/lib/subcommands/app/index.js.map +1 -1
  53. package/lib/subcommands/app/models.d.ts +5 -0
  54. package/lib/subcommands/app/models.d.ts.map +1 -1
  55. package/lib/subcommands/app/models.js +42 -1
  56. package/lib/subcommands/app/models.js.map +1 -1
  57. package/lib/subcommands/app/status.js +1 -1
  58. package/lib/subcommands/app/status.js.map +1 -1
  59. package/lib/subcommands/app/version.d.ts.map +1 -1
  60. package/lib/subcommands/app/version.js +9 -11
  61. package/lib/subcommands/app/version.js.map +1 -1
  62. package/lib/util/logger.d.ts.map +1 -1
  63. package/lib/util/logger.js +3 -1
  64. package/lib/util/logger.js.map +1 -1
  65. package/package.json +5 -4
  66. package/readme.md +30 -1
  67. package/src/application-control/config.ts +5 -1
  68. package/src/application-control/index.ts +2 -2
  69. package/src/application-control/install.ts +17 -4
  70. package/src/application-control/status.ts +9 -8
  71. package/src/cloud-connection/device-agent-cloud-connection.ts +225 -132
  72. package/src/cloud-connection/live-updates-handler.test.ts +6 -5
  73. package/src/cloud-connection/live-updates-handler.ts +90 -64
  74. package/src/cloud-connection/message-builder.ts +117 -0
  75. package/src/cloud-connection/messages.ts +27 -35
  76. package/src/cloud-connection/publisher.ts +17 -30
  77. package/src/cloud-connection/transaction-queue.test.ts +55 -0
  78. package/src/cloud-connection/transaction-queue.ts +40 -0
  79. package/src/local-connection/rabbitmq-connection.ts +5 -1
  80. package/src/subcommands/app/index.ts +3 -1
  81. package/src/subcommands/app/models.ts +44 -0
  82. package/src/subcommands/app/status.ts +2 -2
  83. package/src/subcommands/app/version.ts +16 -14
  84. package/src/util/logger.ts +5 -1
@@ -1,20 +1,27 @@
1
1
  import {
2
- AppLogsMessage,
3
- DeviceAgentMessagePayload,
2
+ AppLogsPayload,
3
+ ToClientMessagePayload,
4
4
  keyMirrors,
5
- LiveUpdatesToggles
5
+ LiveStateUpdatesTogglePayload,
6
+ ToClientMessage
6
7
  } from '@alwaysai/device-agent-schemas';
7
8
  import { getAppLogs } from '../application-control';
8
9
  import { logger } from '../util/logger';
9
10
  import sleep from '../util/sleep';
10
11
  import { Publisher } from './publisher';
11
12
  import {
12
- getAppInstallStatusMessage,
13
- getAppStateMessage,
14
- getDeviceStatsMessage
13
+ getStatusResponsePayload,
14
+ getAppStatePayload,
15
+ getDeviceStatsPayload
15
16
  } from './messages';
16
- import { AgentMessageTypeValue } from '@alwaysai/device-agent-schemas/lib/constants';
17
+ import { ToClientMessageTypeValue } from '@alwaysai/device-agent-schemas';
17
18
  import { ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS } from '../environment';
19
+ import {
20
+ buildAppLogsMessage,
21
+ buildAppStateMessage,
22
+ buildDeviceStatsMessage,
23
+ buildStatusResponseMessage
24
+ } from './message-builder';
18
25
 
19
26
  const LIVE_UPDATES_TIMEOUT = ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS
20
27
  ? parseInt(ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS)
@@ -22,22 +29,24 @@ const LIVE_UPDATES_TIMEOUT = ALWAYSAI_LIVE_UPDATES_TIMEOUT_MS
22
29
 
23
30
  export class LiveUpdatesHandler {
24
31
  private publisher: Publisher;
32
+ private clientId: string;
25
33
 
26
34
  private liveUpdatesTimeout: ReturnType<typeof setTimeout>;
27
35
  private liveUpdatesAlive = {
28
- [keyMirrors.agentMessageType.device_stats]: false,
29
- [keyMirrors.agentMessageType.app_state]: false,
30
- [keyMirrors.agentMessageType.app_logs]: false,
31
- [keyMirrors.agentMessageType.app_install_status]: false
36
+ [keyMirrors.toClientMessageType.device_stats]: false,
37
+ [keyMirrors.toClientMessageType.app_state]: false,
38
+ [keyMirrors.toClientMessageType.app_logs]: false,
39
+ [keyMirrors.toClientMessageType.status_response]: false
32
40
  };
33
41
  private liveUpdatesSleepIntervals = {
34
- [keyMirrors.agentMessageType.device_stats]: 5000,
35
- [keyMirrors.agentMessageType.app_state]: 5000,
36
- [keyMirrors.agentMessageType.app_logs]: 5000,
37
- [keyMirrors.agentMessageType.app_install_status]: 5000
42
+ [keyMirrors.toClientMessageType.device_stats]: 5000,
43
+ [keyMirrors.toClientMessageType.app_state]: 5000,
44
+ [keyMirrors.toClientMessageType.app_logs]: 5000,
45
+ [keyMirrors.toClientMessageType.status_response]: 5000
38
46
  };
47
+
39
48
  private appLogStreams = new Set<string>();
40
- private appInstallStatuses = new Set<string>();
49
+ private transactionStatuses = new Set<string>();
41
50
 
42
51
  private async startAppLogStream(projectId: string) {
43
52
  logger.info(`Starting log stream for ${projectId}`);
@@ -46,7 +55,7 @@ export class LiveUpdatesHandler {
46
55
  projectId,
47
56
  args: ['--tail', '100', '--no-log-prefix']
48
57
  });
49
- readable.on('data', (chunk: Buffer) => {
58
+ readable.on('data', async (chunk: Buffer) => {
50
59
  if (!this.appLogStreams.has(projectId)) {
51
60
  // why doesn't typescript know about this function?
52
61
  // @ts-ignore
@@ -55,13 +64,11 @@ export class LiveUpdatesHandler {
55
64
  return;
56
65
  }
57
66
  const logStr = chunk.toString();
58
- const message: AppLogsMessage = {
59
- messageType: keyMirrors.agentMessageType.app_logs,
60
- appLogs: {
61
- projectId,
62
- logChunk: logStr
63
- }
67
+ const payload: AppLogsPayload = {
68
+ projectId,
69
+ logChunk: logStr
64
70
  };
71
+ const message = await buildAppLogsMessage(payload, this.clientId);
65
72
  this.publisher.publishToClient(message);
66
73
  });
67
74
 
@@ -77,18 +84,18 @@ export class LiveUpdatesHandler {
77
84
  }
78
85
 
79
86
  private continuePublishing(
80
- flag: AgentMessageTypeValue,
81
- projectId?: string
87
+ flag: ToClientMessageTypeValue,
88
+ txId?: string
82
89
  ): boolean {
83
90
  switch (flag) {
84
- case keyMirrors.agentMessageType.device_stats:
85
- case keyMirrors.agentMessageType.app_state:
91
+ case keyMirrors.toClientMessageType.device_stats:
92
+ case keyMirrors.toClientMessageType.app_state:
86
93
  return this.liveUpdatesAlive[flag];
87
- case keyMirrors.agentMessageType.app_install_status: {
88
- if (!projectId) {
89
- throw new Error(`Project ID not provided to continuePublishing!`);
94
+ case keyMirrors.toClientMessageType.status_response: {
95
+ if (!txId) {
96
+ throw new Error(`Transaction ID not provided to continuePublishing!`);
90
97
  }
91
- return this.appInstallStatuses.has(projectId);
98
+ return this.transactionStatuses.has(txId);
92
99
  }
93
100
  default:
94
101
  logger.error(`Unrecognized publishable flag ${flag}`);
@@ -96,7 +103,7 @@ export class LiveUpdatesHandler {
96
103
  }
97
104
  }
98
105
 
99
- private getLiveUpdatesInterval(flag: AgentMessageTypeValue): number {
106
+ private getLiveUpdatesInterval(flag: ToClientMessageTypeValue): number {
100
107
  const exists = this.liveUpdatesSleepIntervals[flag];
101
108
  if (exists) {
102
109
  return exists;
@@ -105,12 +112,12 @@ export class LiveUpdatesHandler {
105
112
  return -1;
106
113
  }
107
114
 
108
- private setLiveUpdates(toggles: LiveUpdatesToggles) {
115
+ private setLiveUpdates(toggles: LiveStateUpdatesTogglePayload) {
109
116
  if (toggles.deviceStats !== undefined) {
110
117
  this.liveUpdatesAlive.device_stats = toggles.deviceStats;
111
118
  }
112
119
  if (toggles.appState !== undefined) {
113
- this.liveUpdatesAlive.app_state = toggles.appState;
120
+ this.liveUpdatesAlive.app_logs = toggles.appState;
114
121
  }
115
122
  }
116
123
 
@@ -126,20 +133,33 @@ export class LiveUpdatesHandler {
126
133
  }
127
134
 
128
135
  private async startPublishingLiveUpdates<T extends any[]>(
129
- messageType: AgentMessageTypeValue,
130
- getMessageData: (...args: T) => Promise<DeviceAgentMessagePayload>,
136
+ messageType: ToClientMessageTypeValue,
137
+ payloadBuilderFunction: (...args: T) => Promise<ToClientMessagePayload>,
138
+ messageBuilderFunction: (
139
+ payload: ToClientMessagePayload,
140
+ txId: string
141
+ ) => Promise<ToClientMessage>,
131
142
  args: T,
132
- projectId?: string
143
+ txId: string
133
144
  ) {
134
145
  logger.info(`Turned on live updates for ${messageType}`);
135
146
  // eslint-disable-next-line no-constant-condition
136
147
  while (true) {
137
148
  try {
138
- const message = await getMessageData(...args);
139
- if (!this.continuePublishing(messageType, projectId)) {
149
+ if (!this.continuePublishing(messageType, txId)) {
140
150
  logger.info(`Turned off live updates for ${messageType}`);
141
151
  break;
142
152
  }
153
+ const payload: ToClientMessagePayload = await payloadBuilderFunction(
154
+ ...args
155
+ );
156
+ logger.debug(
157
+ `payload returned from builder: ${JSON.stringify(payload)}`
158
+ );
159
+ const message = await messageBuilderFunction(payload, txId);
160
+ logger.debug(
161
+ `message returned from builder: ${JSON.stringify(message)}`
162
+ );
143
163
  this.publisher.publishToClient(message);
144
164
  } catch (e) {
145
165
  logger.error(
@@ -154,8 +174,9 @@ export class LiveUpdatesHandler {
154
174
  Public interface
155
175
  =================================================================*/
156
176
 
157
- constructor(publisher: Publisher) {
177
+ constructor(publisher: Publisher, clientId: string) {
158
178
  this.publisher = publisher;
179
+ this.clientId = clientId;
159
180
  logger.debug(
160
181
  `Toggle live updates timeout set to ${LIVE_UPDATES_TIMEOUT} ms`
161
182
  );
@@ -173,34 +194,35 @@ export class LiveUpdatesHandler {
173
194
  return this.liveUpdatesAlive.app_logs;
174
195
  }
175
196
 
176
- public async enableAppInstallStatus(props: {
177
- projectId: string;
178
- appReleaseHash: string;
179
- }) {
180
- const { projectId, appReleaseHash } = props;
181
- this.liveUpdatesAlive.app_install_status = true;
182
- if (!this.appInstallStatuses.has(projectId)) {
183
- this.appInstallStatuses.add(projectId);
197
+ public async enableTransactionStatus(props: { txId: string }) {
198
+ const { txId } = props;
199
+ this.liveUpdatesAlive.status_response = true;
200
+ if (!this.transactionStatuses.has(txId)) {
201
+ this.transactionStatuses.add(txId);
184
202
  // Don't wait for this call to finish since it loops until disabled
185
203
  void this.startPublishingLiveUpdates(
186
- keyMirrors.agentMessageType.app_install_status,
187
- getAppInstallStatusMessage,
188
- [keyMirrors.appInstallStatus.in_progress, '', appReleaseHash],
189
- projectId
204
+ keyMirrors.toClientMessageType.status_response,
205
+ getStatusResponsePayload,
206
+ buildStatusResponseMessage,
207
+ [keyMirrors.statusResponse.in_progress, ''],
208
+ txId
190
209
  );
191
210
  }
192
211
  }
193
212
 
194
- public async disableAppInstallStatus(props: { projectId: string }) {
195
- const { projectId } = props;
196
- this.appInstallStatuses.delete(projectId);
213
+ public async disableTransactionStatus(props: { txId: string }) {
214
+ const { txId } = props;
215
+ this.transactionStatuses.delete(txId);
197
216
 
198
- if (this.appInstallStatuses.size === 0) {
199
- this.liveUpdatesAlive.app_install_status = false;
217
+ if (this.transactionStatuses.size === 0) {
218
+ this.liveUpdatesAlive.status_response = false;
200
219
  }
201
220
  }
202
221
 
203
- public async handleToggles(toggles: LiveUpdatesToggles) {
222
+ public async handleToggles(
223
+ toggles: LiveStateUpdatesTogglePayload,
224
+ txId: string
225
+ ) {
204
226
  const { deviceStats, appState, appLogs } = toggles;
205
227
  this.restartLiveUpdatesTimeout();
206
228
 
@@ -210,9 +232,11 @@ export class LiveUpdatesHandler {
210
232
  if (deviceStats && currentDeviceStats !== true) {
211
233
  // Don't wait for this call to finish since it loops until disabled
212
234
  void this.startPublishingLiveUpdates(
213
- keyMirrors.agentMessageType.device_stats,
214
- getDeviceStatsMessage,
215
- []
235
+ keyMirrors.toClientMessageType.device_stats,
236
+ getDeviceStatsPayload,
237
+ buildDeviceStatsMessage,
238
+ [],
239
+ txId
216
240
  );
217
241
  }
218
242
  }
@@ -223,9 +247,11 @@ export class LiveUpdatesHandler {
223
247
  if (appState && currentAppState !== true) {
224
248
  // Don't wait for this call to finish since it loops until disabled
225
249
  void this.startPublishingLiveUpdates(
226
- keyMirrors.agentMessageType.app_state,
227
- getAppStateMessage,
228
- []
250
+ keyMirrors.toClientMessageType.app_state,
251
+ getAppStatePayload,
252
+ buildAppStateMessage,
253
+ [],
254
+ txId
229
255
  );
230
256
  }
231
257
  }
@@ -0,0 +1,117 @@
1
+ import {
2
+ AppLogsMessage,
3
+ AppLogsMessageType,
4
+ AppLogsPayload,
5
+ AppStateMessage,
6
+ AppStateMessageType,
7
+ AppStatePayload,
8
+ BaseToClientMessage,
9
+ DeviceStatsMessage,
10
+ DeviceStatsMessageType,
11
+ DeviceStatsPayload,
12
+ SignedUrlsRequestMessage,
13
+ SignedUrlsRequestMessageType,
14
+ SignedUrlsRequestPayload,
15
+ StatusResponseMessage,
16
+ StatusResponseMessageType,
17
+ StatusResponsePayload,
18
+ generateTxId,
19
+ getToClientTopic,
20
+ keyMirrors,
21
+ validateToDeviceAgentMessage
22
+ } from '@alwaysai/device-agent-schemas';
23
+ import { getDeviceUuid } from '../util/get-device-id';
24
+
25
+ function buildBaseClientMessage(txId?: string): BaseToClientMessage {
26
+ const clientId = getDeviceUuid();
27
+ const baseClientMessage = {
28
+ timestamp: new Date().toUTCString(),
29
+ deviceId: clientId,
30
+ topic: getToClientTopic(clientId),
31
+ txId: txId || generateTxId()
32
+ };
33
+ return baseClientMessage;
34
+ }
35
+
36
+ // Public Message Builders
37
+
38
+ // app logs
39
+ export async function buildAppLogsMessage(
40
+ payload: AppLogsPayload,
41
+ txId?: string
42
+ ): Promise<AppLogsMessage> {
43
+ const baseMessage = buildBaseClientMessage(txId);
44
+ const messageType: AppLogsMessageType =
45
+ keyMirrors.toClientMessageType.app_logs;
46
+ const message = {
47
+ ...baseMessage,
48
+ messageType,
49
+ payload
50
+ };
51
+ return message;
52
+ }
53
+
54
+ // app state
55
+ export async function buildAppStateMessage(
56
+ payload: AppStatePayload,
57
+ txId?: string
58
+ ): Promise<AppStateMessage> {
59
+ const baseMessage = buildBaseClientMessage(txId);
60
+ const messageType: AppStateMessageType =
61
+ keyMirrors.toClientMessageType.app_state;
62
+ const message = {
63
+ ...baseMessage,
64
+ messageType,
65
+ payload
66
+ };
67
+ return message;
68
+ }
69
+
70
+ // signed URLs
71
+ export async function buildSignedUrlsRequestMessage(
72
+ payload: SignedUrlsRequestPayload,
73
+ txId?: string
74
+ ): Promise<SignedUrlsRequestMessage> {
75
+ const baseMessage = buildBaseClientMessage(txId);
76
+ const messageType: SignedUrlsRequestMessageType =
77
+ keyMirrors.toCloudMessageType.signed_urls_request;
78
+ const message = {
79
+ ...baseMessage,
80
+ messageType,
81
+ payload
82
+ };
83
+ return message;
84
+ }
85
+
86
+ // status response
87
+ export async function buildStatusResponseMessage(
88
+ payload: StatusResponsePayload,
89
+ txId?: string
90
+ ): Promise<StatusResponseMessage> {
91
+ const baseMessage = buildBaseClientMessage(txId);
92
+ const messageType: StatusResponseMessageType =
93
+ keyMirrors.toClientMessageType.status_response;
94
+ const message = {
95
+ ...baseMessage,
96
+ messageType,
97
+ payload
98
+ };
99
+ const valid = validateToDeviceAgentMessage(message);
100
+ return message;
101
+ }
102
+
103
+ // device stats
104
+ export async function buildDeviceStatsMessage(
105
+ payload: DeviceStatsPayload,
106
+ txId?: string
107
+ ): Promise<DeviceStatsMessage> {
108
+ const messageType: DeviceStatsMessageType =
109
+ keyMirrors.toClientMessageType.device_stats;
110
+ const baseMessage = buildBaseClientMessage(txId);
111
+ const message = {
112
+ ...baseMessage,
113
+ messageType,
114
+ payload
115
+ };
116
+ return message;
117
+ }
@@ -1,10 +1,11 @@
1
1
  import {
2
- AppInstallStatusMessage,
3
- AppStatePacket,
4
- keyMirrors
2
+ AppState,
3
+ AppStatePayload,
4
+ DeviceStatsPayload,
5
+ StatusResponsePayload
5
6
  } from '@alwaysai/device-agent-schemas';
6
- import { AppInstallStatusValue } from '@alwaysai/device-agent-schemas/lib/constants';
7
- import { getAppStatus } from '../application-control';
7
+ import { StatusResponseValue } from '@alwaysai/device-agent-schemas/lib/constants';
8
+ import { getAppState } from '../application-control';
8
9
  import {
9
10
  getCpuUtil,
10
11
  getDiskUtil,
@@ -12,49 +13,40 @@ import {
12
13
  } from '../device-control/device-control';
13
14
  import { AgentConfigFile } from '../infrastructure/agent-config';
14
15
 
15
- export async function getAppStateMessage() {
16
- const appStateMessage: AppStatePacket[] = [];
16
+ export async function getAppStatePayload(): Promise<AppStatePayload> {
17
+ const appState: AppState[] = [];
17
18
  const apps = await AgentConfigFile().getApps();
18
19
  for (const app of apps) {
19
20
  const projectId = app.projectId;
20
- const status = await getAppStatus({ projectId });
21
- appStateMessage.push(status);
21
+ const status = await getAppState({ projectId });
22
+ appState.push(status);
22
23
  }
23
- const appStatePackage = {
24
- messageType: keyMirrors.agentMessageType.app_state,
25
- appState: appStateMessage
24
+ const appStatePayload = {
25
+ appState: appState
26
26
  };
27
- return appStatePackage;
27
+ return appStatePayload;
28
28
  }
29
29
 
30
- export async function getAppInstallStatusMessage(
31
- status: AppInstallStatusValue,
32
- message: string,
33
- appReleaseHash: string
34
- ): Promise<AppInstallStatusMessage> {
35
- const appInstallStatusMessage: AppInstallStatusMessage = {
36
- messageType: keyMirrors.agentMessageType.app_install_status,
37
- appInstallStatus: {
38
- status,
39
- message,
40
- appReleaseHash
41
- }
30
+ export async function getStatusResponsePayload(
31
+ status: StatusResponseValue,
32
+ message: string
33
+ ): Promise<StatusResponsePayload> {
34
+ const statusResponsePayload: StatusResponsePayload = {
35
+ status,
36
+ message
42
37
  };
43
- return appInstallStatusMessage;
38
+ return statusResponsePayload;
44
39
  }
45
40
 
46
- export async function getDeviceStatsMessage() {
41
+ export async function getDeviceStatsPayload(): Promise<DeviceStatsPayload> {
47
42
  const cpuUsage = await getCpuUtil();
48
43
  const diskUtil = await getDiskUtil();
49
44
  const memUtil = await getMemUtil();
50
45
 
51
- const deviceStatsMessage = {
52
- messageType: keyMirrors.agentMessageType.device_stats,
53
- deviceStats: {
54
- cpuUsage,
55
- diskUtil,
56
- usedMemoryPercentage: memUtil
57
- }
46
+ const deviceStatsPayload: DeviceStatsPayload = {
47
+ cpuUsage,
48
+ diskUtil,
49
+ usedMemoryPercentage: memUtil
58
50
  };
59
- return deviceStatsMessage;
51
+ return deviceStatsPayload;
60
52
  }
@@ -1,10 +1,10 @@
1
+ import { logger } from '../util/logger';
1
2
  import {
2
- DeviceAgentMessage,
3
- DeviceAgentMessagePayload,
4
- getClientTopic,
5
- getCloudTopic
3
+ ToClientMessage,
4
+ ToCloudMessage,
5
+ getToClientTopic,
6
+ getToCloudTopic
6
7
  } from '@alwaysai/device-agent-schemas';
7
- import { logger } from '../util/logger';
8
8
 
9
9
  export class Publisher {
10
10
  private client: any;
@@ -15,21 +15,8 @@ export class Publisher {
15
15
  constructor(client: any, clientId: string) {
16
16
  this.client = client;
17
17
  this.clientId = clientId;
18
- this.toClientTopic = getClientTopic(this.clientId);
19
- this.toCloudTopic = getCloudTopic(this.clientId);
20
- }
21
-
22
- private buildMessagePacket(
23
- topic: string,
24
- payload: DeviceAgentMessagePayload
25
- ): DeviceAgentMessage {
26
- const packet = {
27
- timestamp: new Date().toUTCString(),
28
- deviceId: this.clientId,
29
- topic,
30
- payload
31
- };
32
- return packet;
18
+ this.toClientTopic = getToClientTopic(this.clientId);
19
+ this.toCloudTopic = getToCloudTopic(this.clientId);
33
20
  }
34
21
 
35
22
  public publish(topic: string, payload: string) {
@@ -63,23 +50,23 @@ export class Publisher {
63
50
  });
64
51
  }
65
52
 
66
- public publishDeviceAgentPayload(
53
+ public publishDeviceAgentMessage(
67
54
  topic: string,
68
- payload: DeviceAgentMessagePayload
55
+ message: ToClientMessage | ToCloudMessage
69
56
  ) {
70
- const packet = this.buildMessagePacket(topic, payload);
71
- const packetStr = JSON.stringify(packet);
57
+ const messageStr = JSON.stringify(message);
72
58
  logger.debug(
73
- `Publishing message:\n${JSON.stringify({ topic, packet }, null, 2)}`
59
+ `Publishing message:\n${JSON.stringify({ topic, message }, null, 2)}`
74
60
  );
75
- this.publish(topic, packetStr);
61
+ this.publish(topic, messageStr);
76
62
  }
77
63
 
78
- public publishToClient(payload: DeviceAgentMessagePayload) {
79
- this.publishDeviceAgentPayload(this.toClientTopic, payload);
64
+ public publishToClient(message: ToClientMessage) {
65
+ this.publishDeviceAgentMessage(this.toClientTopic, message);
80
66
  }
81
67
 
82
- public publishToCloud(payload: DeviceAgentMessagePayload) {
83
- this.publishDeviceAgentPayload(this.toCloudTopic, payload);
68
+ public publishToCloud(message: ToCloudMessage) {
69
+ // Can edit topic field in message here if we want
70
+ this.publishDeviceAgentMessage(this.toCloudTopic, message);
84
71
  }
85
72
  }
@@ -0,0 +1,55 @@
1
+ import { generateTxId } from '@alwaysai/device-agent-schemas';
2
+ import { TransactionQueue } from './transaction-queue';
3
+
4
+ describe('Test Transaction Queue', () => {
5
+ let txnQueue: TransactionQueue;
6
+
7
+ beforeEach(() => {
8
+ txnQueue = new TransactionQueue();
9
+ jest.clearAllMocks();
10
+ });
11
+
12
+ test('Add new to transaction queue', async () => {
13
+ const txId = generateTxId();
14
+ const projectId = '1241fad-agah-gfadg-2352dgzg';
15
+ txnQueue.addTxIdToQueue(txId, projectId);
16
+ expect(txnQueue.checkTxnInQueue(txId)).toBeTruthy();
17
+ });
18
+
19
+ test('Attempt to add existing to transaction queue, results in failure', async () => {
20
+ const txId = generateTxId();
21
+ const projectId = '1241fad-agah-gfadg-2352dgzg';
22
+ txnQueue.addTxIdToQueue(txId, projectId);
23
+ expect(() => txnQueue.addTxIdToQueue(txId, projectId)).toThrow(
24
+ `txId ${txId} is already added to the queue!`
25
+ );
26
+ });
27
+
28
+ test('Check current transaction', async () => {
29
+ const txId = generateTxId();
30
+ const projectId = '1241fad-agah-gfadg-2352dgzg';
31
+ txnQueue.addTxIdToQueue(txId, projectId);
32
+
33
+ const txId2 = generateTxId();
34
+ const projectId2 = '1241faegta-agah-gagadg-2352dgzg';
35
+ txnQueue.addTxIdToQueue(txId2, projectId2);
36
+ expect(txnQueue.getCurrentTxId()).toEqual(txId);
37
+ });
38
+
39
+ test('Test remove transaction from queue', async () => {
40
+ const txId = generateTxId();
41
+ const projectId = '1241fad-agah-gfadg-2352dgzg';
42
+ txnQueue.addTxIdToQueue(txId, projectId);
43
+ txnQueue.completeCurrentTxn();
44
+
45
+ expect(txnQueue.getCurrentTxId()).toBeUndefined();
46
+ });
47
+
48
+ test('Test get project ID for a given txId', async () => {
49
+ const txId = generateTxId();
50
+ const projectId = '1241fad-agah-gfadg-2352dgzg';
51
+ txnQueue.addTxIdToQueue(txId, projectId);
52
+
53
+ expect(txnQueue.getProjectIdForTxnId(txId)).toEqual(projectId);
54
+ });
55
+ });
@@ -0,0 +1,40 @@
1
+ export class TransactionQueue {
2
+ private transactionList: string[];
3
+ private txIdToProjectIdMap: { [txId: string]: string } = {};
4
+
5
+ constructor() {
6
+ this.transactionList = [];
7
+ this.txIdToProjectIdMap = {};
8
+ }
9
+
10
+ public addTxIdToQueue(txId: string, projectId: string) {
11
+ if (!this.checkTxnInQueue(txId)) {
12
+ this.transactionList.push(txId);
13
+ this.txIdToProjectIdMap[txId] = projectId;
14
+ } else {
15
+ throw new Error(`txId ${txId} is already added to the queue!`);
16
+ }
17
+ }
18
+
19
+ public getCurrentTxId() {
20
+ return this.transactionList[0];
21
+ }
22
+
23
+ public checkTxnInQueue(txId: string) {
24
+ return this.transactionList.includes(txId);
25
+ }
26
+
27
+ public getProjectIdForTxnId(txId: string) {
28
+ return this.txIdToProjectIdMap[txId];
29
+ }
30
+
31
+ public completeTxn(txId: string) {
32
+ delete this.txIdToProjectIdMap[txId];
33
+ this.transactionList.splice(this.transactionList.indexOf(txId), 1);
34
+ }
35
+
36
+ public completeCurrentTxn() {
37
+ delete this.txIdToProjectIdMap[this.transactionList[0]];
38
+ this.transactionList.shift();
39
+ }
40
+ }
@@ -57,7 +57,11 @@ export async function writeRabbitMQDockerComposeFile() {
57
57
  ports: [`${LOCAL_CONNECTION_PORT}:${LOCAL_CONNECTION_PORT}`],
58
58
  hostname: 'my-rabbit',
59
59
  restart: 'on-failure',
60
- environment: [`RABBITMQ_NODE_PORT=${LOCAL_CONNECTION_PORT}`]
60
+ environment: [`RABBITMQ_NODE_PORT=${LOCAL_CONNECTION_PORT}`],
61
+ volumes: [
62
+ './rabbitmq/:/var/lib/rabbitmq/',
63
+ './rabbitmq/log/:/var/log/rabbitmq/'
64
+ ]
61
65
  }
62
66
  }
63
67
  };
@@ -5,7 +5,8 @@ import {
5
5
  addModelCliLeaf,
6
6
  removeModelCliLeaf,
7
7
  replaceModelsCliLeaf,
8
- updateModelsCliLeaf
8
+ updateModelsCliLeaf,
9
+ installModelCliLeaf
9
10
  } from './models';
10
11
  import {
11
12
  getAppStatusCliLeaf,
@@ -39,6 +40,7 @@ export const appCliBranch = CliBranch({
39
40
  addModelCliLeaf,
40
41
  removeModelCliLeaf,
41
42
  replaceModelsCliLeaf,
43
+ installModelCliLeaf,
42
44
  updateModelsCliLeaf,
43
45
  getAllEnvsCliLeaf,
44
46
  setEnvCliLeaf,