SFTP Connenction manager d365fo x++
SFTP Connenction manager d365fo x++
using System.IO; using System.Collections; using Renci.SshNet; using Renci.SshNet.Sftp;//RESCP.ssh class DSAPSFTPConnectionManager { /// <summary> /// Test SFTP connection /// </summary> public static boolean testConnection(DSAPSFTPProfiles _profile) { boolean isConnected = false; System.Exception ex; DSAPSFTPProfiles profileUpdate; try { SftpClient sftp = new SftpClient( _profile.HostName, _profile.Port, _profile.UserName, _profile.Password ); sftp.Connect(); if (sftp.IsConnected) { info(strFmt("SFTP Authentication successful to %1:%2", _profile.HostName, _profile.Port)); isConnected = true; // Update connection status using a separate select forupdate ttsbegin; select forupdate profileUpdate where profileUpdate.RecId == _profile.RecId; if (profileUpdate) { profileUpdate.ConnectionStatus = DSAPSFTPConnectionStatus::Valid; profileUpdate.LastValidatedBy = curUserId(); profileUpdate.LastValidatedDateTime = DateTimeUtil::utcNow(); profileUpdate.update(); } ttscommit; } sftp.Disconnect(); sftp.Dispose(); } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); while (ex) { warning(strFmt("Exception: %1", ex.get_Message())); ex = ex.get_InnerException(); } // Update connection status on failure try { ttsbegin; select forupdate profileUpdate where profileUpdate.RecId == _profile.RecId; if (profileUpdate) { profileUpdate.ConnectionStatus = DSAPSFTPConnectionStatus::Invalid; profileUpdate.LastValidatedBy = curUserId(); profileUpdate.LastValidatedDateTime = DateTimeUtil::utcNow(); profileUpdate.update(); } ttscommit; } catch { // If update fails, just log it warning("Failed to update profile connection status"); } } return isConnected; } /// <summary> /// Upload file to SFTP server - CORRECTED VERSION /// </summary> public static void uploadFile(DSAPSFTPProfiles _profile, str localFilePath) { System.Exception ex; try { // Initialize SFTP client Renci.SshNet.SftpClient sftp = new Renci.SshNet.SftpClient( _profile.HostName, _profile.Port, _profile.UserName, _profile.Password ); sftp.Connect(); if (!sftp.IsConnected) { throw new System.Exception(strFmt("Failed to connect to %1:%2", _profile.HostName, _profile.Port)); } info(strFmt("Connected to SFTP server: %1:%2", _profile.HostName, _profile.Port)); // Get the working directory first str workingDirectory = sftp.WorkingDirectory; info(strFmt("Current working directory: %1", workingDirectory)); // Determine remote folder - use lowercase 'out' as shown in FileZilla str remoteFolder; if (_profile.FolderOUT && strLen(_profile.FolderOUT) > 0) { remoteFolder = _profile.FolderOUT; // Remove any leading slashes or backslashes while (strLen(remoteFolder) > 0 && (strStartsWith(remoteFolder, "/") || strStartsWith(remoteFolder, "\\"))) { remoteFolder = subStr(remoteFolder, 2, strLen(remoteFolder) - 1); } } else { // Default to 'out' folder (lowercase as seen in FileZilla) remoteFolder = "out"; } // Build the full remote folder path // Try to use relative path from working directory str remoteFolderPath = remoteFolder; info(strFmt("Checking if folder exists: %1", remoteFolderPath)); // Check if folder exists, if not try to create it try { if (!sftp.Exists(remoteFolderPath)) { info(strFmt("Folder does not exist, creating: %1", remoteFolderPath)); sftp.CreateDirectory(remoteFolderPath); } else { info(strFmt("Folder exists: %1", remoteFolderPath)); } } catch { // If checking/creating folder fails, try to continue anyway warning(strFmt("Could not verify/create folder: %1. Attempting upload anyway.", remoteFolderPath)); } // Get just the filename from the local path str fileName = System.IO.Path::GetFileName(localFilePath); // Build remote file path - use forward slash as path separator for SFTP str remoteFilePath = strFmt("%1/%2", remoteFolderPath, fileName); info(strFmt("Uploading file from: %1", localFilePath)); info(strFmt("Uploading file to: %1", remoteFilePath)); // Upload file System.IO.FileStream fs = null; try { fs = new System.IO.FileStream(localFilePath, System.IO.FileMode::Open, System.IO.FileAccess::Read); // Try upload with the constructed path sftp.UploadFile(fs, remoteFilePath, true, null); info(strFmt("File uploaded successfully: %1 → %2", fileName, remoteFilePath)); } catch (Exception::CLRError) { // If first attempt fails, try with just filename in working directory warning(strFmt("Failed to upload to %1, trying working directory", remoteFilePath)); if (fs) { fs.Close(); fs = new System.IO.FileStream(localFilePath, System.IO.FileMode::Open, System.IO.FileAccess::Read); } // Try uploading to just the filename (current directory) sftp.UploadFile(fs, fileName, true, null); info(strFmt("File uploaded to working directory: %1", fileName)); } finally { if (fs) { fs.Close(); fs.Dispose(); } } sftp.Disconnect(); sftp.Dispose(); } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); str errorMessage = ""; while (ex) { errorMessage = ex.get_Message(); error(strFmt("Upload failed: %1", errorMessage)); ex = ex.get_InnerException(); } // Provide more helpful error message if (strScan(errorMessage, "permission", 1, strLen(errorMessage)) > 0) { error("Permission denied. Check that the SFTP user has write access to the target folder."); } else if (strScan(errorMessage, "not found", 1, strLen(errorMessage)) > 0 || strScan(errorMessage, "does not exist", 1, strLen(errorMessage)) > 0) { error("Target folder not found. Verify the FolderOUT path in the SFTP Profile configuration."); } throw; } } /// <summary> /// Read remote file list from SFTP server using Renci.SshNet /// </summary> public static List getRemoteFileList(DSAPSFTPProfiles _profile, boolean useInFolder = false) { List fileList = new List(Types::String); System.Exception ex; try { str host = _profile.HostName; int port = _profile.Port; str username = _profile.UserName; str password = _profile.Password; str remoteFolder = useInFolder ? (strLen(_profile.FolderIN) ? _profile.FolderIN : "/IN") : (strLen(_profile.FolderOUT) ? _profile.FolderOUT : "/OUT"); Renci.SshNet.SftpClient sftpClient = new Renci.SshNet.SftpClient(host, port, username, password); sftpClient.Connect(); System.Collections.IEnumerable files = sftpClient.ListDirectory(remoteFolder, null); System.Collections.IEnumerator enumerator = files.GetEnumerator(); while (enumerator.MoveNext()) { Renci.SshNet.Sftp.SftpFile file = enumerator.get_Current(); if (!file.get_IsDirectory() && file.get_Name() != "." && file.get_Name() != "..") { // Add full path for deletion or download fileList.addEnd(file.get_FullName()); } } sftpClient.Disconnect(); } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); warning(strFmt("Error listing remote files: %1", ex.get_Message())); } return fileList; } /// <summary> /// Delete file from SFTP server /// </summary> public static void DeleteRemoteFiles(DSAPSFTPProfiles _profile, List fileList) { System.Exception ex; if (fileList.elements() == 0) { info("No files provided for deletion."); return; } try { str host = _profile.HostName; int port = _profile.Port; str username = _profile.UserName; str password = _profile.Password; Renci.SshNet.SftpClient sftpClient = new Renci.SshNet.SftpClient(host, port, username, password); sftpClient.Connect(); if (!sftpClient.IsConnected) { warning("SFTP connection failed. Cannot delete files."); return; } ListEnumerator le = fileList.getEnumerator(); while (le.moveNext()) { str remoteFileFullPath = le.current(); // full path now try { if (sftpClient.Exists(remoteFileFullPath)) { sftpClient.DeleteFile(remoteFileFullPath); info(strFmt("Deleted file: %1", remoteFileFullPath)); } else { warning(strFmt("File not found on server: %1", remoteFileFullPath)); } } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); warning(strFmt("Failed to delete file %1: %2", remoteFileFullPath, ex.get_Message())); } } sftpClient.Disconnect(); info("Delete operation completed."); } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); warning(strFmt("SFTP delete operation failed: %1", ex.get_Message())); } } public static void MoveFileOutToIn(DSAPSFTPProfiles _profile) { System.Exception ex; try { str host = _profile.HostName; int port = _profile.Port; str username = _profile.UserName; str password = _profile.Password; str sourceFolder = strLen(_profile.FolderOUT) ? _profile.FolderOUT : "/OUT"; str destinationFolder = strLen(_profile.FolderIN) ? _profile.FolderIN : "/IN"; Renci.SshNet.SftpClient sftpClient = new Renci.SshNet.SftpClient(host, port, username, password); sftpClient.Connect(); if (!sftpClient.IsConnected) { warning("SFTP connection failed."); return; } System.Collections.IEnumerable files = sftpClient.ListDirectory(sourceFolder, null); System.Collections.IEnumerator enumerator = files.GetEnumerator(); int movedCount = 0; int errorCount = 0; while (enumerator.MoveNext()) { Renci.SshNet.Sftp.SftpFile file = enumerator.get_Current(); // Skip directories and system files if (!file.get_IsDirectory() && file.get_Name() != "." && file.get_Name() != "..") { str sourceFilePath = sourceFolder + "/" + file.get_Name(); str destinationFilePath = destinationFolder + "/" + file.get_Name(); try { sftpClient.RenameFile(sourceFilePath, destinationFilePath); movedCount++; info(strFmt("File moved successfully: %1 → %2", sourceFilePath, destinationFilePath)); } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); warning(strFmt("Failed to move file %1: %2", sourceFilePath, ex.get_Message())); errorCount++; } } } sftpClient.Disconnect(); if (movedCount > 0 && errorCount == 0) info(strFmt("Successfully moved %1 files from OUT to IN folder.", movedCount)); else if (movedCount > 0 && errorCount > 0) warning(strFmt("Moved %1 files, %2 errors occurred.", movedCount, errorCount)); else info("No files found to move in OUT folder."); } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); warning(strFmt("Error moving files to IN folder: %1", ex.get_Message())); } } public static void MoveFileInToOut(DSAPSFTPProfiles _profile) { System.Exception ex; try { str host = _profile.HostName; int port = _profile.Port; str username = _profile.UserName; str password = _profile.Password; str sourceFolder = strLen(_profile.FolderIN) ? _profile.FolderIN : "/IN"; str destinationFolder = strLen(_profile.FolderOUT) ? _profile.FolderOUT : "/OUT"; Renci.SshNet.SftpClient sftpClient = new Renci.SshNet.SftpClient(host, port, username, password); sftpClient.Connect(); if (!sftpClient.IsConnected) { warning("SFTP connection failed."); return; } System.Collections.IEnumerable files = sftpClient.ListDirectory(sourceFolder, null); System.Collections.IEnumerator enumerator = files.GetEnumerator(); int movedCount = 0; int errorCount = 0; while (enumerator.MoveNext()) { Renci.SshNet.Sftp.SftpFile file = enumerator.get_Current(); // Skip directories and system files if (!file.get_IsDirectory() && file.get_Name() != "." && file.get_Name() != "..") { str sourceFilePath = sourceFolder + "/" + file.get_Name(); str destinationFilePath = destinationFolder + "/" + file.get_Name(); try { sftpClient.RenameFile(sourceFilePath, destinationFilePath); movedCount++; info(strFmt("File moved successfully: %1 → %2", sourceFilePath, destinationFilePath)); } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); warning(strFmt("Failed to move file %1: %2", sourceFilePath, ex.get_Message())); errorCount++; } } } sftpClient.Disconnect(); if (movedCount > 0 && errorCount == 0) info(strFmt("Successfully moved %1 files from IN to OUT folder.", movedCount)); else if (movedCount > 0 && errorCount > 0) warning(strFmt("Moved %1 files, %2 errors occurred.", movedCount, errorCount)); else info("No files found to move in IN folder."); } catch (Exception::CLRError) { ex = CLRInterop::getLastException(); warning(strFmt("Error moving files from IN to OUT folder: %1", ex.get_Message())); } } /// <summary> /// Download file from SFTP server using Renci.SshNet /// </summary> public static void downloadFile(DSAPSFTPProfiles _profile, str remoteFileName, str localFolder) { System.Exception ex; if (!System.IO.Directory::Exists(localFolder)) { warning(strFmt("Local folder does not exist: %1", localFolder)); return; } try { str host = _profile.HostName; int port = _profile.Port; str username = _profile.UserName; str password = _profile.Password; // Fix remote folder path str remoteFolder = strLen(_profile.FolderIN) ? _profile.FolderIN : "/"; if (!strEndsWith(remoteFolder, "/")) remoteFolder += "/"; // Use full path only if needed str remoteFilePath = strStartsWith(remoteFileName, "/") ? remoteFileName : remoteFolder + remoteFileName; str fileName = System.IO.Path::GetFileName(remoteFileName); str localFilePath = System.IO.Path::Combine(localFolder, fileName); info(strFmt("Attempting download: %1 → %2", remoteFilePath, localFilePath)); Renci.SshNet.SftpClient sftpClient = new Renci.SshNet.SftpClient(host, port, username, password); sftpClient.Connect(); if (!sftpClient.IsConnected) { warning("SFTP connection failed."); return; } // Check if file exists on server if (!sftpClient.Exists(remoteFilePath)) { warning(strFmt("Remote file not found: %1", remoteFilePath)); sftpClient.Disconnect(); return; } // Download file System.IO.FileStream fileStream = new System.IO.FileStream(localFilePath, System.IO.FileMode::Create); sftpClient.DownloadFile(remoteFilePath, fileStream, null); fileStream.Close(); sftpClient.Disconnect(); info(strFmt("File downloaded successfully: %1 → %2", remoteFilePath, localFilePath)); } catch (Exception::CLRError) { System.Exception clrEx = CLRInterop::getLastException(); System.Exception innerEx = clrEx.get_InnerException(); str message = clrEx.get_Message(); if (innerEx) message += " | Inner Exception: " + innerEx.get_Message(); warning(strFmt("Download failed: %1", message)); } } }
Comments
Post a Comment