-
Notifications
You must be signed in to change notification settings - Fork 30
/
13b-getenv.js
174 lines (149 loc) · 5.24 KB
/
13b-getenv.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
//
// Copyright (c) 2020 Cisco Systems
// Licensed under the MIT License
//
/**
* Implements Environment Variables for Macros:
* A. environment.js : this macro manages volatile ENV variables (stores/updates and returns the current values for an environment variable)
* B* getenv.js : this is not a macro but a code snippet that you insert into existing macros to retrieve ENV variables (local to your device)
*
* Quick start:
* - customize the default list of ENV variables for your device
* - deploy the 'environment.js' macro to your device
* - insert the 'getenv()' code snipped into other macros on the same device
* - access ENV variables from macros once 'env-ready' event is emmitted
*
* Note: if a variable is not found in ENV, '' is returned (empty)
*
* Example of a Macro using the getenv() function:
*
* // Fired when the environnment Macro is ready to provide ENV variables
* xapi.on('env-ready', async (ready) => {
* if (!ready) {
* console.log('Environment macro is not responding! aborting...');
* return;
* }
*
* let variable = 'DEVICE_SECRET'
* let secret = await getenv(variable);
* console.log(`echo \$${variable} = ${secret}`);
* });
*
*/
const xapi = require('xapi');
// Fired when the environnment Macro is ready to provide ENV variables
xapi.on('env-ready', async (ready) => {
if (!ready) {
console.log('Environment macro is not responding! aborting...');
return;
}
// Example
let variable = 'DEVICE_SECRET'
let secret = await getenv(variable);
console.log(`echo \$${variable} = ${secret}`);
});
//
// getenv()
//
// Asks the 'Environment' macro to send the value of an environment variable
const ENV_TIMEOUT = 500; // delay for the environment macro to respond
function getenv(variable) {
return new Promise((resolve, reject) => {
let context = {}
// Wait for response from 'Environment' macro
context.stop = xapi.event.on("Message Send Text", function (msg) {
let parsed;
try {
parsed = JSON.parse(msg);
}
catch (err) {
console.debug(`cannot JSON parse "MessageSent" event: ${msg}: it's ok, simply ignoring this event`);
return;
}
let data = parsed;
if (data.operation && (data.operation == "get_response")) {
console.debug(`received value: "${data.value}" for env variable: "${data.env}"`);
// Check this is the variable we have requested
if (variable != data.env) {
console.debug(`received incorrect variable, ${data.env} instead of ${variable}, ignoring...`);
return;
}
// If found, stop listening
if (context.stop) {
console.debug(`unsubscribe from "Message Send" events, for variable: ${variable}`);
context.stop();
delete context.stop;
}
resolve(data.value);
return;
}
console.debug(`ignoring "Message Sent" event, not a get_response: ${msg}`);
});
// Send request to get the value for the variable
let data = {
'operation': 'get',
'env': variable
};
xapi.command('Message Send', { Text: JSON.stringify(data) }).then(() => {
// The Environment macro should respond before TIMEOUT
setTimeout(() => {
if (context.stop) {
console.debug(`unsubscribe from Message send for: ${variable}`);
context.stop();
delete context.stop;
}
let error = new Error('Environment Timeout');
error.code = "TIMEOUT";
return reject(error);
}, ENV_TIMEOUT);
});
});
}
// Introduce a new event 'env-ready' that fires when 'Environment' macro is ready:
//
// xapi.on('env-ready')
//
const ENV_RETRY_DELAY = 500;
xapi.on('ready', async () => {
const NB_RETRIES = 4;
let retries = 0;
while (retries < NB_RETRIES) {
if (await checkEnvironmentIsReady()) {
xapi.emit('env-ready', true);
return;
}
else {
// Wait exponentially before retrying
// note: this elapsed time comes on top of the ENV_TIMEOUT for the 'getenv()' function
await timeout(retries * retries * ENV_RETRY_DELAY);
retries++;
}
}
console.debug(`no response from the Environment macro after ${NB_RETRIES} tentatives, is it running?`);
xapi.emit('env-ready', false);
});
function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function checkEnvironmentIsReady() {
try {
let value = await getenv('PING');
if ('PONG' == value) {
console.debug('PING => PONG: good to proceed...')
console.debug('"Environment" macro is operational');
return true;
}
else {
console.debug('Environment" macro is NOT operational: unexpected value');
return false;
}
}
catch (err) {
if (err.code == 'TIMEOUT') {
console.debug('Environment" macro is NOT operational: timeout');
return false;
}
console.debug('"Environment" macro is NOT operational: unexpected error');
return false;
}
}