1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2025-10-08 22:51:57 +02:00

Доработка тестов, рефакторинг SFTP

This commit is contained in:
Anton Titovets
2025-10-03 19:19:18 +03:00
parent 92440b69ac
commit 5c4a806313
13 changed files with 770 additions and 409 deletions

View File

@@ -1,12 +1,12 @@
"MAIN ---"
linux-vdso.so.1 (0x00007ffe131f6000)
libssl.so.3 => /lib64/libssl.so.3 (0x00007fda26200000)
libcrypto.so.3 => /lib64/libcrypto.so.3 (0x00007fda25a00000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fda25600000)
libc.so.6 => /lib64/libc.so.6 (0x00007fda25200000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007fda24e00000)
/lib64/ld-linux-x86-64.so.2 (0x00007fda26600000)
libz.so.1 => /lib64/libz.so.1 (0x00007fda24a00000)
linux-vdso.so.1 (0x00007fff486f1000)
libssl.so.3 => /lib64/libssl.so.3 (0x00007bad3de00000)
libcrypto.so.3 => /lib64/libcrypto.so.3 (0x00007bad3d600000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007bad3d200000)
libc.so.6 => /lib64/libc.so.6 (0x00007bad3ce00000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007bad3ca00000)
/lib64/ld-linux-x86-64.so.2 (0x00007bad3e200000)
libz.so.1 => /lib64/libz.so.1 (0x00007bad3c600000)
GLIBC_2.2.5
GLIBC_2.3
GLIBC_2.3.4

View File

@@ -1,15 +1,12 @@
mod methods;
mod ssh_settings;
mod sftp;
mod sftp_methods;
mod ssh_methods;
use std::io::Read;
use std::path::Path;
use addin1c::{name, Variant};
use serde_json::json;
use crate::core::getset;
use ssh2::{MethodType, Session, Sftp};
use crate::component::ssh_settings::{SshAuthTypes, SshConf};
use common_tcp::tcp_establish::create_tcp_connection;
use ssh2::{Session, Sftp};
use crate::component::ssh_settings::SshConf;
// МЕТОДЫ КОМПОНЕНТЫ -------------------------------------------------------------------------------
@@ -28,7 +25,9 @@ pub const METHODS: &[&[u16]] = &[
name!("UploadFile"),
name!("UploadData"),
name!("RemoveFile"),
name!("IsSFTP")
name!("IsSFTP"),
name!("DownloadToFile"),
name!("DownloadToBuffer"),
];
// Число параметров функций компоненты
@@ -48,6 +47,8 @@ pub fn get_params_amount(num: usize) -> usize {
11 => 2,
12 => 1,
13 => 0,
14 => 2,
15 => 1,
_ => 0,
}
}
@@ -118,6 +119,22 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn
},
13 => {
Box::new(obj.sftp.is_some())
},
14 => {
let path = params[0].get_string().unwrap_or("".to_string());
let filepath = params[1].get_string().unwrap_or("".to_string());
Box::new(obj.download_to_file(&path, &filepath))
},
15 => {
let path = params[0].get_string().unwrap_or("".to_string());
match obj.download_to_vec(&path) {
Ok(v) => Box::new(v),
Err(e) => Box::new(e)
}
}
_ => Box::new(false), // Неверный номер команды
}
@@ -138,7 +155,7 @@ pub struct AddIn {
}
impl AddIn {
/// Создает новый объект
pub fn new() -> Self {
AddIn {
inner: None,
@@ -147,285 +164,6 @@ impl AddIn {
}
}
pub fn set_settings(&mut self, settings: String) -> String{
let mut conf = self.conf.take().unwrap_or_else(|| SshConf::new());
match conf.set_settings(settings) {
Ok(_) => {
self.conf = Some(conf);
json!({"result": true}).to_string()
},
Err(e) => format_json_error(&e),
}
}
pub fn set_proxy(&mut self, proxy: String) -> String{
let mut conf = self.conf.take().unwrap_or_else(|| SshConf::new());
match conf.set_proxy(proxy) {
Ok(_) => {
self.conf = Some(conf);
json!({"result": true}).to_string()
},
Err(e) => format_json_error(&e),
}
}
pub fn initialize(&mut self) -> String {
let conf_data = match &self.conf{
Some(conf_data) => conf_data,
None => return format_json_error("No configuration found")
};
let settings = match &conf_data.set {
Some(settings) => settings,
None => return format_json_error("No settings found")
};
let username= &settings.username;
let password = settings.password.as_deref().unwrap_or("");
let passphrase = &settings.passphrase;
let key_path = &settings.key_path;
let pub_path = &settings.pub_path;
let proxy = &conf_data.proxy;
let tcp = match create_tcp_connection(&settings.host, settings.port, proxy){
Ok(tcp) => tcp,
Err(e) => return format_json_error(format!("TCP error: {}", e.to_string()).as_str())
};
ssh2::init();
let mut identities = vec![];
let methods;
let banner;
let kex;
let mut sess = match Session::new(){
Ok(sess) => {
methods = sess.auth_methods(username).unwrap_or("").to_string();
banner = sess.banner().unwrap_or("").to_string();
kex = sess.methods(MethodType::Kex).unwrap_or("").to_string();
sess
},
Err(e) => return format_json_error(format!("Session error: {}", e.to_string()).as_str())
};
match sess.agent(){
Ok(agent) => {
match agent.identities(){
Ok(idents) => {
for ident in idents{
identities.push(ident.comment().to_string());
}
}
Err(e) => identities.push(e.to_string())
}
}
Err(e) => identities.push(e.to_string())
};
sess.set_tcp_stream(tcp);
if let Err(e) = sess.handshake() {
return json!({
"result": false,
"error": format!("Handshake error: {}", e.to_string()),
"identities": identities,
"methods": methods,
"banner": banner,
"kex_methods": kex
}).to_string();
};
let auth_success = match settings.auth_type {
SshAuthTypes::Password => sess.userauth_password(username, password),
SshAuthTypes::Agent => sess.userauth_agent(username),
SshAuthTypes::PrivateKey => {
let path = match key_path{
Some(key_path) => key_path.as_ref(),
None => return format_json_error("No key path provided with PK auth type")
};
let pub_path = match pub_path{
Some(pub_path) => Some(Path::new(pub_path)),
None => None
};
sess.userauth_pubkey_file(username, pub_path, path, passphrase.as_deref())
},
};
if let Err(e) = auth_success{
return format_json_error(format!("Auth error: {}", e.to_string()).as_str());
};
if !sess.authenticated(){
return format_json_error("Authentication failed with no errors");
}
self.inner = Some(sess);
json!({"result": true}).to_string()
}
pub fn execute(&self, command: &str) -> String {
let session = match &self.inner{
Some(sess) => sess,
None => return format_json_error("No session"),
};
let mut channel = match session.channel_session(){
Ok(channel) => channel,
Err(e) => return format_json_error(&e.to_string())
};
if let Err(e) = channel.exec(command){
return format_json_error(&e.to_string());
};
let mut stdout = String::new();
if let Err(e) = channel.read_to_string(&mut stdout).map_err(|e| e.to_string()){
stdout = e.to_string();
};
let mut stderr = String::new();
if let Err(e) = channel.stderr().read_to_string(&mut stderr).map_err(|e| e.to_string()){
stderr = e.to_string();
};
let exit_code = match channel.wait_close(){
Ok(_) => channel.exit_status().map_err(|e| e.to_string()),
Err(e) => Err(e.to_string())
};
let code = match exit_code{
Ok(code) => code.to_string(),
Err(e) => e.to_string()
};
json!({"result": true, "exit_code": code, "stdout": stdout, "stderr": stderr}).to_string()
}
pub fn get_configuration(&mut self) -> String{
let conf = match &self.conf{
Some(conf) => conf,
None => return format_json_error("No configuration found")
};
json!({"result": true, "conf": conf}).to_string()
}
// SFTP
pub fn make_sftp(&mut self) -> String {
match &self.inner{
Some(sess) => {
self.sftp = match sftp::make_sftp(sess){
Ok(sftp) => Some(sftp),
Err(e) => return e.to_string()
};
json!({"result": true}).to_string()
},
None => json!({"result": false, "error": "Init SSH connection first"}).to_string()
}
}
pub fn make_directory(&mut self, path: &str, mode: i32) -> String {
match &self.sftp{
Some(s) => {
match sftp::make_directory(s, path, mode){
Ok(_) => json!({"result": true}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn remove_directory(&mut self, path: &str) -> String {
match &self.sftp{
Some(s) => {
match sftp::remove_directory(s, path){
Ok(_) => json!({"result": true}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn list_directory(&mut self, path: &str) -> String {
match &self.sftp{
Some(s) => {
match sftp::list_directory(s, path){
Ok(d) => json!({"result": true, "data": d}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn upload_file(&mut self, file: &str, path: &str) -> String {
match &self.sftp{
Some(s) => {
match sftp::upload_file(s, file, path){
Ok(d) => json!({"result": true, "bytes": d}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn upload_data(&mut self, data: &[u8], path: &str) -> String {
match &self.sftp{
Some(s) => {
match sftp::upload_data(s, data, path){
Ok(d) => json!({"result": true, "bytes": d}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn delete_file(&mut self, path: &str) -> String {
match &self.sftp{
Some(s) => {
match sftp::remove_file(s, path){
Ok(_) => json!({"result": true}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn disconnect(&mut self) -> String{
if let Some(_conn) = self.inner.take() {
self.sftp.take();
json!({"result": true}).to_string()
} else {
json!({"result": false, "error": "No session"}).to_string()
}
}
pub fn get_field_ptr(&self, index: usize) -> *const dyn getset::ValueType {
match index {
_ => panic!("Index out of bounds"),
@@ -442,7 +180,6 @@ pub fn format_json_error(error: &str) -> String {
// УНИЧТОЖЕНИЕ ОБЪЕКТА -----------------------------------------------------------------------------
// Обработка удаления объекта
impl Drop for AddIn {
fn drop(&mut self) {}
}

View File

@@ -1,110 +0,0 @@
use std::io::{BufReader, Cursor, Read, copy};
use serde_json::{json, Value};
use ssh2::{Session, Sftp};
pub fn make_sftp(session: &Session) -> Result<Sftp, String> {
session.sftp().map_err( |err| err.to_string() )
}
pub fn make_directory(sftp: &Sftp, path: &str, mode: i32) -> Result<(), String> {
let mode_oct = oct(mode)?;
sftp.mkdir(path.as_ref(), mode_oct).map_err(|err| err.to_string())
}
pub fn remove_directory(sftp: &Sftp, path: &str) -> Result<(), String> {
sftp.rmdir(path.as_ref()).map_err(|err| err.to_string())
}
pub fn list_directory(sftp: &Sftp, path: &str) -> Result<Vec<Value>, String> {
let mut data = vec![];
match sftp.readdir(path) {
Ok(contents) => {
for item in contents {
let object_pb = item.0;
let object_path = object_pb.to_str().unwrap_or("").to_string();
let object_info = &item.1;
let object_perm = object_info.perm.unwrap_or(0);
let object_filename = object_pb
.file_name()
.unwrap_or("".as_ref())
.to_str()
.unwrap_or("")
.to_string();
let object_ext = object_pb
.extension()
.unwrap_or("".as_ref())
.to_str()
.unwrap_or("")
.to_string();
data.push(json!({
"uid": object_info.uid,
"gid": object_info.gid,
"is_directory": is_directory(object_perm),
"is_symlink": object_pb.is_symlink(),
"modified": object_info.mtime,
"accessed": object_info.atime,
"name": object_filename,
"size": object_info.size,
"path": object_path,
"permissions": format!("{:o}", object_perm),
"extension": object_ext,
}));
}
Ok(data)
},
Err(err) => Err(err.to_string()),
}
}
pub fn upload_data(sftp: &Sftp, data: &[u8], path: &str) -> Result<u64, String> {
let mut cursor = Cursor::new(data);
upload_from_reader(sftp, path, &mut cursor)
}
pub fn upload_file(sftp: &Sftp, filepath: &str, path: &str) -> Result<u64, String> {
let file = match std::fs::File::open(filepath) {
Ok(f) => f,
Err(e) => return Err(format!("File error: {}", e))
};
let mut buf_reader = BufReader::new(file);
upload_from_reader(sftp, path, &mut buf_reader)
}
pub fn remove_file(sftp: &Sftp, path: &str) -> Result<(), String> {
sftp.unlink(path.as_ref()).map_err(|err| err.to_string())
}
fn is_directory(mode: u32) -> bool {
const S_IFMT: u32 = 0o170000; // маска типа файла
const S_IFDIR: u32 = 0o040000; // биты для каталога
(mode & S_IFMT) == S_IFDIR
}
fn oct(o: i32) -> Result<i32, String> {
i32::from_str_radix(&o.to_string(), 8).map_err(|err| err.to_string())
}
fn upload_from_reader<R: Read>(sftp: &Sftp, path: &str, reader: &mut R) -> Result<u64, String> {
let mut remote = match sftp.create(path.as_ref()) {
Ok(remote) => remote,
Err(e) => return Err(format!("File access error: {}", e))
};
match copy(reader, &mut remote) {
Ok(b) => Ok(b),
Err(e) => Err(format!("Upload error: {}", &e.to_string()))
}
}

View File

@@ -0,0 +1,233 @@
use std::io::{BufReader, Cursor, Read, copy, Write};
use std::path::Path;
use serde_json::{json};
use ssh2::{Sftp};
use crate::component::{AddIn};
use crate::component::format_json_error;
impl AddIn{
pub fn make_sftp(&mut self) -> String {
match &self.inner{
Some(sess) => {
let result = sess.sftp().map_err( |err| err.to_string() );
self.sftp = match result{
Ok(sftp) => Some(sftp),
Err(e) => return e.to_string()
};
json!({"result": true}).to_string()
},
None => json!({"result": false, "error": "Init SSH connection first"}).to_string()
}
}
pub fn make_directory(&mut self, path: &str, mode: i32) -> String {
match &self.sftp{
Some(s) => {
let mode_oct = match oct(mode){
Ok(mode) => mode,
Err(e) => return format_json_error(&e.to_string())
};
let result = s.mkdir(path.as_ref(), mode_oct).map_err(|err| err.to_string());
match result{
Ok(_) => json!({"result": true}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn remove_directory(&mut self, path: &str) -> String {
match &self.sftp{
Some(s) => {
match s.rmdir(path.as_ref()) {
Ok(_) => json!({"result": true}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn list_directory(&mut self, path: &str) -> String {
let sftp = match &self.sftp {
Some(s) => s,
None => return json!({"result": false, "error": "Init SFTP first"}).to_string()
};
let mut data = vec![];
match sftp.readdir(path) {
Ok(contents) => {
for item in contents {
let object_pb = item.0;
let object_path = object_pb.to_str().unwrap_or("").to_string();
let object_info = &item.1;
let object_perm = object_info.perm.unwrap_or(0);
let object_filename = object_pb
.file_name()
.unwrap_or("".as_ref())
.to_str()
.unwrap_or("")
.to_string();
let object_ext = object_pb
.extension()
.unwrap_or("".as_ref())
.to_str()
.unwrap_or("")
.to_string();
data.push(json!({
"uid": object_info.uid,
"gid": object_info.gid,
"is_directory": is_directory(object_perm),
"is_symlink": object_pb.is_symlink(),
"modified": object_info.mtime,
"accessed": object_info.atime,
"name": object_filename,
"size": object_info.size,
"path": object_path,
"permissions": format!("{:o}", object_perm),
"extension": object_ext,
}));
}
json!({"result": true, "data": data}).to_string()
},
Err(err) => format_json_error(&err.to_string()),
}
}
pub fn upload_file(&mut self, file: &str, path: &str) -> String {
match &self.sftp{
Some(s) => {
let file = match std::fs::File::open(file) {
Ok(f) => f,
Err(e) => return format_json_error(format!("File error: {}", e).as_str())
};
let mut buf_reader = BufReader::new(file);
let result = upload_from_reader(s, path, &mut buf_reader);
match result{
Ok(d) => json!({"result": true, "bytes": d}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn upload_data(&mut self, data: &[u8], path: &str) -> String {
match &self.sftp{
Some(s) => {
let mut cursor = Cursor::new(data);
let result = upload_from_reader(s, path, &mut cursor);
match result{
Ok(d) => json!({"result": true, "bytes": d}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn delete_file(&mut self, path: &str) -> String {
match &self.sftp{
Some(s) => {
match s.unlink(path.as_ref()){
Ok(_) => json!({"result": true}).to_string(),
Err(e) => format_json_error(&e.to_string())
}
},
None => json!({"result": false, "error": "Init SFTP first"}).to_string()
}
}
pub fn download_to_file(&mut self, path: &str, file_path: &str) -> String {
let sftp = match &self.sftp {
Some(s) => s,
None => return json!({"result": false, "error": "Init SFTP first"}).to_string()
};
let mut file = match std::fs::File::create(file_path){
Ok(f) => f,
Err(e) => return format_json_error(format!("File error: {}", e).as_str())
};
match download_to_writer(sftp, path, &mut file){
Ok(b) => json!({"result": true, "bytes": b, "filepath": file_path}).to_string(),
Err(e) => format_json_error(&e)
}
}
pub fn download_to_vec(&mut self, path: &str) -> Result<Vec<u8>, String> {
match &self.sftp{
Some(s) => {
let mut buffer = Vec::new();
match download_to_writer(s, path, &mut buffer){
Ok(_) => Ok(buffer),
Err(e) => Err(format_json_error(&e))
}
},
None => Err(json!({"result": false, "error": "Init SFTP first"}).to_string())
}
}
}
fn is_directory(mode: u32) -> bool {
const S_IFMT: u32 = 0o170000;
const S_IFDIR: u32 = 0o040000;
(mode & S_IFMT) == S_IFDIR
}
fn oct(o: i32) -> Result<i32, String> {
i32::from_str_radix(&o.to_string(), 8).map_err(|err| err.to_string())
}
fn upload_from_reader<R: Read>(sftp: &Sftp, path: &str, reader: &mut R) -> Result<u64, String> {
let mut remote = match sftp.create(path.as_ref()) {
Ok(remote) => remote,
Err(e) => return Err(format!("Remote file access error: {}", e))
};
match copy(reader, &mut remote) {
Ok(b) => Ok(b),
Err(e) => Err(format!("Upload error: {}", &e.to_string()))
}
}
fn download_to_writer<W: Write>(sftp: &Sftp, path: &str, writer: &mut W, ) -> Result<u64, String> {
let mut remote = match sftp.open(Path::new(path)) {
Ok(remote) => remote,
Err(e) => return Err(format!("Remote file access error: {}", e))
};
match copy(&mut remote, writer) {
Ok(b) => Ok(b),
Err(e) => Err(format!("Upload error: {}", &e.to_string()))
}
}

View File

@@ -0,0 +1,201 @@
use std::io::Read;
use std::path::Path;
use common_tcp::tcp_establish::create_tcp_connection;
use serde_json::json;
use ssh2::{MethodType, Session};
use crate::component::{format_json_error, AddIn};
use crate::component::ssh_settings::{SshAuthTypes, SshConf};
impl AddIn{
pub fn set_settings(&mut self, settings: String) -> String{
let mut conf = self.conf.take().unwrap_or_else(|| SshConf::new());
match conf.set_settings(settings) {
Ok(_) => {
self.conf = Some(conf);
json!({"result": true}).to_string()
},
Err(e) => format_json_error(&e),
}
}
pub fn set_proxy(&mut self, proxy: String) -> String{
let mut conf = self.conf.take().unwrap_or_else(|| SshConf::new());
match conf.set_proxy(proxy) {
Ok(_) => {
self.conf = Some(conf);
json!({"result": true}).to_string()
},
Err(e) => format_json_error(&e),
}
}
pub fn initialize(&mut self) -> String {
let conf_data = match &self.conf{
Some(conf_data) => conf_data,
None => return format_json_error("No configuration found")
};
let settings = match &conf_data.set {
Some(settings) => settings,
None => return format_json_error("No settings found")
};
let username= &settings.username;
let password = settings.password.as_deref().unwrap_or("");
let passphrase = &settings.passphrase;
let key_path = &settings.key_path;
let pub_path = &settings.pub_path;
let proxy = &conf_data.proxy;
let tcp = match create_tcp_connection(&settings.host, settings.port, proxy){
Ok(tcp) => tcp,
Err(e) => return format_json_error(format!("TCP error: {}", e.to_string()).as_str())
};
ssh2::init();
let mut identities = vec![];
let methods;
let banner;
let kex;
let mut sess = match Session::new(){
Ok(sess) => {
methods = sess.auth_methods(username).unwrap_or("").to_string();
banner = sess.banner().unwrap_or("").to_string();
kex = sess.methods(MethodType::Kex).unwrap_or("").to_string();
sess
},
Err(e) => return format_json_error(format!("Session error: {}", e.to_string()).as_str())
};
match sess.agent(){
Ok(agent) => {
match agent.identities(){
Ok(idents) => {
for ident in idents{
identities.push(ident.comment().to_string());
}
}
Err(e) => identities.push(e.to_string())
}
}
Err(e) => identities.push(e.to_string())
};
sess.set_tcp_stream(tcp);
if let Err(e) = sess.handshake() {
return json!({
"result": false,
"error": format!("Handshake error: {}", e.to_string()),
"identities": identities,
"methods": methods,
"banner": banner,
"kex_methods": kex
}).to_string();
};
let auth_success = match settings.auth_type {
SshAuthTypes::Password => sess.userauth_password(username, password),
SshAuthTypes::Agent => sess.userauth_agent(username),
SshAuthTypes::PrivateKey => {
let path = match key_path{
Some(key_path) => key_path.as_ref(),
None => return format_json_error("No key path provided with PK auth type")
};
let pub_path = match pub_path{
Some(pub_path) => Some(Path::new(pub_path)),
None => None
};
sess.userauth_pubkey_file(username, pub_path, path, passphrase.as_deref())
},
};
if let Err(e) = auth_success{
return format_json_error(format!("Auth error: {}", e.to_string()).as_str());
};
if !sess.authenticated(){
return format_json_error("Authentication failed with no errors");
}
self.inner = Some(sess);
json!({"result": true}).to_string()
}
pub fn execute(&self, command: &str) -> String {
let session = match &self.inner{
Some(sess) => sess,
None => return format_json_error("No session"),
};
let mut channel = match session.channel_session(){
Ok(channel) => channel,
Err(e) => return format_json_error(&e.to_string())
};
if let Err(e) = channel.exec(command){
return format_json_error(&e.to_string());
};
let mut stdout = String::new();
if let Err(e) = channel.read_to_string(&mut stdout).map_err(|e| e.to_string()){
stdout = e.to_string();
};
let mut stderr = String::new();
if let Err(e) = channel.stderr().read_to_string(&mut stderr).map_err(|e| e.to_string()){
stderr = e.to_string();
};
let exit_code = match channel.wait_close(){
Ok(_) => channel.exit_status().map_err(|e| e.to_string()),
Err(e) => Err(e.to_string())
};
let code = match exit_code{
Ok(code) => code.to_string(),
Err(e) => e.to_string()
};
json!({"result": true, "exit_code": code, "stdout": stdout, "stderr": stderr}).to_string()
}
pub fn get_configuration(&mut self) -> String{
let conf = match &self.conf{
Some(conf) => conf,
None => return format_json_error("No configuration found")
};
json!({"result": true, "conf": conf}).to_string()
}
pub fn disconnect(&mut self) -> String{
if let Some(_conn) = self.inner.take() {
self.sftp.take();
json!({"result": true}).to_string()
} else {
json!({"result": false, "error": "No session"}).to_string()
}
}
}

Binary file not shown.

Binary file not shown.

View File

@@ -448,6 +448,103 @@
КонецФункции
// Сохранить файл
// Сохраняет файл с сервера по указанному пути
//
// Параметры:
// Соединение - Произвольный - Существующее соединение или конфигурация соединения - conn
// Путь - Строка - Путь файла на сервере - path
// ИмяФайла - Строка - Путь для сохранения файла на диске - file
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение - Результат обработки
Функция СохранитьФайл(Знач Соединение, Знач Путь, Знач ИмяФайла) Экспорт
ЗакрыватьСоединение = ПроверитьСоздатьСоединение(Соединение);
Если Не ЭтоКоннектор(Соединение) Тогда
Возврат Соединение;
Иначе
OPI_ПреобразованиеТипов.ПолучитьСтроку(Путь);
OPI_ПреобразованиеТипов.ПолучитьСтроку(ИмяФайла);
OPI_Инструменты.ВернутьУправляющиеПоследовательности(ИмяФайла);
Результат = Соединение.DownloadToFile(Путь, ИмяФайла);
Результат = OPI_Инструменты.JsonВСтруктуру(Результат);
КонецЕсли;
Если ЗакрыватьСоединение Тогда
Результат.Вставить("close_connection", ЗакрытьСоединение(Соединение));
КонецЕсли;
Возврат Результат;
КонецФункции
// Получить данные файла !NOCLI
// Получает файл с сервера как двоичные данные
//
// Параметры:
// Соединение - Произвольный - Существующее соединение или конфигурация соединения - conn
// Путь - Строка - Путь файла на сервере - path
//
// Возвращаемое значение:
// Соответствие Из КлючИЗначение, ДвоичныеДанные - Данные файла или информация об ошибке
Функция ПолучитьДанныеФайла(Знач Соединение, Знач Путь) Экспорт
ЗакрыватьСоединение = ПроверитьСоздатьСоединение(Соединение);
Если Не ЭтоКоннектор(Соединение) Тогда
Возврат Соединение;
Иначе
OPI_ПреобразованиеТипов.ПолучитьСтроку(Путь);
Если OPI_Компоненты.ТребуетсяПередачаЧерезФайл() Тогда
// BSLLS:MissingTemporaryFileDeletion-off
//@skip-check missing-temporary-file-deletion
ИВФ = ПолучитьИмяВременногоФайла();
// BSLLS:MissingTemporaryFileDeletion-on
Результат = Соединение.DownloadToFile(Путь, ИВФ);
Результат = OPI_Инструменты.JsonВСтруктуру(Результат);
Если Результат["result"] Тогда
Данные = Новый ДвоичныеДанные(ИВФ);
OPI_Инструменты.УдалитьФайлВПопытке(ИВФ, "Не удалось удалить временный файл после загрузки");
Возврат Данные;
КонецЕсли;
Иначе
Данные = Соединение.DownloadToBuffer(Путь);
Если ТипЗнч(Данные) = Тип("Строка") Тогда
Результат = OPI_Инструменты.JsonВСтруктуру(Данные);
Иначе
Возврат Данные;
КонецЕсли;
КонецЕсли;
КонецЕсли;
Если ЗакрыватьСоединение Тогда
Результат.Вставить("close_connection", ЗакрытьСоединение(Соединение));
КонецЕсли;
Возврат Результат;
КонецФункции
#КонецОбласти
#КонецОбласти

View File

@@ -11756,6 +11756,41 @@
КонецФункции
Функция Проверка_SFTP_СохранитьФайл(Знач Результат, Знач Вариант, РазмерРезультата = "", РазмерПроверки = "")
Если СтрНайти(Вариант, "Размер файла") > 0 Тогда
ОжидаетЧто(Результат).Равно(РазмерРезультата);
ОжидаетЧто(Результат).Равно(РазмерПроверки);
Иначе
ОжидаетЧто(Результат["result"]).Равно(Истина);
КонецЕсли;
Если СтрНайти(Вариант, "HTTP") Тогда
OPI_Инструменты.Пауза(2);
КонецЕсли;
Возврат Результат;
КонецФункции
Функция Проверка_SFTP_ПолучитьДанныеФайла(Знач Результат, Знач Вариант, РазмерПроверки = "")
Если СтрНайти(Вариант, "Размер файла") > 0 Тогда
ОжидаетЧто(Результат).Равно(РазмерПроверки);
ИначеЕсли СтрНайти(Вариант, "Размер") > 0 Тогда
ОжидаетЧто(Результат["result"]).Равно(Истина);
Иначе
ОжидаетЧто(Результат).ИмеетТип("ДвоичныеДанные");
КонецЕсли;
Если СтрНайти(Вариант, "HTTP") Тогда
OPI_Инструменты.Пауза(2);
КонецЕсли;
Возврат Результат;
КонецФункции
#КонецОбласти
#Область ReportPortal

View File

@@ -3020,6 +3020,8 @@
Для Каждого ПараметрыТеста Из МассивВариантов Цикл
SFTP_ЗагрузитьФайл(ПараметрыТеста);
SFTP_ПолучитьДанныеФайла(ПараметрыТеста);
SFTP_СохранитьФайл(ПараметрыТеста);
SFTP_УдалитьФайл(ПараметрыТеста);
КонецЦикла;
@@ -22376,7 +22378,7 @@
Результат = OPI_FTP.СохранитьФайл(Соединение, Путь, ИмяФайла);
Если Не Результат["result"] Тогда
Обработать(РазмерФайла, "FTP", "СохранитьФайл", "Множественный, " + Постфикс);
Обработать(Результат, "FTP", "СохранитьФайл", "Множественный, " + Постфикс);
КонецЕсли;
КонецЦикла;
@@ -22453,7 +22455,7 @@
Результат = OPI_FTP.ПолучитьДанныеФайла(Соединение, Путь);
Если Не ТипЗнч(Результат) = Тип("ДвоичныеДанные") Тогда
Обработать(Размер, "FTP", "ПолучитьДанныеФайла", "Множественный, " + Постфикс);
Обработать(Результат, "FTP", "ПолучитьДанныеФайла", "Множественный, " + Постфикс);
КонецЕсли;
КонецЦикла;
@@ -24000,6 +24002,172 @@
КонецПроцедуры
Процедура SFTP_СохранитьФайл(ПараметрыФункции)
Постфикс = ПараметрыФункции["Postfix"]; // SKIP
Хост = ПараметрыФункции["SSH_Host"];
Порт = ПараметрыФункции["SSH_Port"];
ИспользоватьПрокси = Истина;
НастройкиПрокси = Неопределено;
ВидАвторизации = "По логину и паролю";
ИспользоватьПрокси = ПараметрыФункции["Proxy"]; // SKIP
ВидАвторизации = ПараметрыФункции["AuthType"]; // SKIP
Если ВидАвторизации = "По логину и паролю" Тогда
Логин = ПараметрыФункции["SSH_User"];
Пароль = ПараметрыФункции["SSH_Password"];
НастройкиSSH = OPI_SFTP.ПолучитьНастройкиЛогинПароль(Хост, Порт, Логин, Пароль);
ИначеЕсли ВидАвторизации = "По ключу" Тогда
Логин = ПараметрыФункции["SSH_User"];
ПриватныйКлюч = "./ssh_key";
ПубличныйКлюч = "./ssh_key.pub";
ПриватныйКлюч = ПараметрыФункции["SSH_Key"]; // SKIP
ПубличныйКлюч = ПараметрыФункции["SSH_Pub"]; // SKIP
НастройкиSSH = OPI_SFTP.ПолучитьНастройкиПриватныйКлюч(Хост, Порт, Логин, ПриватныйКлюч, ПубличныйКлюч);
Иначе
Логин = ПараметрыФункции["SSH_User"];
НастройкиSSH = OPI_SFTP.ПолучитьНастройкиЧерезАгента(Хост, Порт, Логин);
КонецЕсли;
Если ИспользоватьПрокси Тогда
ТипПрокси = ПараметрыФункции["Proxy_Type"]; // http, socks5, socks4
АдресПрокси = ПараметрыФункции["Proxy_IP"];
ПортПрокси = ПараметрыФункции["Proxy_Port"];
ЛогинПрокси = ПараметрыФункции["Proxy_User"];
ПарольПрокси = ПараметрыФункции["Proxy_Password"];
НастройкиПрокси = OPI_SFTP.ПолучитьНастройкиПрокси(АдресПрокси, ПортПрокси, ТипПрокси, ЛогинПрокси, ПарольПрокси);
КонецЕсли;
Соединение = OPI_SFTP.ОткрытьСоединение(НастройкиSSH, НастройкиПрокси);
Если OPI_SFTP.ЭтоКоннектор(Соединение) Тогда
Путь = "pic_from_disk.png";
ИмяФайла = ПолучитьИмяВременногоФайла("bin");
Результат = OPI_SFTP.СохранитьФайл(Соединение, Путь, ИмяФайла);
Иначе
Результат = Соединение; // Ошибка соединения
КонецЕсли;
// END
Обработать(Результат, "SSH", "СохранитьФайл", Постфикс);
Путь = "files_folder/pic_from_binary.png";
Для Н = 1 По 20 Цикл
Результат = OPI_SFTP.СохранитьФайл(Соединение, Путь, ИмяФайла);
Если Не Результат["result"] Тогда
Обработать(Результат, "FTP", "СохранитьФайл", "Множественный, " + Постфикс);
КонецЕсли;
КонецЦикла;
OPI_Инструменты.УдалитьФайлВПопытке(ИмяФайла, "Не удалось удалить временный файл после теста!");
КонецПроцедуры
Процедура SFTP_ПолучитьДанныеФайла(ПараметрыФункции)
Постфикс = ПараметрыФункции["Postfix"]; // SKIP
Хост = ПараметрыФункции["SSH_Host"];
Порт = ПараметрыФункции["SSH_Port"];
ИспользоватьПрокси = Истина;
НастройкиПрокси = Неопределено;
ВидАвторизации = "По логину и паролю";
ИспользоватьПрокси = ПараметрыФункции["Proxy"]; // SKIP
ВидАвторизации = ПараметрыФункции["AuthType"]; // SKIP
Если ВидАвторизации = "По логину и паролю" Тогда
Логин = ПараметрыФункции["SSH_User"];
Пароль = ПараметрыФункции["SSH_Password"];
НастройкиSSH = OPI_SFTP.ПолучитьНастройкиЛогинПароль(Хост, Порт, Логин, Пароль);
ИначеЕсли ВидАвторизации = "По ключу" Тогда
Логин = ПараметрыФункции["SSH_User"];
ПриватныйКлюч = "./ssh_key";
ПубличныйКлюч = "./ssh_key.pub";
ПриватныйКлюч = ПараметрыФункции["SSH_Key"]; // SKIP
ПубличныйКлюч = ПараметрыФункции["SSH_Pub"]; // SKIP
НастройкиSSH = OPI_SFTP.ПолучитьНастройкиПриватныйКлюч(Хост, Порт, Логин, ПриватныйКлюч, ПубличныйКлюч);
Иначе
Логин = ПараметрыФункции["SSH_User"];
НастройкиSSH = OPI_SFTP.ПолучитьНастройкиЧерезАгента(Хост, Порт, Логин);
КонецЕсли;
Если ИспользоватьПрокси Тогда
ТипПрокси = ПараметрыФункции["Proxy_Type"]; // http, socks5, socks4
АдресПрокси = ПараметрыФункции["Proxy_IP"];
ПортПрокси = ПараметрыФункции["Proxy_Port"];
ЛогинПрокси = ПараметрыФункции["Proxy_User"];
ПарольПрокси = ПараметрыФункции["Proxy_Password"];
НастройкиПрокси = OPI_SFTP.ПолучитьНастройкиПрокси(АдресПрокси, ПортПрокси, ТипПрокси, ЛогинПрокси, ПарольПрокси);
КонецЕсли;
Соединение = OPI_SFTP.ОткрытьСоединение(НастройкиSSH, НастройкиПрокси);
Если OPI_SFTP.ЭтоКоннектор(Соединение) Тогда
Путь = "pic_from_disk.png";
Результат = OPI_FTP.ПолучитьДанныеФайла(Соединение, Путь);
Иначе
Результат = Соединение; // Ошибка соединения
КонецЕсли;
// END
Обработать(Результат, "SFTP", "ПолучитьДанныеФайла", Постфикс);
Путь = "files_folder/pic_from_binary.png";
Для Н = 1 По 20 Цикл
Результат = OPI_SFTP.ПолучитьДанныеФайла(Соединение, Путь);
Если Не ТипЗнч(Результат) = Тип("ДвоичныеДанные") Тогда
Обработать(Результат, "SFTP", "ПолучитьДанныеФайла", "Множественный, " + Постфикс);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
#КонецОбласти
#КонецОбласти