@node-red/runtime 3.0.0-beta.1 → 3.0.0-beta.4

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.
@@ -165,7 +165,7 @@ function buildDiagnosticReport(scope, callback) {
165
165
 
166
166
  /** gets a sanitised list containing only the module name */
167
167
  function listContextModules() {
168
- const keys = Object.keys(runtime.settings.contextStorage);
168
+ const keys = Object.keys(runtime.settings.contextStorage || {});
169
169
  const result = {};
170
170
  keys.forEach(e => {
171
171
  result[e] = {
package/lib/api/flows.js CHANGED
@@ -255,5 +255,82 @@ var api = module.exports = {
255
255
  }
256
256
  }
257
257
  return sendCredentials;
258
- }
258
+ },
259
+ /**
260
+ * Gets running state of runtime flows
261
+ * @param {Object} opts
262
+ * @param {User} opts.user - the user calling the api
263
+ * @param {Object} opts.req - the request to log (optional)
264
+ * @return {{state:string, started:boolean}} - the current run state of the flows
265
+ * @memberof @node-red/runtime_flows
266
+ */
267
+ getState: async function(opts) {
268
+ runtime.log.audit({event: "flows.getState"}, opts.req);
269
+ const result = {
270
+ state: runtime.flows.state()
271
+ }
272
+ return result;
273
+ },
274
+ /**
275
+ * Sets running state of runtime flows
276
+ * @param {Object} opts
277
+ * @param {Object} opts.req - the request to log (optional)
278
+ * @param {User} opts.user - the user calling the api
279
+ * @param {string} opts.state - the requested state. Valid values are "start" and "stop".
280
+ * @return {Promise<Flow>} - the active flow configuration
281
+ * @memberof @node-red/runtime_flows
282
+ */
283
+ setState: async function(opts) {
284
+ opts = opts || {};
285
+ const makeError = (error, errcode, statusCode) => {
286
+ const message = typeof error == "object" ? error.message : error
287
+ const err = typeof error == "object" ? error : new Error(message||"Unexpected Error")
288
+ err.status = err.status || statusCode || 400;
289
+ err.code = err.code || errcode || "unexpected_error"
290
+ runtime.log.audit({
291
+ event: "flows.setState",
292
+ state: opts.state || "",
293
+ error: errcode || "unexpected_error",
294
+ message: err.code
295
+ }, opts.req);
296
+ return err
297
+ }
298
+
299
+ const getState = () => {
300
+ return {
301
+ state: runtime.flows.state()
302
+ }
303
+ }
304
+
305
+ if(!runtime.settings.runtimeState || runtime.settings.runtimeState.enabled !== true) {
306
+ throw (makeError("Method Not Allowed", "not_allowed", 405))
307
+ }
308
+ switch (opts.state) {
309
+ case "start":
310
+ try {
311
+ try {
312
+ runtime.settings.set('runtimeFlowState', opts.state);
313
+ } catch(err) {}
314
+ if (runtime.settings.safeMode) {
315
+ delete runtime.settings.safeMode
316
+ }
317
+ await runtime.flows.startFlows("full")
318
+ return getState()
319
+ } catch (err) {
320
+ throw (makeError(err, err.code, 500))
321
+ }
322
+ case "stop":
323
+ try {
324
+ try {
325
+ runtime.settings.set('runtimeFlowState', opts.state);
326
+ } catch(err) {}
327
+ await runtime.flows.stopFlows("full")
328
+ return getState()
329
+ } catch (err) {
330
+ throw (makeError(err, err.code, 500))
331
+ }
332
+ default:
333
+ throw (makeError(`Cannot change flows runtime state to '${opts.state}'}`, "invalid_run_state", 400))
334
+ }
335
+ },
259
336
  }
@@ -91,7 +91,7 @@ var api = module.exports = {
91
91
  safeSettings.context = runtime.nodes.listContextStores();
92
92
  if (runtime.settings.editorTheme && runtime.settings.editorTheme.codeEditor) {
93
93
  safeSettings.codeEditor = runtime.settings.editorTheme.codeEditor || {};
94
- safeSettings.codeEditor.lib = safeSettings.codeEditor.lib || "ace";
94
+ safeSettings.codeEditor.lib = safeSettings.codeEditor.lib || "monaco";
95
95
  safeSettings.codeEditor.options = safeSettings.codeEditor.options || {};
96
96
  }
97
97
  safeSettings.libraries = runtime.library.getLibraries();
@@ -148,6 +148,18 @@ var api = module.exports = {
148
148
  enabled: (runtime.settings.diagnostics && runtime.settings.diagnostics.enabled === false) ? false : true,
149
149
  ui: (runtime.settings.diagnostics && runtime.settings.diagnostics.ui === false) ? false : true
150
150
  }
151
+ if(safeSettings.diagnostics.enabled === false) {
152
+ safeSettings.diagnostics.ui = false; // cannot have UI without endpoint
153
+ }
154
+
155
+ safeSettings.runtimeState = {
156
+ //unless runtimeState.ui and runtimeState.enabled are explicitly true, they will default to false.
157
+ enabled: !!runtime.settings.runtimeState && runtime.settings.runtimeState.enabled === true,
158
+ ui: !!runtime.settings.runtimeState && runtime.settings.runtimeState.ui === true
159
+ }
160
+ if(safeSettings.runtimeState.enabled !== true) {
161
+ safeSettings.runtimeState.ui = false; // cannot have UI without endpoint
162
+ }
151
163
 
152
164
  runtime.settings.exportNodeSettings(safeSettings);
153
165
  runtime.plugins.exportPluginSettings(safeSettings);
@@ -36,6 +36,8 @@ var activeFlowConfig = null;
36
36
 
37
37
  var activeFlows = {};
38
38
  var started = false;
39
+ var state = 'stop'
40
+
39
41
  var credentialsPendingReset = false;
40
42
 
41
43
  var activeNodesToFlow = {};
@@ -50,6 +52,7 @@ function init(runtime) {
50
52
  storage = runtime.storage;
51
53
  log = runtime.log;
52
54
  started = false;
55
+ state = 'stop';
53
56
  if (!typeEventRegistered) {
54
57
  events.on('type-registered',function(type) {
55
58
  if (activeFlowConfig && activeFlowConfig.missingTypes.length > 0) {
@@ -214,19 +217,26 @@ function setFlows(_config,_credentials,type,muteLog,forceStart,user) {
214
217
  // Flows are running (or should be)
215
218
 
216
219
  // Stop the active flows (according to deploy type and the diff)
217
- return stop(type,diff,muteLog).then(() => {
220
+ return stop(type,diff,muteLog,true).then(() => {
218
221
  // Once stopped, allow context to remove anything no longer needed
219
222
  return context.clean(activeFlowConfig)
220
223
  }).then(() => {
224
+ if (!isLoad) {
225
+ log.info(log._("nodes.flows.updated-flows"));
226
+ }
221
227
  // Start the active flows
222
- start(type,diff,muteLog).then(() => {
228
+ start(type,diff,muteLog,true).then(() => {
223
229
  events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true});
224
230
  });
225
231
  // Return the new revision asynchronously to the actual start
226
232
  return flowRevision;
227
233
  }).catch(function(err) { })
228
234
  } else {
235
+ if (!isLoad) {
236
+ log.info(log._("nodes.flows.updated-flows"));
237
+ }
229
238
  events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true});
239
+ return flowRevision;
230
240
  }
231
241
  });
232
242
  }
@@ -259,9 +269,10 @@ function getFlows() {
259
269
  return activeConfig;
260
270
  }
261
271
 
262
- async function start(type,diff,muteLog) {
263
- type = type||"full";
272
+ async function start(type,diff,muteLog,isDeploy) {
273
+ type = type || "full";
264
274
  started = true;
275
+ state = 'start'
265
276
  var i;
266
277
  // If there are missing types, report them, emit the necessary runtime event and return
267
278
  if (activeFlowConfig.missingTypes.length > 0) {
@@ -283,7 +294,7 @@ async function start(type,diff,muteLog) {
283
294
  log.info(log._("nodes.flows.missing-type-install-2"));
284
295
  log.info(" "+settings.userDir);
285
296
  }
286
- events.emit("runtime-event",{id:"runtime-state",payload:{error:"missing-types", type:"warning",text:"notification.warnings.missing-types",types:activeFlowConfig.missingTypes},retain:true});
297
+ events.emit("runtime-event",{id:"runtime-state",payload:{state: 'stop', error:"missing-types", type:"warning",text:"notification.warnings.missing-types",types:activeFlowConfig.missingTypes},retain:true});
287
298
  return;
288
299
  }
289
300
 
@@ -297,7 +308,7 @@ async function start(type,diff,muteLog) {
297
308
  missingModules.push({module:err[i].module.module, error: err[i].error.code || err[i].error.toString()})
298
309
  log.info(` - ${err[i].module.spec} [${err[i].error.code || "unknown_error"}]`);
299
310
  }
300
- events.emit("runtime-event",{id:"runtime-state",payload:{error:"missing-modules", type:"warning",text:"notification.warnings.missing-modules",modules:missingModules},retain:true});
311
+ events.emit("runtime-event",{id:"runtime-state",payload:{state: 'stop', error:"missing-modules", type:"warning",text:"notification.warnings.missing-modules",modules:missingModules},retain:true});
301
312
  return;
302
313
  }
303
314
 
@@ -306,10 +317,23 @@ async function start(type,diff,muteLog) {
306
317
  log.info("*****************************************************************")
307
318
  log.info(log._("nodes.flows.safe-mode"));
308
319
  log.info("*****************************************************************")
309
- events.emit("runtime-event",{id:"runtime-state",payload:{error:"safe-mode", type:"warning",text:"notification.warnings.safe-mode"},retain:true});
320
+ state = 'safe'
321
+ events.emit("runtime-event",{id:"runtime-state",payload:{state: 'safe', error:"safe-mode", type:"warning",text:"notification.warnings.safe-mode"},retain:true});
310
322
  return;
311
323
  }
312
324
 
325
+ let runtimeState
326
+ try {
327
+ runtimeState = settings.get('runtimeFlowState') || 'start'
328
+ } catch (err) {}
329
+ if (runtimeState === 'stop') {
330
+ log.info(log._("nodes.flows.stopped-flows"));
331
+ events.emit("runtime-event",{id:"runtime-state",payload:{ state: 'stop', deploy:isDeploy },retain:true});
332
+ state = 'stop'
333
+ started = false
334
+ return
335
+ }
336
+
313
337
  if (!muteLog) {
314
338
  if (type !== "full") {
315
339
  log.info(log._("nodes.flows.starting-modified-"+type));
@@ -364,12 +388,10 @@ async function start(type,diff,muteLog) {
364
388
  }
365
389
  }
366
390
  }
367
- // Having created or updated all flows, now start them.
368
391
  for (id in activeFlows) {
369
392
  if (activeFlows.hasOwnProperty(id)) {
370
393
  try {
371
394
  activeFlows[id].start(diff);
372
-
373
395
  // Create a map of node id to flow id and also a subflowInstance lookup map
374
396
  var activeNodes = activeFlows[id].getActiveNodes();
375
397
  Object.keys(activeNodes).forEach(function(nid) {
@@ -387,7 +409,7 @@ async function start(type,diff,muteLog) {
387
409
  if (credentialsPendingReset === true) {
388
410
  credentialsPendingReset = false;
389
411
  } else {
390
- events.emit("runtime-event",{id:"runtime-state",retain:true});
412
+ events.emit("runtime-event",{id:"runtime-state", payload:{ state: 'start', deploy:isDeploy}, retain:true});
391
413
  }
392
414
 
393
415
  if (!muteLog) {
@@ -400,7 +422,7 @@ async function start(type,diff,muteLog) {
400
422
  return;
401
423
  }
402
424
 
403
- function stop(type,diff,muteLog) {
425
+ function stop(type,diff,muteLog,isDeploy) {
404
426
  if (!started) {
405
427
  return Promise.resolve();
406
428
  }
@@ -420,6 +442,7 @@ function stop(type,diff,muteLog) {
420
442
  }
421
443
  }
422
444
  started = false;
445
+ state = 'stop'
423
446
  var promises = [];
424
447
  var stopList;
425
448
  var removedList = diff.removed;
@@ -471,6 +494,8 @@ function stop(type,diff,muteLog) {
471
494
  }
472
495
  }
473
496
  events.emit("flows:stopped",{config: activeConfig, type: type, diff: diff});
497
+
498
+ events.emit("runtime-event",{ id:"runtime-state", payload:{ state: 'stop', deploy:isDeploy }, retain:true });
474
499
  // Deprecated event
475
500
  events.emit("nodes-stopped");
476
501
  });
@@ -790,7 +815,7 @@ module.exports = {
790
815
  stopFlows: stop,
791
816
 
792
817
  get started() { return started },
793
-
818
+ state: () => { return state },
794
819
  // handleError: handleError,
795
820
  // handleStatus: handleStatus,
796
821
 
package/lib/index.js CHANGED
@@ -215,7 +215,7 @@ function start() {
215
215
  }
216
216
  }
217
217
  return redNodes.loadContextsPlugin().then(function () {
218
- redNodes.loadFlows().then(redNodes.startFlows).catch(function(err) {});
218
+ redNodes.loadFlows().then(() => { redNodes.startFlows() }).catch(function(err) {});
219
219
  started = true;
220
220
  });
221
221
  });
@@ -399,12 +399,12 @@ module.exports = {
399
399
  * @memberof @node-red/runtime
400
400
  */
401
401
  version: externalAPI.version,
402
-
402
+
403
403
  /**
404
404
  * @memberof @node-red/diagnostics
405
405
  */
406
406
  diagnostics:externalAPI.diagnostics,
407
-
407
+
408
408
  storage: storage,
409
409
  events: events,
410
410
  hooks: hooks,
@@ -8,7 +8,6 @@
8
8
  "httpStatic": "HTTP Static : __path__"
9
9
  }
10
10
  },
11
-
12
11
  "server": {
13
12
  "loading": "Loading palette nodes",
14
13
  "palette-editor": {
@@ -61,7 +60,6 @@
61
60
  "function-required": "httpsRefreshInterval requires https property to be a function"
62
61
  }
63
62
  },
64
-
65
63
  "api": {
66
64
  "flows": {
67
65
  "error-save": "Error saving flows: __message__",
@@ -79,18 +77,16 @@
79
77
  "error-enable": "Failed to enable node:"
80
78
  }
81
79
  },
82
-
83
80
  "comms": {
84
81
  "error": "Communication channel error: __message__",
85
82
  "error-server": "Communication server error: __message__",
86
83
  "error-send": "Communication send error: __message__"
87
84
  },
88
-
89
85
  "settings": {
90
86
  "user-not-available": "Cannot save user settings: __message__",
91
87
  "not-available": "Settings not available",
92
88
  "property-read-only": "Property '__prop__' is read-only",
93
- "readonly-mode" : "Runtime in read-only mode. Changes will not be saved."
89
+ "readonly-mode": "Runtime in read-only mode. Changes will not be saved."
94
90
  },
95
91
  "library": {
96
92
  "unknownLibrary": "Unknown library: __library__",
@@ -101,12 +97,12 @@
101
97
  },
102
98
  "nodes": {
103
99
  "credentials": {
104
- "error":"Error loading credentials: __message__",
105
- "error-saving":"Error saving credentials: __message__",
100
+ "error": "Error loading credentials: __message__",
101
+ "error-saving": "Error saving credentials: __message__",
106
102
  "not-registered": "Credential type '__type__' is not registered",
107
103
  "system-key-warning": "\n\n---------------------------------------------------------------------\nYour flow credentials file is encrypted using a system-generated key.\n\nIf the system-generated key is lost for any reason, your credentials\nfile will not be recoverable, you will have to delete it and re-enter\nyour credentials.\n\nYou should set your own key using the 'credentialSecret' option in\nyour settings file. Node-RED will then re-encrypt your credentials\nfile using your chosen key the next time you deploy a change.\n---------------------------------------------------------------------\n",
108
- "unencrypted" : "Using unencrypted credentials",
109
- "encryptedNotFound" : "Encrypted credentials not found"
104
+ "unencrypted": "Using unencrypted credentials",
105
+ "encryptedNotFound": "Encrypted credentials not found"
110
106
  },
111
107
  "flows": {
112
108
  "safe-mode": "Flows stopped in safe mode. Deploy to start.",
@@ -126,6 +122,7 @@
126
122
  "stopped-flows": "Stopped flows",
127
123
  "stopped": "Stopped",
128
124
  "stopping-error": "Error stopping node: __message__",
125
+ "updated-flows": "Updated flows",
129
126
  "added-flow": "Adding flow: __label__",
130
127
  "updated-flow": "Updated flow: __label__",
131
128
  "removed-flow": "Removed flow: __label__",
@@ -150,7 +147,6 @@
150
147
  }
151
148
  }
152
149
  },
153
-
154
150
  "storage": {
155
151
  "index": {
156
152
  "forbidden-flow-name": "forbidden flow name"
@@ -180,7 +176,6 @@
180
176
  }
181
177
  }
182
178
  },
183
-
184
179
  "context": {
185
180
  "log-store-init": "Context store : '__name__' [__info__]",
186
181
  "error-loading-module": "Error loading context store: __message__",
@@ -195,5 +190,4 @@
195
190
  "error-write": "Error writing context: __message__"
196
191
  }
197
192
  }
198
-
199
193
  }
@@ -100,7 +100,9 @@
100
100
  "error": "クレデンシャルの読み込みエラー: __message__",
101
101
  "error-saving": "クレデンシャルの保存エラー: __message__",
102
102
  "not-registered": "クレデンシャル '__type__' は登録されていません",
103
- "system-key-warning": "\n\n---------------------------------------------------------------------\nフローのクレデンシャルファイルはシステム生成キーで暗号化されています。\n\nシステム生成キーを何らかの理由で失った場合、クレデンシャルファイルを\n復元することはできません。その場合、ファイルを削除してクレデンシャルを\n再入力しなければなりません。\n\n設定ファイル内で 'credentialSecret' オプションを使って独自キーを設定\nします。変更を次にデプロイする際、Node-REDは選択したキーを用いてクレ\nデンシャルを再暗号化します。 \n\n---------------------------------------------------------------------\n"
103
+ "system-key-warning": "\n\n---------------------------------------------------------------------\nフローのクレデンシャルファイルはシステム生成キーで暗号化されています。\n\nシステム生成キーを何らかの理由で失った場合、クレデンシャルファイルを\n復元することはできません。その場合、ファイルを削除してクレデンシャルを\n再入力しなければなりません。\n\n設定ファイル内で 'credentialSecret' オプションを使って独自キーを設定\nします。変更を次にデプロイする際、Node-REDは選択したキーを用いてクレ\nデンシャルを再暗号化します。 \n\n---------------------------------------------------------------------\n",
104
+ "unencrypted": "暗号化されていないクレデンシャルを使用",
105
+ "encryptedNotFound": "暗号化されたクレデンシャルが存在しません"
104
106
  },
105
107
  "flows": {
106
108
  "safe-mode": "セーフモードでフローを停止しました。開始するためにはデプロイしてください",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node-red/runtime",
3
- "version": "3.0.0-beta.1",
3
+ "version": "3.0.0-beta.4",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./lib/index.js",
6
6
  "repository": {
@@ -16,8 +16,8 @@
16
16
  }
17
17
  ],
18
18
  "dependencies": {
19
- "@node-red/registry": "3.0.0-beta.1",
20
- "@node-red/util": "3.0.0-beta.1",
19
+ "@node-red/registry": "3.0.0-beta.4",
20
+ "@node-red/util": "3.0.0-beta.4",
21
21
  "async-mutex": "0.3.2",
22
22
  "clone": "2.1.2",
23
23
  "express": "4.18.1",