@bprotsyk/aso-core 2.0.33 → 2.0.35
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/lib/utils/server-util.d.ts +4 -1
- package/lib/utils/server-util.js +66 -20
- package/package.json +4 -2
- package/src/utils/server-util.ts +89 -33
|
@@ -29,7 +29,10 @@ export declare class ServerUtil {
|
|
|
29
29
|
setupCertbot(): Promise<boolean>;
|
|
30
30
|
setupSSL(email: string, host: string): Promise<void>;
|
|
31
31
|
refresh(): Promise<boolean>;
|
|
32
|
-
uploadDirectoryToSftp(localDir: string, remoteDir: string, sftpConfig:
|
|
32
|
+
uploadDirectoryToSftp(localDir: string, remoteDir: string, sftpConfig: any): Promise<void>;
|
|
33
|
+
ensureDirectoryExistence(dirPath: string): void;
|
|
33
34
|
generateNginxConfig(domain: string, rootPath: string): Promise<string>;
|
|
35
|
+
extractUploadedZip(name: string, file: any): Promise<void>;
|
|
36
|
+
ensureDirectoryExistsViaSSH(sshConfig: ISFTP, remoteDir: string): Promise<void>;
|
|
34
37
|
}
|
|
35
38
|
export {};
|
package/lib/utils/server-util.js
CHANGED
|
@@ -4,11 +4,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.ServerUtil = exports.PORT = exports.HOST = exports.PASSWORD = exports.IP = void 0;
|
|
7
|
+
const node_ssh_1 = require("node-ssh");
|
|
7
8
|
const child_process_1 = __importDefault(require("child_process"));
|
|
8
9
|
const ssh2_sftp_client_1 = __importDefault(require("ssh2-sftp-client"));
|
|
9
10
|
const fs_1 = __importDefault(require("fs"));
|
|
10
11
|
const mustache_1 = __importDefault(require("mustache"));
|
|
11
12
|
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const unzipper_1 = __importDefault(require("unzipper"));
|
|
12
14
|
const { promisify } = require("util");
|
|
13
15
|
const execPromise = promisify(child_process_1.default.exec);
|
|
14
16
|
exports.IP = "185.123.53.227";
|
|
@@ -169,53 +171,97 @@ class ServerUtil {
|
|
|
169
171
|
const sftp = new ssh2_sftp_client_1.default();
|
|
170
172
|
try {
|
|
171
173
|
await sftp.connect(sftpConfig);
|
|
172
|
-
await sftp.stat(remoteDir).catch(async (err) => {
|
|
173
|
-
if (err.code === 2) {
|
|
174
|
-
// Код 2 означає, що директорія не існує
|
|
175
|
-
await sftp.mkdir(remoteDir, true);
|
|
176
|
-
console.log(`Папка створена: ${remoteDir}`);
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
console.error(`Помилка під час перевірки або створення папки: ${remoteDir}`, err);
|
|
180
|
-
throw err;
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
174
|
const items = fs_1.default.readdirSync(localDir, { withFileTypes: true });
|
|
184
175
|
for (const item of items) {
|
|
185
176
|
const localPath = path_1.default.join(localDir, item.name);
|
|
186
177
|
const remotePath = `${remoteDir}/${item.name}`;
|
|
187
178
|
if (item.isDirectory()) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
console.
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
console.error(`Помилка під час перевірки або створення папки: ${remotePath}`, err);
|
|
179
|
+
// Створення підкаталогу на віддаленому сервері
|
|
180
|
+
await sftp.mkdir(remotePath, true).catch(async (err) => {
|
|
181
|
+
if (err.code !== 4) { // Ігноруємо помилку "Directory already exists"
|
|
182
|
+
console.error(`Помилка під час створення папки: ${remotePath}`, err);
|
|
195
183
|
throw err;
|
|
196
184
|
}
|
|
197
185
|
});
|
|
186
|
+
// Рекурсивне копіювання вмісту директорії
|
|
198
187
|
await this.uploadDirectoryToSftp(localPath, remotePath, sftpConfig);
|
|
199
188
|
}
|
|
200
189
|
else {
|
|
190
|
+
// Завантаження файлу на віддалений сервер
|
|
201
191
|
await sftp.put(localPath, remotePath);
|
|
202
192
|
console.log(`Передано файл: ${localPath} -> ${remotePath}`);
|
|
203
193
|
}
|
|
204
194
|
}
|
|
205
|
-
console.log(
|
|
195
|
+
console.log('Усі файли та папки успішно передані.');
|
|
206
196
|
}
|
|
207
197
|
catch (err) {
|
|
208
|
-
console.error(
|
|
198
|
+
console.error('Помилка під час передавання файлів через SFTP:', err);
|
|
209
199
|
}
|
|
210
200
|
finally {
|
|
211
201
|
await sftp.end();
|
|
212
202
|
}
|
|
213
203
|
}
|
|
204
|
+
ensureDirectoryExistence(dirPath) {
|
|
205
|
+
if (!fs_1.default.existsSync(dirPath)) {
|
|
206
|
+
fs_1.default.mkdirSync(dirPath, { recursive: true });
|
|
207
|
+
}
|
|
208
|
+
}
|
|
214
209
|
async generateNginxConfig(domain, rootPath) {
|
|
215
210
|
const templatePath = path_1.default.join(__dirname, "..", "templates", "nginx-template.conf");
|
|
216
211
|
const template = fs_1.default.readFileSync(templatePath, "utf8");
|
|
217
212
|
const config = mustache_1.default.render(template, { domain, rootPath });
|
|
218
213
|
return config;
|
|
219
214
|
}
|
|
215
|
+
async extractUploadedZip(name, file) {
|
|
216
|
+
const zipFilePath = file.path;
|
|
217
|
+
const outputDir = path_1.default.join(__dirname, '..', 'uploads', name);
|
|
218
|
+
console.log('Looking for ZIP file at:', zipFilePath);
|
|
219
|
+
console.log('Extracting to:', outputDir);
|
|
220
|
+
this.ensureDirectoryExistence(outputDir);
|
|
221
|
+
if (!fs_1.default.existsSync(zipFilePath)) {
|
|
222
|
+
console.error('Error: File not found:', zipFilePath);
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
await new Promise((resolve, reject) => {
|
|
227
|
+
fs_1.default.createReadStream(zipFilePath)
|
|
228
|
+
.pipe(unzipper_1.default.Parse())
|
|
229
|
+
.on('entry', (entry) => {
|
|
230
|
+
// Видаляємо перший сегмент шляху, щоб уникнути кореневої директорії
|
|
231
|
+
const entryPath = path_1.default.join(outputDir, ...entry.path.split('/').slice(1));
|
|
232
|
+
if (entry.type === 'Directory') {
|
|
233
|
+
this.ensureDirectoryExistence(entryPath);
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
this.ensureDirectoryExistence(path_1.default.dirname(entryPath));
|
|
237
|
+
entry.pipe(fs_1.default.createWriteStream(entryPath));
|
|
238
|
+
}
|
|
239
|
+
})
|
|
240
|
+
.on('close', resolve)
|
|
241
|
+
.on('error', reject);
|
|
242
|
+
});
|
|
243
|
+
console.log('File successfully extracted.');
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
console.error('Error extracting file:', err);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
async ensureDirectoryExistsViaSSH(sshConfig, remoteDir) {
|
|
250
|
+
const ssh = new node_ssh_1.NodeSSH();
|
|
251
|
+
try {
|
|
252
|
+
await ssh.connect(sshConfig);
|
|
253
|
+
// Перевірка, чи існує директорія, і створення її, якщо вона не існує
|
|
254
|
+
const command = `if [ ! -d "${remoteDir}" ]; then mkdir -p "${remoteDir}"; fi`;
|
|
255
|
+
await ssh.execCommand(command);
|
|
256
|
+
console.log(`Перевірено або створено папку: ${remoteDir}`);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
console.error('Помилка під час перевірки або створення папки через SSH:', err);
|
|
260
|
+
throw err;
|
|
261
|
+
}
|
|
262
|
+
finally {
|
|
263
|
+
ssh.dispose();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
220
266
|
}
|
|
221
267
|
exports.ServerUtil = ServerUtil;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bprotsyk/aso-core",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.35",
|
|
4
4
|
"main": "lib/index.js",
|
|
5
5
|
"types": "lib/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -37,7 +37,8 @@
|
|
|
37
37
|
"replace-in-file": "^7.0.1",
|
|
38
38
|
"sleep-promise": "^9.1.0",
|
|
39
39
|
"ssh2-sftp-client": "^11.0.0",
|
|
40
|
-
"styled-components": "^5.3.9"
|
|
40
|
+
"styled-components": "^5.3.9",
|
|
41
|
+
"unzipper": "^0.12.3"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|
|
43
44
|
"@types/mustache": "^4.2.5",
|
|
@@ -45,6 +46,7 @@
|
|
|
45
46
|
"@types/react": "^18.2.14",
|
|
46
47
|
"@types/react-dom": "^18.3.0",
|
|
47
48
|
"@types/ssh2-sftp-client": "^9.0.4",
|
|
49
|
+
"@types/unzipper": "^0.10.10",
|
|
48
50
|
"copyfiles": "^2.4.1",
|
|
49
51
|
"typedoc": "^0.23.28",
|
|
50
52
|
"typescript": "^4.9.5"
|
package/src/utils/server-util.ts
CHANGED
|
@@ -4,6 +4,8 @@ import Client from "ssh2-sftp-client";
|
|
|
4
4
|
import fs from "fs";
|
|
5
5
|
import mustache from "mustache";
|
|
6
6
|
import path from "path";
|
|
7
|
+
import unzipper from 'unzipper';
|
|
8
|
+
|
|
7
9
|
const { promisify } = require("util");
|
|
8
10
|
const execPromise = promisify(ChildProcess.exec);
|
|
9
11
|
|
|
@@ -205,65 +207,53 @@ export class ServerUtil {
|
|
|
205
207
|
return true;
|
|
206
208
|
}
|
|
207
209
|
|
|
208
|
-
async
|
|
210
|
+
async uploadDirectoryToSftp(
|
|
209
211
|
localDir: string,
|
|
210
212
|
remoteDir: string,
|
|
211
|
-
sftpConfig:
|
|
213
|
+
sftpConfig: any
|
|
212
214
|
) {
|
|
213
215
|
const sftp = new Client();
|
|
214
|
-
|
|
216
|
+
|
|
215
217
|
try {
|
|
216
218
|
await sftp.connect(sftpConfig);
|
|
217
|
-
|
|
218
|
-
await sftp.stat(remoteDir).catch(async (err) => {
|
|
219
|
-
if (err.code === 2) {
|
|
220
|
-
// Код 2 означає, що директорія не існує
|
|
221
|
-
await sftp.mkdir(remoteDir, true);
|
|
222
|
-
console.log(`Папка створена: ${remoteDir}`);
|
|
223
|
-
} else {
|
|
224
|
-
console.error(
|
|
225
|
-
`Помилка під час перевірки або створення папки: ${remoteDir}`,
|
|
226
|
-
err
|
|
227
|
-
);
|
|
228
|
-
throw err;
|
|
229
|
-
}
|
|
230
|
-
});
|
|
231
|
-
|
|
232
219
|
const items = fs.readdirSync(localDir, { withFileTypes: true });
|
|
233
|
-
|
|
220
|
+
|
|
234
221
|
for (const item of items) {
|
|
235
222
|
const localPath = path.join(localDir, item.name);
|
|
236
223
|
const remotePath = `${remoteDir}/${item.name}`;
|
|
237
|
-
|
|
224
|
+
|
|
238
225
|
if (item.isDirectory()) {
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
console.
|
|
243
|
-
} else {
|
|
244
|
-
console.error(
|
|
245
|
-
`Помилка під час перевірки або створення папки: ${remotePath}`,
|
|
246
|
-
err
|
|
247
|
-
);
|
|
226
|
+
// Створення підкаталогу на віддаленому сервері
|
|
227
|
+
await sftp.mkdir(remotePath, true).catch(async (err) => {
|
|
228
|
+
if (err.code !== 4) { // Ігноруємо помилку "Directory already exists"
|
|
229
|
+
console.error(`Помилка під час створення папки: ${remotePath}`, err);
|
|
248
230
|
throw err;
|
|
249
231
|
}
|
|
250
232
|
});
|
|
251
|
-
|
|
233
|
+
|
|
234
|
+
// Рекурсивне копіювання вмісту директорії
|
|
252
235
|
await this.uploadDirectoryToSftp(localPath, remotePath, sftpConfig);
|
|
253
236
|
} else {
|
|
237
|
+
// Завантаження файлу на віддалений сервер
|
|
254
238
|
await sftp.put(localPath, remotePath);
|
|
255
239
|
console.log(`Передано файл: ${localPath} -> ${remotePath}`);
|
|
256
240
|
}
|
|
257
241
|
}
|
|
258
|
-
|
|
259
|
-
console.log(
|
|
242
|
+
|
|
243
|
+
console.log('Усі файли та папки успішно передані.');
|
|
260
244
|
} catch (err) {
|
|
261
|
-
console.error(
|
|
245
|
+
console.error('Помилка під час передавання файлів через SFTP:', err);
|
|
262
246
|
} finally {
|
|
263
247
|
await sftp.end();
|
|
264
248
|
}
|
|
265
249
|
}
|
|
266
250
|
|
|
251
|
+
ensureDirectoryExistence(dirPath:string) {
|
|
252
|
+
if (!fs.existsSync(dirPath)) {
|
|
253
|
+
fs.mkdirSync(dirPath, { recursive: true });
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
267
257
|
async generateNginxConfig(domain: string, rootPath: string): Promise<string> {
|
|
268
258
|
const templatePath = path.join(
|
|
269
259
|
__dirname,
|
|
@@ -275,4 +265,70 @@ export class ServerUtil {
|
|
|
275
265
|
const config = mustache.render(template, { domain, rootPath });
|
|
276
266
|
return config;
|
|
277
267
|
}
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
async extractUploadedZip(name:string, file:any) {
|
|
271
|
+
const zipFilePath = file.path;
|
|
272
|
+
const outputDir = path.join(__dirname, '..', 'uploads', name);
|
|
273
|
+
|
|
274
|
+
console.log('Looking for ZIP file at:', zipFilePath);
|
|
275
|
+
console.log('Extracting to:', outputDir);
|
|
276
|
+
|
|
277
|
+
this.ensureDirectoryExistence(outputDir);
|
|
278
|
+
|
|
279
|
+
if (!fs.existsSync(zipFilePath)) {
|
|
280
|
+
console.error('Error: File not found:', zipFilePath);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
try {
|
|
285
|
+
await new Promise((resolve, reject) => {
|
|
286
|
+
fs.createReadStream(zipFilePath)
|
|
287
|
+
.pipe(unzipper.Parse())
|
|
288
|
+
.on('entry', (entry) => {
|
|
289
|
+
// Видаляємо перший сегмент шляху, щоб уникнути кореневої директорії
|
|
290
|
+
const entryPath = path.join(
|
|
291
|
+
outputDir,
|
|
292
|
+
...entry.path.split('/').slice(1)
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
if (entry.type === 'Directory') {
|
|
296
|
+
this.ensureDirectoryExistence(entryPath);
|
|
297
|
+
} else {
|
|
298
|
+
this.ensureDirectoryExistence(path.dirname(entryPath));
|
|
299
|
+
entry.pipe(fs.createWriteStream(entryPath));
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
.on('close', resolve)
|
|
303
|
+
.on('error', reject);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
console.log('File successfully extracted.');
|
|
307
|
+
} catch (err) {
|
|
308
|
+
console.error('Error extracting file:', err);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async ensureDirectoryExistsViaSSH(sshConfig:ISFTP, remoteDir:string) {
|
|
313
|
+
const ssh = new NodeSSH();
|
|
314
|
+
|
|
315
|
+
try {
|
|
316
|
+
await ssh.connect(sshConfig);
|
|
317
|
+
|
|
318
|
+
// Перевірка, чи існує директорія, і створення її, якщо вона не існує
|
|
319
|
+
const command = `if [ ! -d "${remoteDir}" ]; then mkdir -p "${remoteDir}"; fi`;
|
|
320
|
+
await ssh.execCommand(command);
|
|
321
|
+
console.log(`Перевірено або створено папку: ${remoteDir}`);
|
|
322
|
+
} catch (err) {
|
|
323
|
+
console.error(
|
|
324
|
+
'Помилка під час перевірки або створення папки через SSH:',
|
|
325
|
+
err
|
|
326
|
+
);
|
|
327
|
+
throw err;
|
|
328
|
+
} finally {
|
|
329
|
+
ssh.dispose();
|
|
330
|
+
}
|
|
331
|
+
}
|
|
278
332
|
}
|
|
333
|
+
|
|
334
|
+
|