@gregoriusrippenstein/node-red-contrib-introspection 0.6.17 → 0.7.1
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/README.md +7 -0
- package/nodes/45-get-flows.js +4 -4
- package/nodes/50-send-flow.js +4 -4
- package/nodes/51-install-package.html +111 -0
- package/nodes/51-install-package.js +137 -0
- package/nodes/60-client-code.js +0 -6
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -99,6 +99,12 @@ Inspired by the [dsm](https://flows.nodered.org/node/node-red-contrib-dsm) packa
|
|
|
99
99
|
|
|
100
100
|
Send a flow to another Node-RED instance. This will replace **any existing** flows on the other server, use with care. Under the hood this uses the [Node-RED API](https://nodered.org/docs/api/admin/methods/post/flows/) to post a new flow to the server. This node also supports authentication if the other server happens to have some.
|
|
101
101
|
|
|
102
|
+
### InstallPackage
|
|
103
|
+
|
|
104
|
+
Node used to install packages on other Node-RED installations. Can be used to install existing modules using or .tgz files that can installed on the instance. To install an existing package, use `msg.payload = { module: '@fubar/example' }` with an optional `version`, this defaults to 'latest'.
|
|
105
|
+
|
|
106
|
+
To install a package on the fly, generate a .tgz as a Buffer and set the the payload to: `msg.payload = { data: Buffer[...]}` where buffer contains the .tgz contents.
|
|
107
|
+
|
|
102
108
|
### ClientCode
|
|
103
109
|
|
|
104
110
|
ClientCode is a node for executing client side, i.e., in the editor, Javascript code triggered by a server side event. Any code that can be executed in the browseer console can be executed in the ClientCode node. A ClientCode node can also send a message back to the server using `node.send(...)` which becomes the server side output of the node.
|
|
@@ -165,6 +171,7 @@ There are [example flows](/examples) contained in the package, examples can also
|
|
|
165
171
|
- [Orphans](https://flowhub.org/f/2401c255b056e0e1)
|
|
166
172
|
- [Sink and Seeker](https://flowhub.org/f/139a816449acd89f)
|
|
167
173
|
- [Obfuscation](https://flowhub.org/f/825ddf24d98eb011)
|
|
174
|
+
- [InstallPackage](https://flowhub.org/f/6dcbd2643ea80615)
|
|
168
175
|
|
|
169
176
|
## License
|
|
170
177
|
|
package/nodes/45-get-flows.js
CHANGED
|
@@ -42,7 +42,7 @@ module.exports = function(RED) {
|
|
|
42
42
|
|
|
43
43
|
}).catch( err => {
|
|
44
44
|
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
45
|
-
node.error(err)
|
|
45
|
+
node.error("error occurred", { ...msg, _err: err})
|
|
46
46
|
});
|
|
47
47
|
};
|
|
48
48
|
|
|
@@ -56,7 +56,7 @@ module.exports = function(RED) {
|
|
|
56
56
|
node, msg, (err, result) => {
|
|
57
57
|
if (err) {
|
|
58
58
|
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
59
|
-
node.error(err)
|
|
59
|
+
node.error("error occurred", {...msg, _err:err})
|
|
60
60
|
} else {
|
|
61
61
|
username = result;
|
|
62
62
|
|
|
@@ -64,7 +64,7 @@ module.exports = function(RED) {
|
|
|
64
64
|
node, msg, (err, result) => {
|
|
65
65
|
if (err) {
|
|
66
66
|
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
67
|
-
node.error(err)
|
|
67
|
+
node.error("error occurred", { ...msg, _err: err })
|
|
68
68
|
} else {
|
|
69
69
|
password = result;
|
|
70
70
|
|
|
@@ -94,7 +94,7 @@ module.exports = function(RED) {
|
|
|
94
94
|
|
|
95
95
|
}).catch((err) => {
|
|
96
96
|
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
97
|
-
node.error( err );
|
|
97
|
+
node.error( "error occurred", {...msg, _err: err });
|
|
98
98
|
});
|
|
99
99
|
});
|
|
100
100
|
}
|
package/nodes/50-send-flow.js
CHANGED
|
@@ -34,7 +34,7 @@ module.exports = function(RED) {
|
|
|
34
34
|
|
|
35
35
|
}).catch( err => {
|
|
36
36
|
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
37
|
-
node.error(err)
|
|
37
|
+
node.error("error occurred", { ...msg, _err: err})
|
|
38
38
|
});
|
|
39
39
|
};
|
|
40
40
|
|
|
@@ -51,7 +51,7 @@ module.exports = function(RED) {
|
|
|
51
51
|
node, msg, (err, result) => {
|
|
52
52
|
if (err) {
|
|
53
53
|
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
54
|
-
node.error(err)
|
|
54
|
+
node.error("error occurred", { ...msg, _err: err})
|
|
55
55
|
} else {
|
|
56
56
|
username = result;
|
|
57
57
|
|
|
@@ -59,7 +59,7 @@ module.exports = function(RED) {
|
|
|
59
59
|
node, msg, (err, result) => {
|
|
60
60
|
if (err) {
|
|
61
61
|
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
62
|
-
node.error(err)
|
|
62
|
+
node.error("error occurred", {...msg, _err: err})
|
|
63
63
|
} else {
|
|
64
64
|
password = result;
|
|
65
65
|
|
|
@@ -89,7 +89,7 @@ module.exports = function(RED) {
|
|
|
89
89
|
|
|
90
90
|
}).catch((err) => {
|
|
91
91
|
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
92
|
-
node.error( err );
|
|
92
|
+
node.error( "error occurred", { ...msg, _err: err });
|
|
93
93
|
});
|
|
94
94
|
});
|
|
95
95
|
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script type="text/javascript">
|
|
2
|
+
RED.nodes.registerType('InstallPackage',{
|
|
3
|
+
color: '#e5e4ef',
|
|
4
|
+
icon: "introspesubflow.svg",
|
|
5
|
+
category: 'introspection',
|
|
6
|
+
defaults: {
|
|
7
|
+
name: {
|
|
8
|
+
value:"",
|
|
9
|
+
},
|
|
10
|
+
hostUrl: {
|
|
11
|
+
value: ""
|
|
12
|
+
},
|
|
13
|
+
useAuthentication: {
|
|
14
|
+
value:false
|
|
15
|
+
},
|
|
16
|
+
apiUsername: {
|
|
17
|
+
value: "",
|
|
18
|
+
},
|
|
19
|
+
apiUsernameType: {
|
|
20
|
+
value: "env",
|
|
21
|
+
},
|
|
22
|
+
apiPassword: {
|
|
23
|
+
value: "",
|
|
24
|
+
},
|
|
25
|
+
apiPasswordType: {
|
|
26
|
+
value: "env",
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
inputs:1,
|
|
30
|
+
outputs:1,
|
|
31
|
+
|
|
32
|
+
label: function() {
|
|
33
|
+
return (this.name || this._def.paletteLabel);
|
|
34
|
+
},
|
|
35
|
+
|
|
36
|
+
labelStyle: function() {
|
|
37
|
+
return this.name?"node_label_italic":"";
|
|
38
|
+
},
|
|
39
|
+
oneditprepare: function() {
|
|
40
|
+
$("#node-input-apiUsername").typedInput({
|
|
41
|
+
types:["env", "msg", "flow","global", "cred"],
|
|
42
|
+
typeField: "#node-input-apiUsernameType"
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
$("#node-input-apiPassword").typedInput({
|
|
46
|
+
types:["env", "msg", "flow","global", "env", "cred"],
|
|
47
|
+
typeField: "#node-input-apiPasswordType"
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
if ( $('#node-input-useAuthentication').is(":checked") ) {
|
|
51
|
+
$('#useAuthentication-input-fields').show();
|
|
52
|
+
} else {
|
|
53
|
+
$('#useAuthentication-input-fields').hide()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
$('#node-input-useAuthentication').on( 'change', function() {
|
|
57
|
+
if ( $('#node-input-useAuthentication').is(":checked") ) {
|
|
58
|
+
$('#useAuthentication-input-fields').show();
|
|
59
|
+
} else {
|
|
60
|
+
$('#useAuthentication-input-fields').hide()
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<script type="text/html" data-template-name="InstallPackage">
|
|
68
|
+
<div class="form-row">
|
|
69
|
+
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
|
|
70
|
+
<input type="text" id="node-input-name" placeholder="Name">
|
|
71
|
+
</div>
|
|
72
|
+
|
|
73
|
+
<div class="form-row">
|
|
74
|
+
<label for="node-input-hostUrl"><i class="fa fa-tag"></i> Host</label>
|
|
75
|
+
<input type="text" id="node-input-hostUrl" placeholder="Host URL">
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="form-row">
|
|
79
|
+
<label for="node-input-useAuthentication">
|
|
80
|
+
<i class="fa "></i>
|
|
81
|
+
<span>Use Authentication?</span>
|
|
82
|
+
</label>
|
|
83
|
+
|
|
84
|
+
<input type="checkbox" id="node-input-useAuthentication"
|
|
85
|
+
style="display:inline-block; width:15px; vertical-align:baseline;">
|
|
86
|
+
</div>
|
|
87
|
+
|
|
88
|
+
<div id="useAuthentication-input-fields" class="hidden">
|
|
89
|
+
<div class="form-row">
|
|
90
|
+
<label for="node-input-apiUsername">
|
|
91
|
+
<i class="fa fa-tag"></i>
|
|
92
|
+
Username
|
|
93
|
+
</label>
|
|
94
|
+
<input type="text" id="node-input-apiUsername">
|
|
95
|
+
<input type="hidden" id="node-input-apiUsernameType">
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div class="form-row">
|
|
99
|
+
<label for="node-input-apiPassword">
|
|
100
|
+
<i class="fa fa-tag"></i>
|
|
101
|
+
Password
|
|
102
|
+
</label>
|
|
103
|
+
<input type="text" id="node-input-apiPassword">
|
|
104
|
+
<input type="hidden" id="node-input-apiPasswordType">
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<script type="text/html" data-help-name="InstallPackage">
|
|
110
|
+
<p>Send flow to another Node-RED instance.</p>
|
|
111
|
+
</script>
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
module.exports = function(RED) {
|
|
2
|
+
function InstallPackageFunctionality(config) {
|
|
3
|
+
RED.nodes.createNode(this,config);
|
|
4
|
+
|
|
5
|
+
var node = this;
|
|
6
|
+
var cfg = config;
|
|
7
|
+
|
|
8
|
+
node.on('close', function() {
|
|
9
|
+
node.status({});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
node.on("input", function(msg, send, done) {
|
|
13
|
+
|
|
14
|
+
if (!msg.payload || Object.prototype.toString.call(msg.payload) !== '[object Object]') {
|
|
15
|
+
return node.error("msg.payload missing or payload not hash", msg)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
var installPackage = (hdrs, got) => {
|
|
19
|
+
let body = undefined
|
|
20
|
+
let headers = {}
|
|
21
|
+
|
|
22
|
+
if ( msg.payload.module ) {
|
|
23
|
+
body = JSON.stringify({
|
|
24
|
+
module: msg.payload.module,
|
|
25
|
+
version: msg.payload.version || "latest"
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
headers = {
|
|
29
|
+
"Content-Type": "application/json"
|
|
30
|
+
}
|
|
31
|
+
} else if ( msg.payload.data && Buffer.isBuffer(msg.payload.data) ) {
|
|
32
|
+
|
|
33
|
+
let formData = require('form-data')
|
|
34
|
+
body = new formData();
|
|
35
|
+
body.append("tarball", msg.payload.data, "tarball.tgz");
|
|
36
|
+
headers = body.getHeaders()
|
|
37
|
+
body = body.getBuffer()
|
|
38
|
+
|
|
39
|
+
} else {
|
|
40
|
+
return node.error("msg.payload not well defined", msg)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
got.post( cfg.hostUrl + "/nodes", {
|
|
44
|
+
headers: {
|
|
45
|
+
...headers,
|
|
46
|
+
...hdrs
|
|
47
|
+
},
|
|
48
|
+
body: body
|
|
49
|
+
}).then( res => {
|
|
50
|
+
send({
|
|
51
|
+
...msg,
|
|
52
|
+
payload: JSON.parse(res.body)
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
node.status({fill:"green",shape:"dot",text:"Good"});
|
|
56
|
+
setTimeout( function() {
|
|
57
|
+
node.status({})
|
|
58
|
+
}, 450);
|
|
59
|
+
|
|
60
|
+
}).catch( err => {
|
|
61
|
+
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
62
|
+
node.error("error occurred", { ...msg, _err: err })
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Authentication
|
|
68
|
+
**/
|
|
69
|
+
if ( cfg.useAuthentication ) {
|
|
70
|
+
var username = undefined;
|
|
71
|
+
var password = undefined;
|
|
72
|
+
|
|
73
|
+
node.status({fill:"blue",shape:"dot",text:"Requesting token"});
|
|
74
|
+
|
|
75
|
+
RED.util.evaluateNodeProperty(cfg.apiUsername, cfg.apiUsernameType,
|
|
76
|
+
node, msg, (err, result) => {
|
|
77
|
+
if (err) {
|
|
78
|
+
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
79
|
+
node.error("error occurred", { ...msg, _err: err})
|
|
80
|
+
} else {
|
|
81
|
+
username = result;
|
|
82
|
+
|
|
83
|
+
RED.util.evaluateNodeProperty(cfg.apiPassword, cfg.apiPasswordType,
|
|
84
|
+
node, msg, (err, result) => {
|
|
85
|
+
if (err) {
|
|
86
|
+
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
87
|
+
node.error("error occurred", { ...msg, _err: err} )
|
|
88
|
+
} else {
|
|
89
|
+
password = result;
|
|
90
|
+
|
|
91
|
+
var data = {
|
|
92
|
+
"client_id": "node-red-admin",
|
|
93
|
+
"grant_type": "password",
|
|
94
|
+
"scope": "*",
|
|
95
|
+
"username": username,
|
|
96
|
+
"password": password
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
import('got').then( (module) => {
|
|
100
|
+
module.got.post( cfg.hostUrl + "/auth/token", {
|
|
101
|
+
json: data
|
|
102
|
+
}).then( res => {
|
|
103
|
+
node.status({
|
|
104
|
+
fill:"blue",
|
|
105
|
+
shape:"dot",
|
|
106
|
+
text:"Sending flow"
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
var access_token = JSON.parse(res.body).access_token;
|
|
110
|
+
|
|
111
|
+
installPackage({
|
|
112
|
+
"Authorization": "Bearer " + access_token
|
|
113
|
+
}, module.got);
|
|
114
|
+
|
|
115
|
+
}).catch((err) => {
|
|
116
|
+
node.status({fill:"red",shape:"dot",text:"Failed"});
|
|
117
|
+
node.error( "error occured", { ...msg, _err: err } );
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
})
|
|
122
|
+
}
|
|
123
|
+
})
|
|
124
|
+
} else {
|
|
125
|
+
/*
|
|
126
|
+
* Authentication free zone...
|
|
127
|
+
*/
|
|
128
|
+
node.status({fill:"blue",shape:"dot",text:"Sending flow"});
|
|
129
|
+
import('got').then( (module) => {
|
|
130
|
+
installPackage({}, module.got);
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
RED.nodes.registerType("InstallPackage", InstallPackageFunctionality);
|
|
137
|
+
}
|
package/nodes/60-client-code.js
CHANGED
|
@@ -42,8 +42,6 @@ module.exports = function(RED) {
|
|
|
42
42
|
}
|
|
43
43
|
} catch(err) {
|
|
44
44
|
res.sendStatus(500);
|
|
45
|
-
node.error("ClientCode: Submission failed: " +
|
|
46
|
-
err.toString())
|
|
47
45
|
}
|
|
48
46
|
} else {
|
|
49
47
|
res.sendStatus(404);
|
|
@@ -64,8 +62,6 @@ module.exports = function(RED) {
|
|
|
64
62
|
}
|
|
65
63
|
} catch (err) {
|
|
66
64
|
res.sendStatus(500);
|
|
67
|
-
node.error("ClientCode: Submission failed: " +
|
|
68
|
-
err.toString())
|
|
69
65
|
}
|
|
70
66
|
} else {
|
|
71
67
|
res.sendStatus(404);
|
|
@@ -135,8 +131,6 @@ module.exports = function(RED) {
|
|
|
135
131
|
}
|
|
136
132
|
} catch (err) {
|
|
137
133
|
res.sendStatus(500);
|
|
138
|
-
node.error("ClientCode: Submission failed: " +
|
|
139
|
-
err.toString())
|
|
140
134
|
}
|
|
141
135
|
});
|
|
142
136
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gregoriusrippenstein/node-red-contrib-introspection",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
4
4
|
"dependencies": {
|
|
5
5
|
"got": "^13",
|
|
6
6
|
"uglify-js": "^3.17.4",
|
|
@@ -28,11 +28,12 @@
|
|
|
28
28
|
"screenshot": "plugins/sidebar.html"
|
|
29
29
|
},
|
|
30
30
|
"nodes": {
|
|
31
|
-
"seeker":
|
|
32
|
-
"sink":
|
|
33
|
-
"getflows":
|
|
34
|
-
"sendflow":
|
|
35
|
-
"
|
|
31
|
+
"seeker": "nodes/05-seeker.js",
|
|
32
|
+
"sink": "nodes/10-sink.js",
|
|
33
|
+
"getflows": "nodes/45-get-flows.js",
|
|
34
|
+
"sendflow": "nodes/50-send-flow.js",
|
|
35
|
+
"installpackage": "nodes/51-install-package.js",
|
|
36
|
+
"clientcode": "nodes/60-client-code.js"
|
|
36
37
|
}
|
|
37
38
|
},
|
|
38
39
|
|