Files
VisualSapfor/src/TestingSystem/DVM/UserConnection.java
02090095 4e503d3b9b v++
Лимит ошибок связи 10
2024-04-08 01:30:46 +03:00

429 lines
18 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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));
}
}