package com.cattles.util.ssh.jsch;
import com.cattles.util.ssh.SSHException;
import com.cattles.util.ssh.SSHMonitor;
import com.cattles.util.ssh.SSHResult;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.io.*;
import java.util.List;
import static com.cattles.util.ssh.SCPUtil.*;
import static com.cattles.util.ssh.SSHResult.makeFailedResult;
public class JschSCPTo implements JschSCPExecutable {
public SSHResult execSCP(Session sshSession, String origin, String dest,
String option, List<SSHMonitor> monitors) {
SSHResult result = new SSHResult("SCP " + option + " " + origin + " " + dest);
boolean isAll = false;
int length = origin.length();
String filePath = origin;
if (origin.substring(length - 1).equals("*")) {
filePath = origin.substring(0, length - 1);
isAll = true;
}
File file = new File(filePath);
try {
if (!file.exists()) {
makeFailedResult(result, new SSHException("File or Directory " + file.getCanonicalPath() + " dosen't exists!"), "SCP error! probably is local file not exists\n");
return result;
}
if (file.isFile()) {
doSingleFileTransfer(sshSession, file, parseRemoteURL(dest),
option, result, monitors);
} else if (file.isDirectory()) {
if (isAll) {
doMultipleFileTransfer(sshSession, file, parseRemoteURL(dest), option, result, monitors);
} else {
doMultipleTransfer(sshSession, file, parseRemoteURL(dest), option, result, monitors);
}
}
result.setSuccess(true);
result.append("Transfer complete!\n");
} catch (JSchException e) {
makeFailedResult(result, e, "SCP error!\n");
} catch (IOException e) {
makeFailedResult(result, e, "SCP error! probably is IO error!\n");
} catch (SSHException e) {
makeFailedResult(result, e, "SCP error! probably is remote server response error!\n");
}
return result;
}
private void doSingleFileTransfer(Session sshSession, File localFile, String dest, String option
, SSHResult result, List<SSHMonitor> monitors) throws JSchException, IOException, SSHException {
String command = "scp -t " + option + " " + dest;
Channel channel = sshSession.openChannel("exec");
try {
((ChannelExec) channel).setCommand(command);
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
channel.connect();
waitForAck(in);
result.append("Beginning transfer " + localFile.getCanonicalPath() + "\n");
sendFileToRemote(localFile, in, out, result, monitors);
} finally {
if (channel != null) channel.disconnect();
}
}
private void doMultipleTransfer(Session sshSession, File localFile, String dest, String option
, SSHResult result, List<SSHMonitor> monitors) throws JSchException, IOException, SSHException {
String command = "scp -r -d -t " + option + " " + dest;
Channel channel = sshSession.openChannel("exec");
try {
((ChannelExec) channel).setCommand(command);
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
channel.connect();
waitForAck(in);
result.append("Beginning transfer " + localFile.getCanonicalPath() + "\n");
sendDirectoryToRemote(localFile, in, out, result, monitors);
result.append(localFile.getCanonicalPath() + " transferred successful!" + "\n");
} finally {
if (channel != null) channel.disconnect();
}
}
private void doMultipleFileTransfer(Session sshSession, File localFile, String dest, String option
, SSHResult result, List<SSHMonitor> monitors) throws JSchException, IOException, SSHException {
String command = "scp -r -d -t " + option + " " + dest;
Channel channel = sshSession.openChannel("exec");
try {
((ChannelExec) channel).setCommand(command);
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
channel.connect();
waitForAck(in);
result.append("Beginning transfer " + localFile.getCanonicalPath() + "\n");
digDirectory(localFile, in, out, result, monitors);
out.write("E\n".getBytes());
out.flush();
waitForAck(in);
result.append(localFile.getCanonicalPath() + " transferred successful!" + "\n");
} finally {
if (channel != null) channel.disconnect();
}
}
private void digDirectory(File localFile, InputStream in, OutputStream out, SSHResult result, List<SSHMonitor> monitors) throws IOException, SSHException {
String msg = "Directory " + localFile.getCanonicalPath() + " is transferred!\n";
result.append(msg);
if (!monitors.isEmpty()) {
for (SSHMonitor mon : monitors) {
mon.info(msg);
}
}
for (File file : localFile.listFiles()) {
if (file.isFile()) {
sendFileToRemote(file, in, out, result, monitors);
} else if (file.isDirectory()) {
sendDirectoryToRemote(file, in, out, result, monitors);
}
}
}
private void sendDirectoryToRemote(File dir, InputStream in, OutputStream out, SSHResult result, List<SSHMonitor> monitors) throws IOException, SSHException {
String command = "D0755 0 " + dir.getName() + "\n";
out.write(command.getBytes());
out.flush();
waitForAck(in);
digDirectory(dir, in, out, result, monitors);
out.write("E\n".getBytes());
out.flush();
waitForAck(in);
}
private void sendFileToRemote(File localFile, InputStream in, OutputStream out, SSHResult result, List<SSHMonitor> monitors) throws IOException, SSHException {
// send "C0644 filesize filename", where filename should not include '/'
long fileSize = localFile.length();
String command = "C0644 " + fileSize + " " + localFile.getName() + "\n";
out.write(command.getBytes());
out.flush();
waitForAck(in);
// send a content of localFile
FileInputStream fis = new FileInputStream(localFile);
byte[] buf = new byte[BUF_SIZE];
long transferred = 0;
try {
while (true) {
int len = fis.read(buf, 0, buf.length);
if (len <= 0) break;
out.write(buf, 0, len);
transferred += len;
if (!monitors.isEmpty() && fileSize > REST_SIZE) {
for (SSHMonitor monitor : monitors) {
monitor.info(localFile.getCanonicalPath() + " is transferring, progress is " + trackProgress(fileSize, transferred));
}
}
/*删除部分*/
// if(fileSize>REST_SIZE){
// try{Thread.sleep(100);}catch(Exception ee){};
// }
}
out.flush();
sendAck(out);
waitForAck(in);
} finally {
fis.close();
}
result.append(localFile.getCanonicalPath() + " transferred successful!\n");
}
}