429 lines
18 KiB
Java
429 lines
18 KiB
Java
package TestingSystem.DVM;
|
||
import Common.Constants;
|
||
import Common.Global;
|
||
import Common.Utils.Utils;
|
||
import GlobalData.Machine.Machine;
|
||
import GlobalData.RemoteFile.RemoteFile;
|
||
import GlobalData.User.User;
|
||
import ProjectData.Project.db_project_info;
|
||
import Visual_DVM_2021.Passes.PassException;
|
||
import com.jcraft.jsch.*;
|
||
import javafx.util.Pair;
|
||
|
||
import java.io.*;
|
||
import java.nio.charset.StandardCharsets;
|
||
import java.util.LinkedHashMap;
|
||
import java.util.Vector;
|
||
public class UserConnection {
|
||
public int iterations = 0; //для тестирования
|
||
//--
|
||
public ChannelSftp sftpChannel = null;
|
||
public ChannelShell shellChannel = null;
|
||
public ChannelExec execChannel = null;
|
||
//--
|
||
JSch jsch = null;
|
||
Session session = null;
|
||
//---
|
||
PipedInputStream in = null;
|
||
PipedOutputStream out = null;
|
||
//---
|
||
PipedOutputStream pin = null;
|
||
PipedInputStream pout = null;
|
||
InputStreamReader fromServer = null;
|
||
//---
|
||
public UserConnection(Machine machine, User user) throws Exception {
|
||
session = (jsch = new JSch()).getSession(user.login, machine.address, machine.port);
|
||
session.setPassword(user.password);
|
||
session.setConfig("StrictHostKeyChecking", "no");
|
||
session.connect(0);
|
||
//-->
|
||
//создать канал для файлов
|
||
sftpChannel = (ChannelSftp) session.openChannel("sftp");
|
||
sftpChannel.connect();
|
||
//-->
|
||
//создать канал для команд
|
||
shellChannel = (ChannelShell) session.openChannel("shell");
|
||
in = new PipedInputStream();
|
||
out = new PipedOutputStream();
|
||
/*
|
||
shellChannel.setInputStream(in);
|
||
shellChannel.setOutputStream(out);
|
||
pin = new PipedOutputStream(in);
|
||
pout = new PipedInputStream(out);
|
||
shellChannel.connect();
|
||
//-
|
||
fromServer = new InputStreamReader(pout);
|
||
ShellParser.setUserName(user.login);
|
||
ShellParser.ReadInvitation(fromServer); //прочитать первое приглашение от машины.
|
||
*/
|
||
}
|
||
public void Disconnect() {
|
||
if (in != null) {
|
||
try {
|
||
in.close();
|
||
} catch (Exception exception) {
|
||
Global.Log.PrintException(exception);
|
||
}
|
||
}
|
||
if (out != null) {
|
||
try {
|
||
out.close();
|
||
} catch (Exception exception) {
|
||
Global.Log.PrintException(exception);
|
||
}
|
||
}
|
||
if (pin != null) {
|
||
try {
|
||
pin.close();
|
||
} catch (Exception exception) {
|
||
Global.Log.PrintException(exception);
|
||
}
|
||
}
|
||
if (pout != null) {
|
||
try {
|
||
pout.close();
|
||
} catch (Exception exception) {
|
||
Global.Log.PrintException(exception);
|
||
}
|
||
}
|
||
if (fromServer != null) {
|
||
try {
|
||
fromServer.close();
|
||
} catch (Exception exception) {
|
||
Global.Log.PrintException(exception);
|
||
}
|
||
}
|
||
if (sftpChannel != null) sftpChannel.disconnect();
|
||
if (shellChannel != null) shellChannel.disconnect();
|
||
if (execChannel != null) execChannel.disconnect();
|
||
if (session != null) {
|
||
session.disconnect();
|
||
}
|
||
//----------------------
|
||
sftpChannel = null;
|
||
shellChannel = null;
|
||
execChannel = null;
|
||
jsch = null;
|
||
session = null;
|
||
//---
|
||
in = null;
|
||
out = null;
|
||
//---
|
||
pin = null;
|
||
pout = null;
|
||
fromServer = null;
|
||
System.gc();
|
||
}
|
||
//--
|
||
//todo из за мусора результатом пользоваться в общем случае невозможно.
|
||
//следует перенаправлять вывод в какой нибудь временный файл на сервере.
|
||
/*
|
||
public String ShellCommand(String command) throws Exception {
|
||
StringBuilder result = new StringBuilder();
|
||
pin.write((command + "\r\n").getBytes());
|
||
ShellParser.ReadInvitation(fromServer); //первое приглашение после эхо. возможен мусор.
|
||
result.append(ShellParser.getCommandResult(fromServer)); //возможный результат и второе приглашение.
|
||
String[] data = result.toString().split("\n");
|
||
return (data.length > 0) ? data[data.length - 1] : result.toString();
|
||
}
|
||
*/
|
||
public void getSingleFile(String src, String dst) throws Exception {
|
||
sftpChannel.get(src, dst);
|
||
}
|
||
public long getFileKBSize(String path) throws Exception {
|
||
long size = sftpChannel.lstat(path).getSize();
|
||
return size / 1024;
|
||
}
|
||
public void getSingleFileWithMaxSize(RemoteFile src, File dst, int maxSize) throws Exception {
|
||
if ((maxSize == 0) || getFileKBSize(src.full_name) <= maxSize) {
|
||
getSingleFile(src.full_name, dst.getAbsolutePath());
|
||
} else {
|
||
Utils.WriteToFile(dst, "Размер файла превышает " + maxSize + " KB.\n" + "Файл не загружен. Его можно просмотреть на машине по адресу\n" + Utils.Brackets(src.full_name));
|
||
}
|
||
}
|
||
public void putSingleFile(File src, RemoteFile dst) throws Exception {
|
||
sftpChannel.put(src.getAbsolutePath(), dst.full_name);
|
||
}
|
||
//-
|
||
public void MKDIR(RemoteFile dir) throws Exception {
|
||
if (!Exists(dir)) sftpChannel.mkdir(dir.full_name);
|
||
}
|
||
//-
|
||
public void RMDIR(String dir) throws Exception {
|
||
if (!dir.isEmpty() && !dir.equals("/") && !dir.equals("\\") && !dir.equals("*")) {
|
||
Command("rm -rf " + Utils.DQuotes(dir));
|
||
} else throw new PassException("Недопустимый путь для удаления папки " + Utils.DQuotes(dir));
|
||
}
|
||
//-
|
||
public void SynchronizeSubDirsR(File local_dir, RemoteFile remote_dir) throws Exception {
|
||
File[] local_subdirs = local_dir.listFiles(File::isDirectory);
|
||
File[] local_files = local_dir.listFiles(File::isFile);
|
||
//------------------------------------------------------------------------
|
||
LinkedHashMap<String, RemoteFile> remote_subdirs = new LinkedHashMap<>();
|
||
LinkedHashMap<String, RemoteFile> remote_files = new LinkedHashMap<>();
|
||
Vector<ChannelSftp.LsEntry> files = sftpChannel.ls(remote_dir.full_name);
|
||
for (ChannelSftp.LsEntry file : files) {
|
||
if (file.getAttrs().isDir()) {
|
||
if (!file.getFilename().equals(".") && !file.getFilename().equals(".."))
|
||
remote_subdirs.put(file.getFilename(), new RemoteFile(remote_dir.full_name, file.getFilename(), true));
|
||
} else {
|
||
RemoteFile rf = new RemoteFile(remote_dir.full_name, file.getFilename());
|
||
rf.updateTime = RemoteFile.convertUpdateTime(file.getAttrs().getMTime());
|
||
remote_files.put(file.getFilename(), rf);
|
||
}
|
||
}
|
||
if (local_subdirs != null) {
|
||
for (File lsd : local_subdirs) {
|
||
if (!lsd.getName().equals(Constants.data)) {
|
||
RemoteFile rsd = null;
|
||
if (!remote_subdirs.containsKey(lsd.getName()))
|
||
sftpChannel.mkdir((rsd = new RemoteFile(remote_dir.full_name, lsd.getName(), true)).full_name);
|
||
else rsd = remote_subdirs.get(lsd.getName());
|
||
SynchronizeSubDirsR(lsd, rsd);
|
||
}
|
||
}
|
||
}
|
||
if (local_files != null) {
|
||
for (File lf : local_files) {
|
||
RemoteFile rf = null;
|
||
if (!remote_files.containsKey(lf.getName())) {
|
||
rf = new RemoteFile(remote_dir.full_name, lf.getName());
|
||
putSingleFile(lf, rf);
|
||
} else {
|
||
rf = remote_files.get(lf.getName());
|
||
if (lf.lastModified() > rf.updateTime) {
|
||
putSingleFile(lf, rf);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
public void writeToFile(String text, RemoteFile dst) throws Exception {
|
||
sftpChannel.put(new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8)), dst.full_name);
|
||
sftpChannel.chmod(0777, dst.full_name);
|
||
}
|
||
public String readFromFile(RemoteFile src) throws Exception {
|
||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||
sftpChannel.get(src.full_name, outputStream);
|
||
return outputStream.toString(StandardCharsets.UTF_8.name());
|
||
}
|
||
//--
|
||
public boolean Exists(String file_full_name) throws Exception {
|
||
try {
|
||
sftpChannel.lstat(file_full_name);
|
||
return true;
|
||
} catch (SftpException e) {
|
||
if (e.id == ChannelSftp.SSH_FX_NO_SUCH_FILE) {
|
||
// file doesn't exist
|
||
return false;
|
||
} else {
|
||
// something else went wrong
|
||
throw e;
|
||
}
|
||
}
|
||
}
|
||
public boolean Exists(RemoteFile file) throws Exception {
|
||
return Exists(file.full_name);
|
||
}
|
||
//--
|
||
public Pair<RemoteFile, RemoteFile> performScript(RemoteFile directory, String... commands) throws Exception {
|
||
RemoteFile script_file = new RemoteFile(directory, Constants.script);
|
||
RemoteFile out = new RemoteFile(directory, Constants.out_file);
|
||
RemoteFile err = new RemoteFile(directory, Constants.err_file);
|
||
//
|
||
Vector<RemoteFile> files = new Vector<>();
|
||
files.add(script_file);
|
||
files.add(out);
|
||
files.add(err);
|
||
for (RemoteFile file : files) {
|
||
if (Exists(file))
|
||
sftpChannel.rm(file.full_name);
|
||
}
|
||
//--
|
||
writeToFile("cd " + Utils.DQuotes(directory.full_name) + "\n" + String.join("\n", commands), script_file);
|
||
//--
|
||
Command(Utils.DQuotes(script_file.full_name) + " 1>" + Utils.DQuotes(out.full_name) + " 2>" + Utils.DQuotes(err.full_name));
|
||
return new Pair<>(out, err);
|
||
}
|
||
public void putResource(RemoteFile dstDirectory, String resource_name) throws Exception {
|
||
File src = Utils.CreateTempResourceFile(resource_name);
|
||
RemoteFile dst = new RemoteFile(dstDirectory, resource_name);
|
||
putSingleFile(src, dst);
|
||
}
|
||
boolean compileModule(RemoteFile modulesDirectory, String module_name) throws Exception {
|
||
String flags = module_name.equals("planner") ? getAvailibleCPPStandard(modulesDirectory) : "";
|
||
String command = "g++ -O3 " + flags + " " + Utils.DQuotes(module_name + ".cpp") + " -o " + Utils.DQuotes(module_name);
|
||
RemoteFile binary = new RemoteFile(modulesDirectory, module_name);
|
||
//--
|
||
if (Exists(binary))
|
||
sftpChannel.rm(binary.full_name);
|
||
//--
|
||
performScript(modulesDirectory, command);
|
||
//--
|
||
if (Exists(binary)) {
|
||
sftpChannel.chmod(0777, binary.full_name);
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
String getAvailibleCPPStandard(RemoteFile scriptDirectory) throws Exception {
|
||
String res = "";
|
||
String command = "g++ -v --help 2> /dev/null | sed -n '/^ *-std=\\([^<][^ ]\\+\\).*/ {s//\\1/p}' | grep c++";
|
||
System.out.println(command);
|
||
Pair<RemoteFile, RemoteFile> oe = performScript(scriptDirectory, command);
|
||
RemoteFile outFile = oe.getKey();
|
||
String out = readFromFile(outFile);
|
||
//--
|
||
RemoteFile cppVersionsInfo = new RemoteFile(scriptDirectory, "cpp_versions.txt");
|
||
sftpChannel.rename(outFile.full_name, cppVersionsInfo.full_name);
|
||
//--
|
||
String[] data = out.split("\n");
|
||
boolean cpp_17 = false;
|
||
boolean cpp_11 = false;
|
||
//определить какие есть версии.
|
||
for (String version : data) {
|
||
switch (version) {
|
||
case "c++17":
|
||
cpp_17 = true;
|
||
break;
|
||
case "c++11":
|
||
cpp_11 = true;
|
||
break;
|
||
}
|
||
}
|
||
if (cpp_17)
|
||
res = "-std=c++17";
|
||
else if (cpp_11)
|
||
res = "-std=c++11";
|
||
RemoteFile cppFlag = new RemoteFile(scriptDirectory, "current_ccp_version");
|
||
writeToFile(res, cppFlag);
|
||
return res;
|
||
}
|
||
public String compileModules(RemoteFile modulesDirectory) throws Exception {
|
||
if (!compileModule(modulesDirectory, "launcher")) {
|
||
return "Не удалось собрать модуль [launcher]";
|
||
}
|
||
if (!compileModule(modulesDirectory, "starter")) {
|
||
return "Не удалось собрать модуль [starter]";
|
||
}
|
||
if (!compileModule(modulesDirectory, "planner")) {
|
||
return "Не удалось собрать модуль [planner]";
|
||
}
|
||
return "";
|
||
}
|
||
//--
|
||
public void tryRM(RemoteFile file) throws Exception {
|
||
if (Exists(file))
|
||
sftpChannel.rm(file.full_name);
|
||
}
|
||
//с проверкой.
|
||
public boolean tryGetSingleFileWithMaxSize(RemoteFile src, File dst, int maxSize) throws Exception {
|
||
if (Exists(src)) {
|
||
if ((maxSize == 0) || (getFileKBSize(src.full_name) <= maxSize)) {
|
||
getSingleFile(src.full_name, dst.getAbsolutePath());
|
||
return true;
|
||
} else {
|
||
Utils.WriteToFile(dst, "Размер файла превышает " + maxSize + " KB.\n" + "Файл не загружен. Его можно просмотреть на машине по адресу\n" + Utils.Brackets(src.full_name));
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
//--
|
||
public void SynchronizeProjectSubDirsR(db_project_info project, File local_dir, RemoteFile remote_dir, boolean data) throws Exception {
|
||
// ShowMessage2("синхронизация: " + local_dir.getName());
|
||
Vector<File> local_subdirs = project.getSubdirectoriesSimple(local_dir);
|
||
Vector<File> local_files = project.getActiveFilesForSynchronization(local_dir, data);
|
||
//------------------------------------------------------------------------
|
||
LinkedHashMap<String, RemoteFile> remote_subdirs = new LinkedHashMap<>();
|
||
LinkedHashMap<String, RemoteFile> remote_files = new LinkedHashMap<>();
|
||
Vector<ChannelSftp.LsEntry> files = sftpChannel.ls(remote_dir.full_name);
|
||
for (ChannelSftp.LsEntry file : files) {
|
||
if (file.getAttrs().isDir()) {
|
||
if (!file.getFilename().equals(".") && !file.getFilename().equals(".."))
|
||
remote_subdirs.put(file.getFilename(), new RemoteFile(remote_dir.full_name, file.getFilename(), true));
|
||
} else {
|
||
RemoteFile rf = new RemoteFile(remote_dir.full_name, file.getFilename());
|
||
rf.updateTime = RemoteFile.convertUpdateTime(file.getAttrs().getMTime());
|
||
remote_files.put(file.getFilename(), rf);
|
||
}
|
||
}
|
||
for (File lsd : local_subdirs) {
|
||
RemoteFile rsd = null;
|
||
if (!remote_subdirs.containsKey(lsd.getName()))
|
||
sftpChannel.mkdir((rsd = new RemoteFile(remote_dir.full_name, lsd.getName(), true)).full_name);
|
||
else rsd = remote_subdirs.get(lsd.getName());
|
||
SynchronizeProjectSubDirsR(project, lsd, rsd, data);
|
||
}
|
||
for (File lf : local_files) {
|
||
RemoteFile rf = null;
|
||
if (!remote_files.containsKey(lf.getName())) {
|
||
rf = new RemoteFile(remote_dir.full_name, lf.getName());
|
||
// ShowMessage2(lf.getName());
|
||
putSingleFile(lf, rf);
|
||
} else {
|
||
rf = remote_files.get(lf.getName());
|
||
if (lf.lastModified() > rf.updateTime) {
|
||
// ShowMessage2(lf.getName());
|
||
putSingleFile(lf, rf);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//--
|
||
public Vector<RemoteFile> getFilesByExtensions(RemoteFile dir, String... extensions) throws Exception {
|
||
Vector<RemoteFile> res = new Vector<>();
|
||
Vector<ChannelSftp.LsEntry> files = sftpChannel.ls(dir.full_name);
|
||
for (ChannelSftp.LsEntry file : files) {
|
||
String[] data = file.getFilename().split("\\.");
|
||
if (data.length > 1) {
|
||
String file_extension = data[data.length - 1];
|
||
for (String extension : extensions) {
|
||
if (file_extension.equalsIgnoreCase(extension))
|
||
res.add(new RemoteFile(dir.full_name, file.getFilename()));
|
||
}
|
||
}
|
||
}
|
||
return res;
|
||
}
|
||
public void deleteFilesByExtensions(RemoteFile dir, String... extensions) throws Exception {
|
||
Vector<RemoteFile> to_delete = getFilesByExtensions(dir, extensions);
|
||
for (RemoteFile file : to_delete)
|
||
sftpChannel.rm(file.full_name);
|
||
}
|
||
public void Command(String... commands) throws Exception {
|
||
if (commands.length > 0) {
|
||
String command = String.join("\n", commands);
|
||
// UI.Print(DebugPrintLevel.Session, command);
|
||
// UI.Print(DebugPrintLevel.Session, "Creating Exec Channel.");
|
||
execChannel = (ChannelExec) session.openChannel("exec");
|
||
execChannel.setErrStream(System.err);
|
||
execChannel.setCommand(command);
|
||
execChannel.connect();
|
||
BufferedReader in = new BufferedReader(new InputStreamReader(execChannel.getInputStream()));
|
||
String line = null;
|
||
while ((line = in.readLine()) != null) {
|
||
System.out.println(Utils.Brackets(line));
|
||
}
|
||
}
|
||
execChannel.disconnect();
|
||
}
|
||
public void CommandNoWait(String... commands) throws Exception {
|
||
if (commands.length > 0) {
|
||
String command = String.join("\n", commands);
|
||
execChannel = (ChannelExec) session.openChannel("exec");
|
||
execChannel.setErrStream(System.err);
|
||
execChannel.setCommand(command);
|
||
execChannel.connect();
|
||
execChannel.disconnect();
|
||
}
|
||
}
|
||
public void performScriptNoWait(RemoteFile directory, String... commands) throws Exception {
|
||
RemoteFile script_file = new RemoteFile(directory, Constants.script);
|
||
if (Exists(script_file))
|
||
sftpChannel.rm(script_file.full_name);
|
||
//--
|
||
writeToFile("cd " + Utils.DQuotes(directory.full_name) + "\n" + String.join("\n", commands), script_file);
|
||
CommandNoWait(Utils.DQuotes(script_file.full_name));
|
||
}
|
||
}
|