Skip to content

Commit

Permalink
Merge pull request #159 from invince/develop
Browse files Browse the repository at this point in the history
Release 1.1.0
  • Loading branch information
invince authored Jan 21, 2025
2 parents 865f0a8 + b13609b commit 32f57f3
Show file tree
Hide file tree
Showing 71 changed files with 511 additions and 264 deletions.
13 changes: 11 additions & 2 deletions TestPlan.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
- rdp
- scp
- ftp
- samba
- icon ok
- clone works
- custom
Expand All @@ -81,6 +82,7 @@
- rdp
- scp
- ftp
- samba
- with same group info cloned
- with same tags info cloned
- edit
Expand Down Expand Up @@ -183,14 +185,18 @@
- [x] drag and drop file to upload
- [x] copy paste file
- [x] cut paste file
- [x] copy paste folder
- [x] cut paste folder
- [x] create folder
- [] create file
- [x] rename folder
- [x] rename file
- [x] delete file
- [x] delete folder
- [x] delete folder containing files
- [x] double click open the file
- if you update the file, the file will be uploaded to scp
- [x] copy current path

## SMB
- all ok, use a third party lib
Expand All @@ -203,14 +209,17 @@
- [x] detail view
- [x] upload
- [x] drag and drop file to upload
- [] copy paste file
- [] cut paste file
- [x] copy paste file
- [x] cut paste file
- [x] copy paste folder
- [x] cut paste folder
- [x] create folder
- [] create file
- [x] rename folder
- [x] rename file
- [x] delete file
- [x] delete folder
- [x] delete folder containing files
- [x] double click open the file
- if you update the file, the file will be uploaded to scp

Expand Down
11 changes: 9 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "yet-another-electron-term",
"version": "1.0.0",
"version": "1.0.1",
"main": "src-electron/electronMain.js",
"scripts": {
"ng": "ng",
Expand Down Expand Up @@ -79,6 +79,7 @@
"multer": "^1.4.5-lts.1",
"ng-terminal": "^6.2.0",
"ngx-spinner": "^17.0.0",
"node-fstab": "^1.0.16",
"node-powershell": "^5.0.1",
"node-pty": "^1.0.0",
"patch-package": "^8.0.0",
Expand Down
120 changes: 120 additions & 0 deletions patches/v9u-smb2+1.0.6.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
diff --git a/node_modules/v9u-smb2/lib/api/rmdir.js b/node_modules/v9u-smb2/lib/api/rmdir.js
index 0dd2032..e3ccac7 100644
--- a/node_modules/v9u-smb2/lib/api/rmdir.js
+++ b/node_modules/v9u-smb2/lib/api/rmdir.js
@@ -1,44 +1,82 @@
var SMB2Forge = require('../tools/smb2-forge');
var SMB2Request = SMB2Forge.request;
-var BigInt = require('../tools/bigint');
+var bigint = require('../tools/bigint');

/*
- * rmdir
- * =====
- *
- * remove directory:
- *
- * - open the folder
- *
- * - remove the folder
- *
- * - close the folder
+ * [INVINCE FIX]: add recursive
+ * Recursive rmdir
+ * ===============
*
+ * Removes a directory and its contents recursively.
*/
module.exports = function rmdir(path, cb) {
var connection = this;

- // SMB2 open file
- SMB2Request('open_folder', { path: path }, connection, function(err, file) {
- if (err) cb && cb(err);
- // SMB2 query directory
- else
- SMB2Request(
- 'set_info',
- {
- FileId: file.FileId,
- FileInfoClass: 'FileDispositionInformation',
- Buffer: new BigInt(1, 1).toBuffer(),
- },
- connection,
- function(err, files) {
- SMB2Request('close', file, connection, function() {
- if (err) {
- return cb(err);
- }
- cb(null, files);
- });
- }
- );
+ connection.exists(path, function (err, exists) {
+ if (err) return cb && cb(err);
+
+ if (!exists) {
+ return cb && cb(new Error('Folder does not exist'));
+ }
+
+ // Open the directory
+ SMB2Request('open_folder', { path: path }, connection, function (err, file) {
+ if (err) return cb && cb(err);
+
+ // Query directory contents
+ SMB2Request('query_directory', { FileId: file.FileId }, connection, function (err, files) {
+ if (err) return cb && cb(err);
+
+ // Recursively delete files and subfolders
+ let deleteTasks = files
+ .filter(fileInfo => '.' !== fileInfo.Filename && '..' !== fileInfo.Filename)
+ .map((fileInfo) => {
+
+ let childPath = `${path}\\${fileInfo.Filename}`;
+ if (fileInfo.FileAttributes & 0x10) {
+ // Directory
+ return new Promise((resolve, reject) => {
+ rmdir.call(connection, childPath, (err) => {
+ if (err) reject(err);
+ else resolve();
+ });
+ });
+ } else {
+ // File
+ return new Promise((resolve, reject) => {
+ connection.unlink(childPath, (err) => {
+ if (err) reject(err);
+ else resolve();
+ });
+ });
+ }
+ });
+
+ // Wait for all deletions to complete
+ Promise.all(deleteTasks)
+ .then(() => {
+ // Remove the directory itself
+ SMB2Request(
+ 'set_info',
+ {
+ FileId: file.FileId,
+ FileInfoClass: 'FileDispositionInformation',
+ Buffer: new bigint(1, 1).toBuffer(),
+ },
+ connection,
+ function (err) {
+ if (err) return cb && cb(err);
+
+ // Close the directory handle
+ SMB2Request('close', file, connection, function (err) {
+ if (err) cb && cb(err);
+ else cb && cb(null);
+ });
+ }
+ );
+ })
+ .catch((err) => cb && cb(err));
+ });
+ });
});
};
7 changes: 5 additions & 2 deletions src-electron/electronMain.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,14 @@ function initHandlerBeforeSettingLoad() {
initTerminalIpcHandler(log, terminalMap);
initSSHTerminalIpcHandler(log, terminalMap);
initTelnetIpcHandler(log, terminalMap);
initRdpHandler(log);
initVncHandler(log, vncMap);

initScpSftpHandler(log, scpMap, expressApp);
initFtpHandler(log, ftpMap, expressApp);
initSambaHandler(log, sambaMap, expressApp);

initRdpHandler(log);
initVncHandler(log, vncMap);

initClipboard(log, mainWindow);
initCustomSessionHandler(log);

Expand Down
4 changes: 2 additions & 2 deletions src-electron/ipc/file-explorer/ftp.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ function initFtpHandler(log, ftpMap, expressApp) {
});

expressApp.post('/api/v1/ftp/upload/:id', upload.single('uploadFiles'), async (req, res) => {
const { data } = req.body;
const { data, filename} = req.body;
const path = JSON.parse(data).name;
const configId = req.params['id'];

Expand All @@ -163,7 +163,7 @@ function initFtpHandler(log, ftpMap, expressApp) {

try {
const result = await withFtpClient(configId, async (client) => {
const remotePath = await avoidDuplicateName(client, `${path}/${req.file.originalname}`);
const remotePath = await avoidDuplicateName(client, `${path}/${filename}`);// the req.file.originalname may have encoding pb
const bufferStream = new Readable();
bufferStream.push(req.file.buffer);
bufferStream.push(null);
Expand Down
69 changes: 63 additions & 6 deletions src-electron/ipc/file-explorer/samba.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const fsPromise = require('fs/promises');
const os = require('os');
const uuid = require('uuid');
const SMB2 = require('v9u-smb2');
const {sleep} = require("ssh2-sftp-client/src/utils");

function initSambaHandler(log, sambaMap, expressApp) {

Expand Down Expand Up @@ -72,6 +73,27 @@ function initSambaHandler(log, sambaMap, expressApp) {
return formattedFiles;
}

async function copyDirectory(smbClient, sourceDir, targetDir) {
// Ensure the target directory exists
await smbClient.mkdir(targetDir, true);

// List all items in the source directory
const items = await smbClient.readdir(sourceDir, { stats: true });

for (const item of items) {
const sourcePath = path.join(sourceDir, item.name);
const targetPath = path.join(targetDir, item.name);

if (item.isDirectory()) {
// Recursively copy subdirectories
await copyDirectory(smbClient, sourcePath, targetPath);
} else {
// Copy individual files
await copyPasteFile(smbClient, sourcePath, targetPath);
}
}
}

//==================== API ====================================================
expressApp.post('/api/v1/samba/:id', async (req, res) => {
const action = req.body.action || 'read';
Expand Down Expand Up @@ -110,9 +132,45 @@ function initSambaHandler(log, sambaMap, expressApp) {
const names = req.body.names || [];
const targetPath = req.body.targetPath;
for (const name of names) {
const sourceFilePath = path.join(pathParam, name);
const targetFilePath = await avoidDuplicateName(smbClient, path.join(targetPath, name));
await copyPasteFile(smbClient, sourceFilePath, targetFilePath);
const sourcePath = path.join(pathParam, name);
const targetPathWithName = await avoidDuplicateName(smbClient, path.join(targetPath, name));
const stats = await smbClient.stat(sourcePath);

if (stats.isDirectory()) {
// Recursively copy the directory
await copyDirectory(smbClient, sourcePath, targetPathWithName);
} else {
// Copy a single file
await copyPasteFile(smbClient, sourcePath, targetPathWithName);
}
}
return { cwd: { name: pathParam, type: 'folder' }, files: await list(smbClient, targetPath, names) };
}
case 'move': {
const names = req.body.names || [];
const targetPath = req.body.targetPath;
for (const name of names) {
const sourcePath = path.join(pathParam, name);
const targetPathWithName = await avoidDuplicateName(smbClient, path.join(targetPath, name));
const stats = await smbClient.stat(sourcePath);

if (stats.isDirectory()) {
// Recursively copy the directory
await copyDirectory(smbClient, sourcePath, targetPathWithName);

// Ensure all resources are closed before deleting the source directory
// FIXME: the smbClient resolve too early, so we need wait a little
await new Promise((resolve) => setTimeout(resolve, 10 * 1000));

// Remove the original directory
// FIXME: also it's better to use a new connection
await withSambaClient(configId, async newSmbClient => await newSmbClient.rmdir(sourcePath));
} else {
// Copy and remove a single file
await copyPasteFile(smbClient, sourcePath, targetPathWithName);
await smbClient.unlink(sourcePath);
}

}
return { cwd: { name: pathParam, type: 'folder' }, files: await list(smbClient, targetPath, names) };
}
Expand All @@ -139,7 +197,7 @@ function initSambaHandler(log, sambaMap, expressApp) {
});

expressApp.post('/api/v1/samba/upload/:id', upload.single('uploadFiles'), async (req, res) => {
const { data } = req.body;
const { data, filename } = req.body;
const targetDir = fixPath(JSON.parse(data).name);
const configId = req.params['id'];

Expand All @@ -148,10 +206,9 @@ function initSambaHandler(log, sambaMap, expressApp) {
res.status(400).send({ error: { code: 400, message: 'No file uploaded' } });
return;
}

try {
const result = await withSambaClient(configId, async (smbClient) => {
const targetPath = await avoidDuplicateName(smbClient, path.join(targetDir, req.file.originalname));
const targetPath = await avoidDuplicateName(smbClient, path.join(targetDir, filename)); // the req.file.originalname may have encoding pb
await smbClient.writeFile(targetPath, req.file.buffer);
return { success: true, message: `File uploaded to ${targetPath}` };
});
Expand Down
Loading

0 comments on commit 32f57f3

Please sign in to comment.