iobroker.script-restore 0.0.4 → 0.0.6
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 +17 -3
- package/admin/index_m.html +344 -6
- package/admin/tab_m.html +174 -33
- package/admin/words.js +398 -0
- package/build/main.js +448 -10
- package/build/main.js.map +3 -3
- package/io-package.json +92 -14
- package/package.json +7 -2
package/build/main.js
CHANGED
|
@@ -27,6 +27,12 @@ var path = __toESM(require("node:path"));
|
|
|
27
27
|
var os = __toESM(require("node:os"));
|
|
28
28
|
var import_node_child_process = require("node:child_process");
|
|
29
29
|
var import_node_util = require("node:util");
|
|
30
|
+
var ftp = __toESM(require("basic-ftp"));
|
|
31
|
+
var import_node_stream = require("node:stream");
|
|
32
|
+
var https = __toESM(require("node:https"));
|
|
33
|
+
var http = __toESM(require("node:http"));
|
|
34
|
+
var import_ssh2_sftp_client = __toESM(require("ssh2-sftp-client"));
|
|
35
|
+
const SMB2 = require("@marsaud/smb2");
|
|
30
36
|
const execAsync = (0, import_node_util.promisify)(import_node_child_process.exec);
|
|
31
37
|
class ScriptRestore extends utils.Adapter {
|
|
32
38
|
constructor(options = {}) {
|
|
@@ -39,8 +45,7 @@ class ScriptRestore extends utils.Adapter {
|
|
|
39
45
|
this.on("unload", this.onUnload.bind(this));
|
|
40
46
|
}
|
|
41
47
|
onReady() {
|
|
42
|
-
|
|
43
|
-
this.log.info(`Script Restore ready. Backup path: ${cfg.backupPath || "/opt/iobroker/backups"}`);
|
|
48
|
+
this.log.info(`Script Restore ready. Backup path: ${this.config.backupPath || "/opt/iobroker/backups"}`);
|
|
44
49
|
}
|
|
45
50
|
onUnload(callback) {
|
|
46
51
|
callback();
|
|
@@ -60,6 +65,63 @@ class ScriptRestore extends utils.Adapter {
|
|
|
60
65
|
case "parseUploadedFile":
|
|
61
66
|
await this.handleParseUploadedFile(obj);
|
|
62
67
|
break;
|
|
68
|
+
case "getSourceConfig":
|
|
69
|
+
this.sendTo(
|
|
70
|
+
obj.from,
|
|
71
|
+
obj.command,
|
|
72
|
+
{
|
|
73
|
+
localEnabled: this.config.localEnabled !== false,
|
|
74
|
+
ftpEnabled: !!this.config.ftpEnabled,
|
|
75
|
+
smbEnabled: !!this.config.smbEnabled,
|
|
76
|
+
httpEnabled: !!this.config.httpEnabled,
|
|
77
|
+
sftpEnabled: !!this.config.sftpEnabled,
|
|
78
|
+
webdavEnabled: !!this.config.webdavEnabled
|
|
79
|
+
},
|
|
80
|
+
obj.callback
|
|
81
|
+
);
|
|
82
|
+
break;
|
|
83
|
+
case "suggestBackupPath":
|
|
84
|
+
await this.handleSuggestBackupPath(obj);
|
|
85
|
+
break;
|
|
86
|
+
case "parseHttpUrl":
|
|
87
|
+
await this.handleParseHttpUrl(obj);
|
|
88
|
+
break;
|
|
89
|
+
case "testSftp":
|
|
90
|
+
await this.handleTestSftp(obj);
|
|
91
|
+
break;
|
|
92
|
+
case "listSftpFiles":
|
|
93
|
+
await this.handleListSftpFiles(obj);
|
|
94
|
+
break;
|
|
95
|
+
case "parseSftpFile":
|
|
96
|
+
await this.handleParseSftpFile(obj);
|
|
97
|
+
break;
|
|
98
|
+
case "testWebdav":
|
|
99
|
+
await this.handleTestWebdav(obj);
|
|
100
|
+
break;
|
|
101
|
+
case "listWebdavFiles":
|
|
102
|
+
await this.handleListWebdavFiles(obj);
|
|
103
|
+
break;
|
|
104
|
+
case "parseWebdavFile":
|
|
105
|
+
await this.handleParseWebdavFile(obj);
|
|
106
|
+
break;
|
|
107
|
+
case "testFtp":
|
|
108
|
+
await this.handleTestFtp(obj);
|
|
109
|
+
break;
|
|
110
|
+
case "testSmb":
|
|
111
|
+
await this.handleTestSmb(obj);
|
|
112
|
+
break;
|
|
113
|
+
case "listFtpFiles":
|
|
114
|
+
await this.handleListFtpFiles(obj);
|
|
115
|
+
break;
|
|
116
|
+
case "parseFtpFile":
|
|
117
|
+
await this.handleParseFtpFile(obj);
|
|
118
|
+
break;
|
|
119
|
+
case "listSmbFiles":
|
|
120
|
+
await this.handleListSmbFiles(obj);
|
|
121
|
+
break;
|
|
122
|
+
case "parseSmbFile":
|
|
123
|
+
await this.handleParseSmbFile(obj);
|
|
124
|
+
break;
|
|
63
125
|
default:
|
|
64
126
|
this.sendTo(obj.from, obj.command, { error: "Unknown command" }, obj.callback);
|
|
65
127
|
}
|
|
@@ -68,9 +130,13 @@ class ScriptRestore extends utils.Adapter {
|
|
|
68
130
|
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
69
131
|
}
|
|
70
132
|
}
|
|
133
|
+
// ─── Local ───────────────────────────────────────────────────────────────
|
|
71
134
|
async handleListLocalFiles(obj) {
|
|
72
|
-
|
|
73
|
-
|
|
135
|
+
if (this.config.localEnabled === false) {
|
|
136
|
+
this.sendTo(obj.from, obj.command, { error: "Local source not enabled" }, obj.callback);
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
const backupPath = this.config.backupPath || "/opt/iobroker/backups";
|
|
74
140
|
try {
|
|
75
141
|
const rawEntries = await fs.readdir(backupPath, { withFileTypes: true, encoding: "utf8" });
|
|
76
142
|
const entries = rawEntries;
|
|
@@ -89,8 +155,11 @@ class ScriptRestore extends utils.Adapter {
|
|
|
89
155
|
}
|
|
90
156
|
}
|
|
91
157
|
async handleParseLocalFile(obj) {
|
|
92
|
-
|
|
93
|
-
|
|
158
|
+
if (this.config.localEnabled === false) {
|
|
159
|
+
this.sendTo(obj.from, obj.command, { error: "Local source not enabled" }, obj.callback);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
const backupPath = this.config.backupPath || "/opt/iobroker/backups";
|
|
94
163
|
const msg = obj.message;
|
|
95
164
|
const filename = path.basename(msg.filename);
|
|
96
165
|
const filepath = path.join(backupPath, filename);
|
|
@@ -112,6 +181,193 @@ class ScriptRestore extends utils.Adapter {
|
|
|
112
181
|
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
113
182
|
}
|
|
114
183
|
}
|
|
184
|
+
// ─── Tests ───────────────────────────────────────────────────────────────
|
|
185
|
+
async handleTestFtp(obj) {
|
|
186
|
+
const msg = obj.message;
|
|
187
|
+
const client = new ftp.Client();
|
|
188
|
+
client.ftp.verbose = false;
|
|
189
|
+
try {
|
|
190
|
+
await client.access({
|
|
191
|
+
host: msg.host,
|
|
192
|
+
port: msg.port || 21,
|
|
193
|
+
user: msg.user || "anonymous",
|
|
194
|
+
password: msg.password || "",
|
|
195
|
+
secure: msg.secure || false
|
|
196
|
+
});
|
|
197
|
+
const list = await client.list(msg.path || "/");
|
|
198
|
+
const count = list.filter((i) => i.type === ftp.FileType.File).length;
|
|
199
|
+
this.sendTo(
|
|
200
|
+
obj.from,
|
|
201
|
+
obj.command,
|
|
202
|
+
{ success: true, message: `Verbunden! ${count} Datei(en) gefunden in: ${msg.path || "/"}` },
|
|
203
|
+
obj.callback
|
|
204
|
+
);
|
|
205
|
+
} catch (e) {
|
|
206
|
+
this.sendTo(obj.from, obj.command, { success: false, message: e.message }, obj.callback);
|
|
207
|
+
} finally {
|
|
208
|
+
client.close();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async handleTestSmb(obj) {
|
|
212
|
+
const msg = obj.message;
|
|
213
|
+
const smb = new SMB2({
|
|
214
|
+
share: `\\\\${msg.host}\\${msg.share}`,
|
|
215
|
+
username: msg.user || "",
|
|
216
|
+
password: msg.password || "",
|
|
217
|
+
domain: msg.domain || ""
|
|
218
|
+
});
|
|
219
|
+
try {
|
|
220
|
+
const files = await this.smbReaddir(smb, msg.path || "");
|
|
221
|
+
this.sendTo(
|
|
222
|
+
obj.from,
|
|
223
|
+
obj.command,
|
|
224
|
+
{
|
|
225
|
+
success: true,
|
|
226
|
+
message: `Verbunden! ${files.length} Eintr\xE4ge in: \\\\${msg.host}\\${msg.share}${msg.path ? `\\${msg.path}` : ""}`
|
|
227
|
+
},
|
|
228
|
+
obj.callback
|
|
229
|
+
);
|
|
230
|
+
} catch (e) {
|
|
231
|
+
this.sendTo(obj.from, obj.command, { success: false, message: e.message }, obj.callback);
|
|
232
|
+
} finally {
|
|
233
|
+
smb.disconnect();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// ─── FTP ─────────────────────────────────────────────────────────────────
|
|
237
|
+
createFtpClient() {
|
|
238
|
+
const client = new ftp.Client();
|
|
239
|
+
client.ftp.verbose = false;
|
|
240
|
+
return client;
|
|
241
|
+
}
|
|
242
|
+
async ftpConnect(client) {
|
|
243
|
+
await client.access({
|
|
244
|
+
host: this.config.ftpHost,
|
|
245
|
+
port: this.config.ftpPort || 21,
|
|
246
|
+
user: this.config.ftpUser || "anonymous",
|
|
247
|
+
password: this.config.ftpPassword || "",
|
|
248
|
+
secure: this.config.ftpSecure || false
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
async handleListFtpFiles(obj) {
|
|
252
|
+
if (!this.config.ftpEnabled) {
|
|
253
|
+
this.sendTo(obj.from, obj.command, { error: "FTP not enabled" }, obj.callback);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
const client = this.createFtpClient();
|
|
257
|
+
try {
|
|
258
|
+
await this.ftpConnect(client);
|
|
259
|
+
const remotePath = this.config.ftpPath || "/";
|
|
260
|
+
const list = await client.list(remotePath);
|
|
261
|
+
const files = list.filter((item) => {
|
|
262
|
+
const n = item.name;
|
|
263
|
+
return item.type === ftp.FileType.File && (n.startsWith("iobroker") || n.startsWith("javascript")) && (n.endsWith(".tar.gz") || n.endsWith(".tar") || n.endsWith(".json") || n.endsWith(".jsonl"));
|
|
264
|
+
}).map((item) => item.name).sort().reverse();
|
|
265
|
+
this.sendTo(obj.from, obj.command, { files, path: remotePath }, obj.callback);
|
|
266
|
+
} catch (e) {
|
|
267
|
+
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
268
|
+
} finally {
|
|
269
|
+
client.close();
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
async handleParseFtpFile(obj) {
|
|
273
|
+
if (!this.config.ftpEnabled) {
|
|
274
|
+
this.sendTo(obj.from, obj.command, { error: "FTP not enabled" }, obj.callback);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const msg = obj.message;
|
|
278
|
+
const filename = path.basename(msg.filename);
|
|
279
|
+
const remotePath = path.posix.join(this.config.ftpPath || "/", filename);
|
|
280
|
+
const client = this.createFtpClient();
|
|
281
|
+
try {
|
|
282
|
+
await this.ftpConnect(client);
|
|
283
|
+
const chunks = [];
|
|
284
|
+
const writable = new import_node_stream.Writable({
|
|
285
|
+
write(chunk, _enc, cb) {
|
|
286
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
287
|
+
cb();
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
await client.downloadTo(writable, remotePath);
|
|
291
|
+
const buf = Buffer.concat(chunks);
|
|
292
|
+
const scripts = await this.parseBuffer(buf, filename);
|
|
293
|
+
this.sendTo(obj.from, obj.command, { scripts }, obj.callback);
|
|
294
|
+
} catch (e) {
|
|
295
|
+
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
296
|
+
} finally {
|
|
297
|
+
client.close();
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
// ─── SMB ─────────────────────────────────────────────────────────────────
|
|
301
|
+
createSmbClient() {
|
|
302
|
+
return new SMB2({
|
|
303
|
+
share: `\\\\${this.config.smbHost}\\${this.config.smbShare}`,
|
|
304
|
+
username: this.config.smbUser || "",
|
|
305
|
+
password: this.config.smbPassword || "",
|
|
306
|
+
domain: this.config.smbDomain || ""
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
smbReaddir(smb, dirPath) {
|
|
310
|
+
return new Promise((resolve, reject) => {
|
|
311
|
+
smb.readdir(dirPath, (err, files) => {
|
|
312
|
+
if (err) {
|
|
313
|
+
reject(err);
|
|
314
|
+
} else {
|
|
315
|
+
resolve(files);
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
smbReadFile(smb, filePath) {
|
|
321
|
+
return new Promise((resolve, reject) => {
|
|
322
|
+
smb.readFile(filePath, (err, data) => {
|
|
323
|
+
if (err) {
|
|
324
|
+
reject(err);
|
|
325
|
+
} else {
|
|
326
|
+
resolve(data);
|
|
327
|
+
}
|
|
328
|
+
});
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
async handleListSmbFiles(obj) {
|
|
332
|
+
if (!this.config.smbEnabled) {
|
|
333
|
+
this.sendTo(obj.from, obj.command, { error: "SMB not enabled" }, obj.callback);
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
const smb = this.createSmbClient();
|
|
337
|
+
try {
|
|
338
|
+
const smbPath = this.config.smbPath || "";
|
|
339
|
+
const entries = await this.smbReaddir(smb, smbPath);
|
|
340
|
+
const files = entries.filter((n) => {
|
|
341
|
+
return (n.startsWith("iobroker") || n.startsWith("javascript")) && (n.endsWith(".tar.gz") || n.endsWith(".tar") || n.endsWith(".json") || n.endsWith(".jsonl"));
|
|
342
|
+
}).sort().reverse();
|
|
343
|
+
this.sendTo(obj.from, obj.command, { files, path: smbPath }, obj.callback);
|
|
344
|
+
} catch (e) {
|
|
345
|
+
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
346
|
+
} finally {
|
|
347
|
+
smb.disconnect();
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
async handleParseSmbFile(obj) {
|
|
351
|
+
if (!this.config.smbEnabled) {
|
|
352
|
+
this.sendTo(obj.from, obj.command, { error: "SMB not enabled" }, obj.callback);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const msg = obj.message;
|
|
356
|
+
const filename = path.basename(msg.filename);
|
|
357
|
+
const smbPath = this.config.smbPath || "";
|
|
358
|
+
const filePath = smbPath ? `${smbPath}\\${filename}` : filename;
|
|
359
|
+
const smb = this.createSmbClient();
|
|
360
|
+
try {
|
|
361
|
+
const buf = await this.smbReadFile(smb, filePath);
|
|
362
|
+
const scripts = await this.parseBuffer(buf, filename);
|
|
363
|
+
this.sendTo(obj.from, obj.command, { scripts }, obj.callback);
|
|
364
|
+
} catch (e) {
|
|
365
|
+
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
366
|
+
} finally {
|
|
367
|
+
smb.disconnect();
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
// ─── Parsing ─────────────────────────────────────────────────────────────
|
|
115
371
|
async parseBuffer(buf, filename) {
|
|
116
372
|
const name = filename.toLowerCase();
|
|
117
373
|
if (name.endsWith(".tar.gz") || name.endsWith(".tgz") || name.endsWith(".tar")) {
|
|
@@ -151,10 +407,7 @@ class ScriptRestore extends utils.Adapter {
|
|
|
151
407
|
const walk = async (d) => {
|
|
152
408
|
let entries;
|
|
153
409
|
try {
|
|
154
|
-
entries = await fs.readdir(d, {
|
|
155
|
-
withFileTypes: true,
|
|
156
|
-
encoding: "utf8"
|
|
157
|
-
});
|
|
410
|
+
entries = await fs.readdir(d, { withFileTypes: true, encoding: "utf8" });
|
|
158
411
|
} catch {
|
|
159
412
|
return null;
|
|
160
413
|
}
|
|
@@ -245,6 +498,191 @@ class ScriptRestore extends utils.Adapter {
|
|
|
245
498
|
source: typeof c.source === "string" ? c.source : ""
|
|
246
499
|
});
|
|
247
500
|
}
|
|
501
|
+
// ─── Suggest backup path ─────────────────────────────────────────────────
|
|
502
|
+
async handleSuggestBackupPath(obj) {
|
|
503
|
+
var _a;
|
|
504
|
+
const candidates = ["/opt/iobroker/backups", "/root/backups"];
|
|
505
|
+
try {
|
|
506
|
+
const backupObj = await this.getForeignObjectAsync("system.adapter.backitup.0");
|
|
507
|
+
if ((_a = backupObj == null ? void 0 : backupObj.native) == null ? void 0 : _a.defaultFolder) {
|
|
508
|
+
candidates.unshift(backupObj.native.defaultFolder);
|
|
509
|
+
}
|
|
510
|
+
} catch {
|
|
511
|
+
}
|
|
512
|
+
for (const p of candidates) {
|
|
513
|
+
try {
|
|
514
|
+
await fs.access(p);
|
|
515
|
+
this.sendTo(obj.from, obj.command, { path: p }, obj.callback);
|
|
516
|
+
return;
|
|
517
|
+
} catch {
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
this.sendTo(obj.from, obj.command, { path: null }, obj.callback);
|
|
521
|
+
}
|
|
522
|
+
// ─── HTTP ────────────────────────────────────────────────────────────────
|
|
523
|
+
downloadUrl(url) {
|
|
524
|
+
return new Promise((resolve, reject) => {
|
|
525
|
+
const mod = url.startsWith("https") ? https : http;
|
|
526
|
+
mod.get(url, (res) => {
|
|
527
|
+
if (res.statusCode !== 200) {
|
|
528
|
+
reject(new Error(`HTTP ${res.statusCode}`));
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
const chunks = [];
|
|
532
|
+
res.on("data", (c) => chunks.push(c));
|
|
533
|
+
res.on("end", () => resolve(Buffer.concat(chunks)));
|
|
534
|
+
res.on("error", reject);
|
|
535
|
+
}).on("error", reject);
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
async handleParseHttpUrl(obj) {
|
|
539
|
+
if (!this.config.httpEnabled) {
|
|
540
|
+
this.sendTo(obj.from, obj.command, { error: "HTTP not enabled" }, obj.callback);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const msg = obj.message;
|
|
544
|
+
const filename = msg.url.split("/").pop() || "backup";
|
|
545
|
+
try {
|
|
546
|
+
const buf = await this.downloadUrl(msg.url);
|
|
547
|
+
const scripts = await this.parseBuffer(buf, filename);
|
|
548
|
+
this.sendTo(obj.from, obj.command, { scripts }, obj.callback);
|
|
549
|
+
} catch (e) {
|
|
550
|
+
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
// ─── SFTP ────────────────────────────────────────────────────────────────
|
|
554
|
+
async handleTestSftp(obj) {
|
|
555
|
+
const msg = obj.message;
|
|
556
|
+
const sftp = new import_ssh2_sftp_client.default();
|
|
557
|
+
try {
|
|
558
|
+
await sftp.connect({ host: msg.host, port: msg.port || 22, username: msg.user, password: msg.password });
|
|
559
|
+
const list = await sftp.list(msg.path || "/");
|
|
560
|
+
const count = list.filter((i) => i.type === "-").length;
|
|
561
|
+
this.sendTo(
|
|
562
|
+
obj.from,
|
|
563
|
+
obj.command,
|
|
564
|
+
{ success: true, message: `Verbunden! ${count} Datei(en) in: ${msg.path || "/"}` },
|
|
565
|
+
obj.callback
|
|
566
|
+
);
|
|
567
|
+
} catch (e) {
|
|
568
|
+
this.sendTo(obj.from, obj.command, { success: false, message: e.message }, obj.callback);
|
|
569
|
+
} finally {
|
|
570
|
+
await sftp.end();
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
async handleListSftpFiles(obj) {
|
|
574
|
+
if (!this.config.sftpEnabled) {
|
|
575
|
+
this.sendTo(obj.from, obj.command, { error: "SFTP not enabled" }, obj.callback);
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
const sftp = new import_ssh2_sftp_client.default();
|
|
579
|
+
try {
|
|
580
|
+
await sftp.connect({
|
|
581
|
+
host: this.config.sftpHost,
|
|
582
|
+
port: this.config.sftpPort || 22,
|
|
583
|
+
username: this.config.sftpUser,
|
|
584
|
+
password: this.config.sftpPassword
|
|
585
|
+
});
|
|
586
|
+
const remotePath = this.config.sftpPath || "/";
|
|
587
|
+
const list = await sftp.list(remotePath);
|
|
588
|
+
const files = list.filter((i) => {
|
|
589
|
+
const n = i.name;
|
|
590
|
+
return i.type === "-" && (n.startsWith("iobroker") || n.startsWith("javascript")) && (n.endsWith(".tar.gz") || n.endsWith(".tar") || n.endsWith(".json") || n.endsWith(".jsonl"));
|
|
591
|
+
}).map((i) => i.name).sort().reverse();
|
|
592
|
+
this.sendTo(obj.from, obj.command, { files, path: remotePath }, obj.callback);
|
|
593
|
+
} catch (e) {
|
|
594
|
+
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
595
|
+
} finally {
|
|
596
|
+
await sftp.end();
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
async handleParseSftpFile(obj) {
|
|
600
|
+
if (!this.config.sftpEnabled) {
|
|
601
|
+
this.sendTo(obj.from, obj.command, { error: "SFTP not enabled" }, obj.callback);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
const msg = obj.message;
|
|
605
|
+
const filename = path.basename(msg.filename);
|
|
606
|
+
const remotePath = path.posix.join(this.config.sftpPath || "/", filename);
|
|
607
|
+
const sftp = new import_ssh2_sftp_client.default();
|
|
608
|
+
try {
|
|
609
|
+
await sftp.connect({
|
|
610
|
+
host: this.config.sftpHost,
|
|
611
|
+
port: this.config.sftpPort || 22,
|
|
612
|
+
username: this.config.sftpUser,
|
|
613
|
+
password: this.config.sftpPassword
|
|
614
|
+
});
|
|
615
|
+
const buf = await sftp.get(remotePath);
|
|
616
|
+
const scripts = await this.parseBuffer(buf, filename);
|
|
617
|
+
this.sendTo(obj.from, obj.command, { scripts }, obj.callback);
|
|
618
|
+
} catch (e) {
|
|
619
|
+
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
620
|
+
} finally {
|
|
621
|
+
await sftp.end();
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
// ─── WebDAV ──────────────────────────────────────────────────────────────
|
|
625
|
+
async handleTestWebdav(obj) {
|
|
626
|
+
const msg = obj.message;
|
|
627
|
+
try {
|
|
628
|
+
const { createClient: createWebdavClient } = await Promise.resolve().then(() => __toESM(require("webdav")));
|
|
629
|
+
const client = createWebdavClient(msg.url, { username: msg.user, password: msg.password });
|
|
630
|
+
const list = await client.getDirectoryContents(msg.path || "/");
|
|
631
|
+
const arr = Array.isArray(list) ? list : list.data;
|
|
632
|
+
this.sendTo(
|
|
633
|
+
obj.from,
|
|
634
|
+
obj.command,
|
|
635
|
+
{ success: true, message: `Verbunden! ${arr.length} Eintr\xE4ge in: ${msg.path || "/"}` },
|
|
636
|
+
obj.callback
|
|
637
|
+
);
|
|
638
|
+
} catch (e) {
|
|
639
|
+
this.sendTo(obj.from, obj.command, { success: false, message: e.message }, obj.callback);
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
async handleListWebdavFiles(obj) {
|
|
643
|
+
if (!this.config.webdavEnabled) {
|
|
644
|
+
this.sendTo(obj.from, obj.command, { error: "WebDAV not enabled" }, obj.callback);
|
|
645
|
+
return;
|
|
646
|
+
}
|
|
647
|
+
try {
|
|
648
|
+
const { createClient: createWebdavClient } = await Promise.resolve().then(() => __toESM(require("webdav")));
|
|
649
|
+
const client = createWebdavClient(this.config.webdavUrl, {
|
|
650
|
+
username: this.config.webdavUser,
|
|
651
|
+
password: this.config.webdavPassword
|
|
652
|
+
});
|
|
653
|
+
const remotePath = this.config.webdavPath || "/";
|
|
654
|
+
const list = await client.getDirectoryContents(remotePath);
|
|
655
|
+
const arr = Array.isArray(list) ? list : list.data;
|
|
656
|
+
const files = arr.filter((i) => {
|
|
657
|
+
const n = i.basename;
|
|
658
|
+
return i.type === "file" && (n.startsWith("iobroker") || n.startsWith("javascript")) && (n.endsWith(".tar.gz") || n.endsWith(".tar") || n.endsWith(".json") || n.endsWith(".jsonl"));
|
|
659
|
+
}).map((i) => i.basename).sort().reverse();
|
|
660
|
+
this.sendTo(obj.from, obj.command, { files, path: remotePath }, obj.callback);
|
|
661
|
+
} catch (e) {
|
|
662
|
+
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
async handleParseWebdavFile(obj) {
|
|
666
|
+
if (!this.config.webdavEnabled) {
|
|
667
|
+
this.sendTo(obj.from, obj.command, { error: "WebDAV not enabled" }, obj.callback);
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
const msg = obj.message;
|
|
671
|
+
const filename = path.basename(msg.filename);
|
|
672
|
+
try {
|
|
673
|
+
const { createClient: createWebdavClient } = await Promise.resolve().then(() => __toESM(require("webdav")));
|
|
674
|
+
const client = createWebdavClient(this.config.webdavUrl, {
|
|
675
|
+
username: this.config.webdavUser,
|
|
676
|
+
password: this.config.webdavPassword
|
|
677
|
+
});
|
|
678
|
+
const remotePath = (this.config.webdavPath ? `${this.config.webdavPath}/` : "/") + filename;
|
|
679
|
+
const buf = Buffer.from(await client.getFileContents(remotePath));
|
|
680
|
+
const scripts = await this.parseBuffer(buf, filename);
|
|
681
|
+
this.sendTo(obj.from, obj.command, { scripts }, obj.callback);
|
|
682
|
+
} catch (e) {
|
|
683
|
+
this.sendTo(obj.from, obj.command, { error: e.message }, obj.callback);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
248
686
|
}
|
|
249
687
|
if (require.main !== module) {
|
|
250
688
|
module.exports = (options) => new ScriptRestore(options);
|