@5minds/node-red-contrib-processcube-tools 1.1.0-feature-6eab97-mg0ov11s → 1.1.0-feature-f07d0c-mg6np5rk
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.
|
@@ -6,7 +6,17 @@
|
|
|
6
6
|
name: { value: '' },
|
|
7
7
|
provider: { value: 'fs' },
|
|
8
8
|
baseDir: { value: '' },
|
|
9
|
-
|
|
9
|
+
usernameType: { value: 'str' },
|
|
10
|
+
username: { value: '', required: true, validate: RED.validators.typedInput('usernameType') },
|
|
11
|
+
passwordType: { value: 'str' },
|
|
12
|
+
password: { value: '', required: true, validate: RED.validators.typedInput('passwordType') },
|
|
13
|
+
hostType: { value: 'str' },
|
|
14
|
+
host: { value: '', required: true, validate: RED.validators.typedInput('hostType') },
|
|
15
|
+
portType: { value: 'str' },
|
|
16
|
+
port: { value: '', required: true, validate: RED.validators.typedInput('portType') },
|
|
17
|
+
databaseType: { value: 'str' },
|
|
18
|
+
database: { value: '', required: true, validate: RED.validators.typedInput('databaseType') },
|
|
19
|
+
|
|
10
20
|
pgSchema: { value: 'public' },
|
|
11
21
|
pgTable: { value: 'files' },
|
|
12
22
|
outputAs: { value: 'stream' },
|
|
@@ -18,6 +28,34 @@
|
|
|
18
28
|
label: function () {
|
|
19
29
|
return this.name || 'file-storage';
|
|
20
30
|
},
|
|
31
|
+
oneditprepare: function () {
|
|
32
|
+
// postgres fields user, password, host, port, database
|
|
33
|
+
$('#node-input-username').typedInput({
|
|
34
|
+
default: 'str',
|
|
35
|
+
types: ['str', 'env'],
|
|
36
|
+
typeField: '#node-input-usernameType',
|
|
37
|
+
});
|
|
38
|
+
$('#node-input-password').typedInput({
|
|
39
|
+
default: 'str',
|
|
40
|
+
types: ['str', 'env'],
|
|
41
|
+
typeField: '#node-input-passwordType',
|
|
42
|
+
});
|
|
43
|
+
$('#node-input-host').typedInput({
|
|
44
|
+
default: 'str',
|
|
45
|
+
types: ['str', 'env'],
|
|
46
|
+
typeField: '#node-input-hostType',
|
|
47
|
+
});
|
|
48
|
+
$('#node-input-port').typedInput({
|
|
49
|
+
default: 'str',
|
|
50
|
+
types: ['str', 'env'],
|
|
51
|
+
typeField: '#node-input-portType',
|
|
52
|
+
});
|
|
53
|
+
$('#node-input-database').typedInput({
|
|
54
|
+
default: 'str',
|
|
55
|
+
types: ['str', 'env'],
|
|
56
|
+
typeField: '#node-input-databaseType',
|
|
57
|
+
});
|
|
58
|
+
},
|
|
21
59
|
});
|
|
22
60
|
</script>
|
|
23
61
|
|
|
@@ -50,15 +88,36 @@
|
|
|
50
88
|
<hr />
|
|
51
89
|
<div class="form-tips">PostgreSQL</div>
|
|
52
90
|
<div class="form-row">
|
|
53
|
-
<label for="node-input-
|
|
54
|
-
<input type="text" id="node-input-
|
|
91
|
+
<label for="node-input-username"><i class="fa fa-user"></i> Username</label>
|
|
92
|
+
<input type="text" id="node-input-username" placeholder="postgres" />
|
|
93
|
+
<input type="hidden" id="node-input-usernameType" />
|
|
94
|
+
</div>
|
|
95
|
+
<div class="form-row">
|
|
96
|
+
<label for="node-input-password"><i class="fa fa-key"></i> Password</label>
|
|
97
|
+
<input type="text" id="node-input-password" placeholder="postgres" />
|
|
98
|
+
<input type="hidden" id="node-input-passwordType" />
|
|
99
|
+
</div>
|
|
100
|
+
<div class="form-row">
|
|
101
|
+
<label for="node-input-host"><i class="fa fa-server"></i> Host</label>
|
|
102
|
+
<input type="text" id="node-input-host" placeholder="localhost" />
|
|
103
|
+
<input type="hidden" id="node-input-hostType" />
|
|
104
|
+
</div>
|
|
105
|
+
<div class="form-row">
|
|
106
|
+
<label for="node-input-port"><i class="fa fa-plug"></i> Port</label>
|
|
107
|
+
<input type="text" id="node-input-port" placeholder="5432" />
|
|
108
|
+
<input type="hidden" id="node-input-portType" />
|
|
109
|
+
</div>
|
|
110
|
+
<div class="form-row">
|
|
111
|
+
<label for="node-input-database"><i class="fa fa-database"></i> Database</label>
|
|
112
|
+
<input type="text" id="node-input-database" placeholder="postgres" />
|
|
113
|
+
<input type="hidden" id="node-input-databaseType" />
|
|
55
114
|
</div>
|
|
56
115
|
<div class="form-row">
|
|
57
116
|
<label for="node-input-pgSchema"><i class="fa fa-sitemap"></i> Schema</label>
|
|
58
117
|
<input type="text" id="node-input-pgSchema" placeholder="public" />
|
|
59
118
|
</div>
|
|
60
119
|
<div class="form-row">
|
|
61
|
-
<label for="node-input-pgTable"><i class="fa fa-table"></i>
|
|
120
|
+
<label for="node-input-pgTable"><i class="fa fa-table"></i> Table</label>
|
|
62
121
|
<input type="text" id="node-input-pgTable" placeholder="files" />
|
|
63
122
|
</div>
|
|
64
123
|
<hr />
|
|
@@ -73,25 +132,72 @@
|
|
|
73
132
|
</script>
|
|
74
133
|
|
|
75
134
|
<script type="text/html" data-help-name="file-storage">
|
|
135
|
+
<h2>File Storage Node</h2>
|
|
76
136
|
<p>
|
|
77
|
-
|
|
78
|
-
oder PostgreSQL (Large Objects + Metadaten-Tabelle).
|
|
137
|
+
A Node-RED node for storing, retrieving, and deleting files (including metadata) using either the local filesystem or PostgreSQL (Large Objects + metadata table) as a backend.
|
|
79
138
|
</p>
|
|
139
|
+
<h3>Features</h3>
|
|
140
|
+
<ul>
|
|
141
|
+
<li><b>Providers:</b>
|
|
142
|
+
<ul>
|
|
143
|
+
<li>Filesystem (stores file and metadata as JSON)</li>
|
|
144
|
+
<li>PostgreSQL (stores file as Large Object and metadata in a table)</li>
|
|
145
|
+
</ul>
|
|
146
|
+
</li>
|
|
147
|
+
<li><b>Actions:</b> Store, Retrieve, Delete files</li>
|
|
148
|
+
<li><b>Flexible output:</b> Stream, Buffer, or Path (filesystem only)</li>
|
|
149
|
+
</ul>
|
|
150
|
+
<h3>Node Properties</h3>
|
|
151
|
+
<ul>
|
|
152
|
+
<li><b>Name:</b> Optional node label.</li>
|
|
153
|
+
<li><b>Provider:</b> Select between Filesystem and PostgreSQL.</li>
|
|
154
|
+
<li><b>Output:</b> Choose the output type for retrieval: Stream, Buffer, or Path (Path only for filesystem).</li>
|
|
155
|
+
<li><b>Base Dir:</b> (Filesystem) Directory where files are stored.</li>
|
|
156
|
+
<li><b>Schema:</b> (PostgreSQL) Database schema (default: public).</li>
|
|
157
|
+
<li><b>Table:</b> (PostgreSQL) Table for metadata (default: files).</li>
|
|
158
|
+
<li><b>Default Action:</b> Default action if not specified in the message (store, get, or delete).</li>
|
|
159
|
+
</ul>
|
|
80
160
|
<h3>Input</h3>
|
|
81
161
|
<pre>
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
>
|
|
162
|
+
msg.action = "store" | "get" | "delete" // Optional, overrides defaultAction
|
|
163
|
+
msg.payload = Buffer | ReadableStream | String // For "store"
|
|
164
|
+
msg.file = {
|
|
165
|
+
id?: string, // For "get" or "delete"
|
|
166
|
+
filename?: string, // For "store"
|
|
167
|
+
contentType?: string,// For "store"
|
|
168
|
+
metadata?: object // For "store"
|
|
169
|
+
}
|
|
170
|
+
</pre>
|
|
92
171
|
<h3>Output</h3>
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
<code>msg.payload</code>
|
|
96
|
-
|
|
172
|
+
<ul>
|
|
173
|
+
<li><b>store:</b> <code>msg.payload</code> contains metadata including the generated <code>id</code>. <code>msg.file</code> contains the merged file info and result.</li>
|
|
174
|
+
<li><b>get:</b> <code>msg.payload</code> contains the file as a Stream, Buffer, or Path (depending on output setting). <code>msg.file</code> contains the file metadata.</li>
|
|
175
|
+
<li><b>delete:</b> <code>msg.payload</code> contains the result of the delete operation.</li>
|
|
176
|
+
</ul>
|
|
177
|
+
<h3>Example Usage</h3>
|
|
178
|
+
<pre>
|
|
179
|
+
// Store a file:
|
|
180
|
+
msg.action = "store";
|
|
181
|
+
msg.payload = Buffer.from("Hello World");
|
|
182
|
+
msg.file = {
|
|
183
|
+
filename: "hello.txt",
|
|
184
|
+
contentType: "text/plain",
|
|
185
|
+
metadata: { author: "Alice" }
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// Retrieve a file:
|
|
189
|
+
msg.action = "get";
|
|
190
|
+
msg.file = { id: "your-file-id" };
|
|
191
|
+
|
|
192
|
+
// Delete a file:
|
|
193
|
+
msg.action = "delete";
|
|
194
|
+
msg.file = { id: "your-file-id" };
|
|
195
|
+
</pre>
|
|
196
|
+
<h3>Notes</h3>
|
|
197
|
+
<ul>
|
|
198
|
+
<li>For PostgreSQL, ensure the connection string, schema, and table exist and the user has the necessary permissions.</li>
|
|
199
|
+
<li>For filesystem storage, ensure the base directory is writable by Node-RED.</li>
|
|
200
|
+
<li>The node is designed to handle large files efficiently using streams.</li>
|
|
201
|
+
</ul>
|
|
202
|
+
<p><b>Enjoy using the File Storage Node in your Node-RED flows!</b></p>
|
|
97
203
|
</script>
|
|
@@ -1,3 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* # File Storage Node
|
|
3
|
+
*
|
|
4
|
+
* A Node-RED node for storing, retrieving, and deleting files (including metadata) using either the local filesystem or PostgreSQL (Large Objects + metadata table) as a backend.
|
|
5
|
+
*
|
|
6
|
+
* ## Features
|
|
7
|
+
* - **Providers:**
|
|
8
|
+
* - Filesystem (stores file and metadata as JSON)
|
|
9
|
+
* - PostgreSQL (stores file as Large Object and metadata in a table)
|
|
10
|
+
* - **Actions:**
|
|
11
|
+
* - Store a file
|
|
12
|
+
* - Retrieve a file
|
|
13
|
+
* - Delete a file
|
|
14
|
+
* - **Flexible output:**
|
|
15
|
+
* - Stream, Buffer, or Path (filesystem only)
|
|
16
|
+
*
|
|
17
|
+
* ## Node Properties
|
|
18
|
+
* - **Name:** Optional node label.
|
|
19
|
+
* - **Provider:** Select between `Filesystem` and `PostgreSQL`.
|
|
20
|
+
* - **Output:** Choose the output type for retrieval: `Stream`, `Buffer`, or `Path` (Path only for filesystem).
|
|
21
|
+
* - **Base Dir:** (Filesystem) Directory where files are stored.
|
|
22
|
+
* - **Connection:** (PostgreSQL) Connection string for the database.
|
|
23
|
+
* - **Schema:** (PostgreSQL) Database schema (default: `public`).
|
|
24
|
+
* - **Table:** (PostgreSQL) Table for metadata (default: `files`).
|
|
25
|
+
* - **Default Action:** Default action if not specified in the message (`store`, `get`, or `delete`).
|
|
26
|
+
*
|
|
27
|
+
* ## Input
|
|
28
|
+
* The node expects the following properties in the incoming message:
|
|
29
|
+
* ```
|
|
30
|
+
* msg.action = "store" | "get" | "delete" // Optional, overrides defaultAction
|
|
31
|
+
* msg.payload = Buffer | ReadableStream | String // For "store"
|
|
32
|
+
* msg.file = {
|
|
33
|
+
* id?: string, // For "get" or "delete"
|
|
34
|
+
* filename?: string, // For "store"
|
|
35
|
+
* contentType?: string,// For "store"
|
|
36
|
+
* metadata?: object // For "store"
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* ## Output
|
|
41
|
+
* - For **store**:
|
|
42
|
+
* - `msg.payload` contains metadata including the generated `id`.
|
|
43
|
+
* - `msg.file` contains the merged file info and result.
|
|
44
|
+
* - For **get**:
|
|
45
|
+
* - `msg.payload` contains the file as a Stream, Buffer, or Path (depending on output setting).
|
|
46
|
+
* - `msg.file` contains the file metadata.
|
|
47
|
+
* - For **delete**:
|
|
48
|
+
* - `msg.payload` contains the result of the delete operation.
|
|
49
|
+
*
|
|
50
|
+
* ## Example Usage
|
|
51
|
+
* // Store a file:
|
|
52
|
+
* msg.action = "store";
|
|
53
|
+
* msg.payload = Buffer.from("Hello World");
|
|
54
|
+
* msg.file = {
|
|
55
|
+
* filename: "hello.txt",
|
|
56
|
+
* contentType: "text/plain",
|
|
57
|
+
* metadata: { author: "Alice" }
|
|
58
|
+
* };
|
|
59
|
+
*
|
|
60
|
+
* // Retrieve a file:
|
|
61
|
+
* msg.action = "get";
|
|
62
|
+
* msg.file = { id: "your-file-id" };
|
|
63
|
+
*
|
|
64
|
+
* // Delete a file:
|
|
65
|
+
* msg.action = "delete";
|
|
66
|
+
* msg.file = { id: "your-file-id" };
|
|
67
|
+
*
|
|
68
|
+
* ## Notes
|
|
69
|
+
* - For PostgreSQL, ensure the connection string, schema, and table exist and the user has the necessary permissions.
|
|
70
|
+
* - For filesystem storage, ensure the base directory is writable by Node-RED.
|
|
71
|
+
* - The node is designed to handle large files efficiently using streams.
|
|
72
|
+
*
|
|
73
|
+
* Enjoy using the File Storage Node in your Node-RED flows!
|
|
74
|
+
*/
|
|
1
75
|
module.exports = function (RED) {
|
|
2
76
|
const StorageCore = require('../storage/storage-core');
|
|
3
77
|
|
|
@@ -9,7 +83,11 @@ module.exports = function (RED) {
|
|
|
9
83
|
node.provider = config.provider || 'fs';
|
|
10
84
|
node.baseDir = config.baseDir;
|
|
11
85
|
node.pg = {
|
|
12
|
-
|
|
86
|
+
username: RED.util.evaluateNodeProperty(config.username, config.usernameType, node) || 'postgres',
|
|
87
|
+
password: RED.util.evaluateNodeProperty(config.password, config.passwordType, node) || 'postgres',
|
|
88
|
+
host: RED.util.evaluateNodeProperty(config.host, config.hostType, node) || 'localhost',
|
|
89
|
+
port: RED.util.evaluateNodeProperty(config.port, config.portType, node) || 5432,
|
|
90
|
+
database: RED.util.evaluateNodeProperty(config.database, config.databaseType, node) || 'postgres',
|
|
13
91
|
schema: config.pgSchema || 'public',
|
|
14
92
|
table: config.pgTable || 'files',
|
|
15
93
|
};
|
package/package.json
CHANGED
|
@@ -7,10 +7,11 @@ const pump = promisify(pipeline);
|
|
|
7
7
|
|
|
8
8
|
class PgProvider {
|
|
9
9
|
constructor(opts = {}) {
|
|
10
|
-
|
|
10
|
+
const conString = "postgres://" + opts.username + ":" + opts.password + "@" + opts.host + ":" + opts.port + "/" + opts.database;
|
|
11
|
+
this.connectionString = conString
|
|
11
12
|
this.schema = opts.schema || 'public';
|
|
12
13
|
this.table = opts.table || 'files';
|
|
13
|
-
|
|
14
|
+
this.pool = new Pool({ connectionString: this.connectionString });
|
|
14
15
|
this.pool = new Pool();
|
|
15
16
|
}
|
|
16
17
|
|
package/storage/storage-core.js
CHANGED
|
@@ -23,7 +23,11 @@ class StorageCore {
|
|
|
23
23
|
* @param {Object} [config.fs]
|
|
24
24
|
* @param {string} [config.fs.baseDir]
|
|
25
25
|
* @param {Object} [config.pg]
|
|
26
|
-
* @param {string} [config.pg.
|
|
26
|
+
* @param {string} [config.pg.username]
|
|
27
|
+
* @param {string} [config.pg.password]
|
|
28
|
+
* @param {string} [config.pg.host]
|
|
29
|
+
* @param {number} [config.pg.port]
|
|
30
|
+
* @param {string} [config.pg.database]
|
|
27
31
|
* @param {string} [config.pg.schema]
|
|
28
32
|
* @param {string} [config.pg.table]
|
|
29
33
|
*/
|