Skip to content

Instantly share code, notes, and snippets.

@mhokanson
Last active September 15, 2025 22:01
Show Gist options
  • Select an option

  • Save mhokanson/fbe605002678b36c4b7f0dd534b1ac50 to your computer and use it in GitHub Desktop.

Select an option

Save mhokanson/fbe605002678b36c4b7f0dd534b1ac50 to your computer and use it in GitHub Desktop.
Accept files via SFTP in Mirth Connect from a Javascript Reader
var sftpConfigs = [
{
"name":"SFTP 1",
"host":"127.0.0.1",
"port":"22",
"directory":"/folder/path/to/messages",
"username":"username1",
"password":"password1",
"isBinary": false,
"afterReadAction":{
"action":"leave"
}
},
{
"name":"SFTP 2",
"host":"localhost",
"port":"22",
"directory":"/path/to/pickup",
"username":"username2",
"password":"password2",
"isBinary": false,
"afterReadAction":{
"action":"delete"
}
},
{
"name":"SFTP 3",
"host":"0.0.0.0",
"port":"22",
"directory":"/SFTPMirth/upload",
"username":"username3",
"password":"password3",
"isBinary": false,
"afterReadAction":{
"action":"move",
"targetDirectory":"/SFTPMirth/upload/test1/test2"
}
}
]
importPackage(com.jcraft.jsch);
sftpConfigs = JSON.parse($cfg("SFTPConfigs"))
// Loop through defined configs and check for files
for(var i=0; i < sftpConfigs.length;i++){
var config = sftpConfigs[i];
// The next bit is based on Nick Rupley's code at:
// https://forums.mirthproject.io/forum/mirth-connect/support/8410-sftp-client?p=60591#post60591
// establish a connection to the SFTP site
var jsch = new JSch();
jsch.setConfig('StrictHostKeyChecking','no');
var session = jsch.getSession(config.username,config.host,config.port);
session.setPassword(config.password);
session.connect();
var channel = session.openChannel('sftp');
channel.connect();
var remoteWorkingDirectory = channel.pwd();
channel.cd(config.directory)
var files = channel.ls("*.*");
for(var f = 0; f < files.size(); f++){
// Exclude folders and symlinks from processing
if( files.get(f).getAttrs().isDir() != true &&
files.get(f).getAttrs().isLink() != true){
var filename = files.get(f).getFilename();
var filepath = files.get(f).getLongname();
// Get the last-modified timestamp for the file
// Also append a trio of zeros to make the timestamp compatible with Date objects
var file_mtime = files.get(f).getAttrs().getMTime() + "000"
var file_age = Date.now() - file_mtime
var inputStream = channel.get(filename)
// Read in the file
if(config.isBinary == true){
var byteArray = org.apache.commons.io.IOUtils.toByteArray(inputStream)
var b64File = java.util.Base64.getEncoder().encodeToString(byteArray)
var file = new RawMessage(b64File, null, {
"fileDirectory":config.directory + "/" + filename,
"originalFilename":filename,
"transferType":config.transferType
})
} else {
var fileContents = org.apache.commons.io.IOUtils.toString(inputStream,'UTF-8')
var file = new RawMessage(fileContents, null, {
"fileDirectory":config.directory + "/" + filename,
"originalFilename":filename,
"transferType":config.transferType
})
}
var msgRoutingResponse = com.mirth.connect.server.userutil.VMRouter().routeMessageByChannelId(channelId, file)
// Trying to work out bad-read detection
// logger.info("msgRoutingResponse: "+JSON.stringify(msgRoutingResponse))
// The process should have thrown an error if file transfer was unsuccessful prior to this
// preventing deletion of failed transfers once complete
switch(config.afterReadAction.action){
case "delete":
channel.rm(filename)
break;
case "move":
// Get the relative path to the destination folder
remoteWorkingDirectory = channel.pwd();
var mkDirPath = config.afterReadAction.targetDirectory
if(mkDirPath.substring(0,remoteWorkingDirectory.length()) == remoteWorkingDirectory){
mkDirPath = mkDirPath.substring(remoteWorkingDirectory.length())
}
// Create the destination directory, if needed
//
// As we cannot create subfolders recursively we'll
// need to check for each folder in the destination path
// and create any folders we find missing
var pathParts = mkDirPath.split("/");
var partialPath = config.directory
for(var p = 0; p < pathParts.length; p++){
if(pathParts[p] == ""){
continue;
}
// The current reletive folder we're checking for
partialPath = partialPath + "/" + pathParts[p]
// Try to create the current folder of the partial destination path
// If the folder already exists an error is thrown
try{
channel.mkdir(partialPath)
} catch (e) {
// Do nothing, as reaching here means the foldr already exists
var folderAlreadyExists
}
}
// Move the file to the destination folder
channel.rename(file.filepath,config.afterReadAction.targetDirectory + "/" + filename)
break;
default:
// Leave things as they are
}
}
}
session.disconnect();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment