@alwaysai/device-agent 2.0.0 → 2.0.2-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.
- package/lib/application-control/environment-variables.d.ts +4 -0
- package/lib/application-control/environment-variables.d.ts.map +1 -1
- package/lib/application-control/environment-variables.js +17 -13
- package/lib/application-control/environment-variables.js.map +1 -1
- package/lib/application-control/install.d.ts +4 -1
- package/lib/application-control/install.d.ts.map +1 -1
- package/lib/application-control/install.js +16 -1
- package/lib/application-control/install.js.map +1 -1
- package/lib/application-control/utils.d.ts.map +1 -1
- package/lib/application-control/utils.js +13 -0
- package/lib/application-control/utils.js.map +1 -1
- package/lib/cloud-connection/base-message-handler.d.ts +27 -0
- package/lib/cloud-connection/base-message-handler.d.ts.map +1 -0
- package/lib/cloud-connection/base-message-handler.js +72 -0
- package/lib/cloud-connection/base-message-handler.js.map +1 -0
- package/lib/cloud-connection/connection-manager.d.ts +20 -0
- package/lib/cloud-connection/connection-manager.d.ts.map +1 -0
- package/lib/cloud-connection/connection-manager.js +164 -0
- package/lib/cloud-connection/connection-manager.js.map +1 -0
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts +7 -23
- package/lib/cloud-connection/device-agent-cloud-connection.d.ts.map +1 -1
- package/lib/cloud-connection/device-agent-cloud-connection.js +49 -517
- package/lib/cloud-connection/device-agent-cloud-connection.js.map +1 -1
- package/lib/cloud-connection/device-agent-message-handler.d.ts +22 -0
- package/lib/cloud-connection/device-agent-message-handler.d.ts.map +1 -0
- package/lib/cloud-connection/device-agent-message-handler.js +357 -0
- package/lib/cloud-connection/device-agent-message-handler.js.map +1 -0
- package/lib/cloud-connection/live-updates-handler.d.ts +1 -0
- package/lib/cloud-connection/live-updates-handler.d.ts.map +1 -1
- package/lib/cloud-connection/live-updates-handler.js +13 -10
- package/lib/cloud-connection/live-updates-handler.js.map +1 -1
- package/lib/cloud-connection/message-dispatcher.d.ts +10 -0
- package/lib/cloud-connection/message-dispatcher.d.ts.map +1 -0
- package/lib/cloud-connection/message-dispatcher.js +27 -0
- package/lib/cloud-connection/message-dispatcher.js.map +1 -0
- package/lib/cloud-connection/publisher.d.ts +3 -2
- package/lib/cloud-connection/publisher.d.ts.map +1 -1
- package/lib/cloud-connection/publisher.js +8 -4
- package/lib/cloud-connection/publisher.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.d.ts +7 -0
- package/lib/cloud-connection/shadow-handler.d.ts.map +1 -1
- package/lib/cloud-connection/shadow-handler.js +77 -1
- package/lib/cloud-connection/shadow-handler.js.map +1 -1
- package/lib/cloud-connection/shadow-handler.test.js +5 -2
- package/lib/cloud-connection/shadow-handler.test.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.d.ts +9 -4
- package/lib/cloud-connection/transaction-manager.d.ts.map +1 -1
- package/lib/cloud-connection/transaction-manager.js +22 -11
- package/lib/cloud-connection/transaction-manager.js.map +1 -1
- package/lib/cloud-connection/transaction-manager.test.js +43 -14
- package/lib/cloud-connection/transaction-manager.test.js.map +1 -1
- package/lib/jobs/job-handler.d.ts +23 -0
- package/lib/jobs/job-handler.d.ts.map +1 -0
- package/lib/jobs/job-handler.js +131 -0
- package/lib/jobs/job-handler.js.map +1 -0
- package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts +8 -0
- package/lib/secure-tunneling/secure-tunnel-message-handler.d.ts.map +1 -0
- package/lib/secure-tunneling/secure-tunnel-message-handler.js +42 -0
- package/lib/secure-tunneling/secure-tunnel-message-handler.js.map +1 -0
- package/lib/subcommands/app/version.d.ts +2 -0
- package/lib/subcommands/app/version.d.ts.map +1 -1
- package/lib/subcommands/app/version.js +14 -2
- package/lib/subcommands/app/version.js.map +1 -1
- package/package.json +2 -2
- package/src/application-control/environment-variables.ts +31 -21
- package/src/application-control/install.ts +24 -3
- package/src/application-control/utils.ts +13 -0
- package/src/cloud-connection/base-message-handler.ts +118 -0
- package/src/cloud-connection/connection-manager.ts +196 -0
- package/src/cloud-connection/device-agent-cloud-connection.ts +104 -817
- package/src/cloud-connection/device-agent-message-handler.ts +642 -0
- package/src/cloud-connection/live-updates-handler.ts +26 -18
- package/src/cloud-connection/message-dispatcher.ts +33 -0
- package/src/cloud-connection/publisher.ts +28 -23
- package/src/cloud-connection/shadow-handler.test.ts +6 -2
- package/src/cloud-connection/shadow-handler.ts +129 -1
- package/src/cloud-connection/transaction-manager.test.ts +55 -24
- package/src/cloud-connection/transaction-manager.ts +42 -31
- package/src/jobs/job-handler.ts +146 -0
- package/src/secure-tunneling/secure-tunnel-message-handler.ts +56 -0
- package/src/subcommands/app/version.ts +20 -2
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { MessageHandler } from '../cloud-connection/message-dispatcher';
|
|
2
|
+
import { logger } from '../util/logger';
|
|
3
|
+
import {
|
|
4
|
+
BaseHandler,
|
|
5
|
+
HandlerContext
|
|
6
|
+
} from '../cloud-connection/base-message-handler';
|
|
7
|
+
import { DeviceAgentMessageHandler } from '../cloud-connection/device-agent-message-handler';
|
|
8
|
+
|
|
9
|
+
class JobState {
|
|
10
|
+
private static instance: JobState;
|
|
11
|
+
public jobInProgress = false;
|
|
12
|
+
|
|
13
|
+
// Singleton pattern
|
|
14
|
+
private constructor() { } // eslint-disable-line
|
|
15
|
+
|
|
16
|
+
static getInstance(): JobState {
|
|
17
|
+
if (!JobState.instance) {
|
|
18
|
+
JobState.instance = new JobState();
|
|
19
|
+
}
|
|
20
|
+
return JobState.instance;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export class JobHandler extends BaseHandler implements MessageHandler {
|
|
25
|
+
private readonly msgHandler: DeviceAgentMessageHandler;
|
|
26
|
+
|
|
27
|
+
constructor(handlerContext: HandlerContext) {
|
|
28
|
+
super(handlerContext);
|
|
29
|
+
this.msgHandler = new DeviceAgentMessageHandler(
|
|
30
|
+
handlerContext,
|
|
31
|
+
this.handleJobError,
|
|
32
|
+
this.handleJobSuccess
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
private readonly state = JobState.getInstance();
|
|
36
|
+
private jobId = '';
|
|
37
|
+
|
|
38
|
+
public async handle(message: any, topic: string): Promise<void> {
|
|
39
|
+
const TOPICS = this.getJobTopic();
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
switch (topic) {
|
|
43
|
+
case TOPICS.NOTIFY_NEXT:
|
|
44
|
+
await this.notifyNext(message);
|
|
45
|
+
break;
|
|
46
|
+
case TOPICS.START_NEXT_ACCEPTED:
|
|
47
|
+
this.startNextAccepted(message);
|
|
48
|
+
break;
|
|
49
|
+
default:
|
|
50
|
+
logger.info(`No handler for topic: ${topic}`);
|
|
51
|
+
}
|
|
52
|
+
} catch (error) {
|
|
53
|
+
logger.error(`Error handling job for topic: ${topic}`, error);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getJobTopic() {
|
|
58
|
+
const TOPICS = {
|
|
59
|
+
NOTIFY_NEXT: `$aws/things/${this.clientId}/jobs/notify-next`,
|
|
60
|
+
START_NEXT: `$aws/things/${this.clientId}/jobs/start-next`,
|
|
61
|
+
START_NEXT_ACCEPTED: `$aws/things/${this.clientId}/jobs/start-next/accepted`,
|
|
62
|
+
UPDATE: `$aws/things/${this.clientId}/jobs/${this.jobId}/update`
|
|
63
|
+
};
|
|
64
|
+
return TOPICS;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private async notifyNext(message: any): Promise<void> {
|
|
68
|
+
// Triggers when a job is completed and we need to notify the next job
|
|
69
|
+
logger.info('Invoking NOTIFY_NEXT handler');
|
|
70
|
+
const TOPICS = this.getJobTopic();
|
|
71
|
+
this.publisher.publish(TOPICS.START_NEXT, JSON.stringify({}));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private startNextAccepted(message: any): void {
|
|
75
|
+
if (this.state.jobInProgress) {
|
|
76
|
+
logger.info('Job already in progress');
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
this.state.jobInProgress = true;
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
if (message.execution) {
|
|
84
|
+
this.processJobExecution(message.execution);
|
|
85
|
+
} else {
|
|
86
|
+
this.state.jobInProgress = false;
|
|
87
|
+
}
|
|
88
|
+
} catch (error: unknown) {
|
|
89
|
+
this.handleError(error);
|
|
90
|
+
}
|
|
91
|
+
this.state.jobInProgress = false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private processJobExecution(execution: any): void {
|
|
95
|
+
logger.info('Job in progress...');
|
|
96
|
+
const { jobDocument, jobId } = execution;
|
|
97
|
+
this.jobId = jobId;
|
|
98
|
+
this.msgHandler.handle(jobDocument);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
private handleError(error: unknown): void {
|
|
102
|
+
if (error instanceof Error) {
|
|
103
|
+
logger.error(`Error starting next job`, error);
|
|
104
|
+
this.handleJobError('', error.message);
|
|
105
|
+
} else {
|
|
106
|
+
let errorMessage: string;
|
|
107
|
+
if (typeof error === 'string') {
|
|
108
|
+
errorMessage = error;
|
|
109
|
+
} else if (typeof error === 'object' && error !== null) {
|
|
110
|
+
try {
|
|
111
|
+
errorMessage = JSON.stringify(error);
|
|
112
|
+
} catch (jsonError) {
|
|
113
|
+
errorMessage = 'Unknown error (failed to stringify)';
|
|
114
|
+
}
|
|
115
|
+
} else {
|
|
116
|
+
errorMessage = 'Unknown error';
|
|
117
|
+
}
|
|
118
|
+
logger.error(`Unexpected error: ${errorMessage}`);
|
|
119
|
+
this.handleJobError('', errorMessage);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
private updateJobStatus(status: string, message?: string): void {
|
|
124
|
+
const { UPDATE } = this.getJobTopic();
|
|
125
|
+
const payload = {
|
|
126
|
+
status,
|
|
127
|
+
statusDetails: {
|
|
128
|
+
message
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
this.publisher.publish(UPDATE, JSON.stringify(payload));
|
|
133
|
+
logger.info(`Marked job ${this.jobId} as ${status}`);
|
|
134
|
+
// Reset the job state
|
|
135
|
+
this.state.jobInProgress = false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private readonly handleJobSuccess = (txId: string): void => {
|
|
139
|
+
this.updateJobStatus('SUCCEEDED');
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
private readonly handleJobError = (_txId: string, msg: string): void => {
|
|
143
|
+
logger.error(`Unexpected error type: ${msg}`);
|
|
144
|
+
this.updateJobStatus('FAILED', `Unexpected error: ${msg}`);
|
|
145
|
+
};
|
|
146
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getUpdateDeltaStateFromMessage,
|
|
3
|
+
validateSecureTunnelShadowUpdate
|
|
4
|
+
} from '@alwaysai/device-agent-schemas';
|
|
5
|
+
import { MessageHandler } from '../cloud-connection/message-dispatcher';
|
|
6
|
+
import { logger } from '../util/logger';
|
|
7
|
+
import { BaseHandler } from '../cloud-connection/base-message-handler';
|
|
8
|
+
|
|
9
|
+
export class SecureTunnelMessageHandler
|
|
10
|
+
extends BaseHandler
|
|
11
|
+
implements MessageHandler<any>
|
|
12
|
+
{
|
|
13
|
+
public getNotifyTopic(): string {
|
|
14
|
+
return `$aws/things/${this.clientId}/tunnels/notify`;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
public async handle(message: any, topic: string): Promise<void> {
|
|
18
|
+
const secureTunnelNotifyTopic = this.getNotifyTopic();
|
|
19
|
+
if (topic === secureTunnelNotifyTopic) {
|
|
20
|
+
await this.secureTunnelHandler.secureTunnelNotifyHandler(message);
|
|
21
|
+
} else if (
|
|
22
|
+
topic === this.shadowHandler.shadowTopics.secureTunnel.updateDelta
|
|
23
|
+
) {
|
|
24
|
+
logger.info(`Received secure tunnel update: ${JSON.stringify(message)}`);
|
|
25
|
+
await this.handleSecureTunnelMessage(message);
|
|
26
|
+
} else if (
|
|
27
|
+
topic === this.shadowHandler.shadowTopics.secureTunnel.deleteAccepted
|
|
28
|
+
) {
|
|
29
|
+
logger.info(`Received secure tunnel deleteAccepted: ${message}`);
|
|
30
|
+
await this.secureTunnelHandler.destroy();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
public async handleSecureTunnelMessage(payload: any): Promise<void> {
|
|
35
|
+
logger.info(`Received secure tunnel update: ${JSON.stringify(payload)}`);
|
|
36
|
+
const state = getUpdateDeltaStateFromMessage(payload);
|
|
37
|
+
if (!state) {
|
|
38
|
+
logger.debug(`No state found in message: ${JSON.stringify(payload)}`);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const valid = validateSecureTunnelShadowUpdate(state);
|
|
42
|
+
if (!valid) {
|
|
43
|
+
logger.error(
|
|
44
|
+
`Error validating message: ${JSON.stringify(
|
|
45
|
+
{ payload, errors: validateSecureTunnelShadowUpdate.errors },
|
|
46
|
+
null,
|
|
47
|
+
2
|
|
48
|
+
)}`
|
|
49
|
+
);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const secureTunnelUpdate =
|
|
53
|
+
await this.secureTunnelHandler.syncShadowToDeviceState(payload);
|
|
54
|
+
await this.shadowHandler.updateSecureTunnelShadow(secureTunnelUpdate);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -37,10 +37,26 @@ export const installAppCliLeaf = CliLeaf({
|
|
|
37
37
|
description: 'Release Hash',
|
|
38
38
|
required: false,
|
|
39
39
|
hidden: true
|
|
40
|
+
}),
|
|
41
|
+
appCfg: CliStringInput({
|
|
42
|
+
description: 'Application Configuration',
|
|
43
|
+
required: false,
|
|
44
|
+
hidden: true
|
|
45
|
+
}),
|
|
46
|
+
envVars: CliStringInput({
|
|
47
|
+
description: 'Environment Variables configuration',
|
|
48
|
+
hidden: true,
|
|
49
|
+
required: false
|
|
40
50
|
})
|
|
41
51
|
},
|
|
42
52
|
async action(_, opts) {
|
|
43
|
-
const {
|
|
53
|
+
const {
|
|
54
|
+
project,
|
|
55
|
+
releaseHash,
|
|
56
|
+
'release-hash': releaseHashNew,
|
|
57
|
+
appCfg,
|
|
58
|
+
envVars
|
|
59
|
+
} = opts;
|
|
44
60
|
if (releaseHash) {
|
|
45
61
|
logger.warn(
|
|
46
62
|
`--releaseHash is deprecated and will be removed in a future release. Please switch to --release-hash`
|
|
@@ -60,7 +76,9 @@ export const installAppCliLeaf = CliLeaf({
|
|
|
60
76
|
payload: {
|
|
61
77
|
baseCommand: keyMirrors.appVersionControl.install,
|
|
62
78
|
projectId: project,
|
|
63
|
-
appReleaseHash: releaseHashResolved
|
|
79
|
+
appReleaseHash: releaseHashResolved,
|
|
80
|
+
appCfg,
|
|
81
|
+
envVars
|
|
64
82
|
}
|
|
65
83
|
};
|
|
66
84
|
await deviceAgent.handleMessage(topic, message);
|