1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2025-07-13 01:30:17 +02:00

Update opi_tcp.rs

This commit is contained in:
Anton Titovets
2024-12-07 18:42:46 +03:00
parent cdf64b5017
commit d6a74c2ab8

View File

@ -1,12 +1,14 @@
use addin1c::{name, ParamValue, RawAddin, Tm, Variant}; use addin1c::{name, ParamValue, RawAddin, Tm, Variant};
use std::io::{Read, Write}; use std::io::{self, Read, Write};
use std::net::{TcpStream, ToSocketAddrs}; use std::net::{TcpStream, ToSocketAddrs};
use std::time::Duration; use std::time::Duration;
use native_tls::{TlsConnector, TlsStream};
// Свойства объекта // Свойства объекта
const PROPS: &[&[u16]] = &[ const PROPS: &[&[u16]] = &[
name!("Адрес"), name!("Адрес"),
name!("Порт") name!("Порт"),
name!("SSL")
]; ];
@ -19,6 +21,7 @@ const METHODS: &[&[u16]] = &[
pub struct OpiTcp { pub struct OpiTcp {
address: String, address: String,
port: i32, port: i32,
ssl: bool
} }
// Конструктор // Конструктор
@ -27,6 +30,7 @@ impl OpiTcp {
OpiTcp { OpiTcp {
address: String::from(""), address: String::from(""),
port: 0, port: 0,
ssl: false
} }
} }
} }
@ -62,6 +66,7 @@ impl RawAddin for OpiTcp {
return val.set_str(s.as_slice()); return val.set_str(s.as_slice());
} }
1 => val.set_i32(self.port), 1 => val.set_i32(self.port),
2 => val.set_bool(self.ssl),
_ => return false, _ => return false,
}; };
true true
@ -84,6 +89,13 @@ impl RawAddin for OpiTcp {
} }
_ => false, _ => false,
}, },
2 => match val {
ParamValue::Bool(x) =>{
self.ssl = *x;
true
}
_ => false,
}
_ => false, _ => false,
} }
} }
@ -96,6 +108,7 @@ impl RawAddin for OpiTcp {
match num { match num {
0 => true, 0 => true,
1 => true, 1 => true,
2 => true,
_ => false, _ => false,
} }
} }
@ -131,7 +144,6 @@ impl RawAddin for OpiTcp {
fn has_ret_val(&mut self, num: usize) -> bool { fn has_ret_val(&mut self, num: usize) -> bool {
match num { match num {
0 => true, 0 => true,
1 => true,
_ => false, _ => false,
} }
} }
@ -169,67 +181,123 @@ impl RawAddin for OpiTcp {
}; };
// Вызываем send_message с address, port, извлечённым message и timeout // Вызываем send_message с address, port, извлечённым message и timeout
send_message(&self.address, self.port, &message, timeout as u64, ret_value) send_message(&self.address, self.port, &message, timeout as u64, self.ssl, ret_value)
}, },
_ => false, _ => false,
} }
} }
} }
fn send_message( fn to_utf16(input: &str) -> Vec<u16> {
input.encode_utf16().collect()
}
pub fn send_message(
address: &str, address: &str,
port: i32, port: i32,
message: &dyn AsRef<[u8]>, // Используем trait, чтобы поддерживать как строку, так и бинарные данные message: &dyn AsRef<[u8]>,
timeout_secs: u64, timeout_secs: u64,
ret_value: &mut Variant use_ssl: bool,
ret_value: &mut Variant,
) -> bool { ) -> bool {
let server_addr = format!("{}:{}", address, port); let addr = format!("{}:{}", address, port);
// Устанавливаем таймауты для подключения и операций чтения/записи // Устанавливаем таймаут
let timeout = Duration::new(timeout_secs, 0); // Таймаут в секундах let timeout = Duration::from_secs(timeout_secs);
// Проверка доступности порта на сервере с таймаутом // Создаем TCP соединение
match TcpStream::connect_timeout(&server_addr.to_socket_addrs().unwrap().next().unwrap(), timeout) { let stream = TcpStream::connect_timeout(&addr.to_socket_addrs().unwrap().next().unwrap(), timeout);
Ok(mut stream) => { let stream = match stream {
// Устанавливаем таймауты на операции с соединением Ok(s) => s,
stream.set_read_timeout(Some(timeout)).unwrap(); Err(e) => {
stream.set_write_timeout(Some(timeout)).unwrap(); ret_value.set_str(&to_utf16(&format!("Failed to connect: {}", e)));
return true;
}
};
// Отправляем сообщение с таймаутом // Применяем таймауты к потокам чтения и записи
match stream.write_all(message.as_ref()) { if let Err(e) = stream.set_read_timeout(Some(timeout)) {
ret_value.set_str(&to_utf16(&format!("Failed to set read timeout: {}", e)));
return true;
}
if let Err(e) = stream.set_write_timeout(Some(timeout)) {
ret_value.set_str(&to_utf16(&format!("Failed to set write timeout: {}", e)));
return true;
}
// Обрабатываем SSL при необходимости
let mut stream = if use_ssl {
let connector = match TlsConnector::new() {
Ok(c) => c,
Err(e) => {
ret_value.set_str(&to_utf16(&format!("Failed to create TLS connector: {}", e)));
return true;
}
};
match connector.connect(address, stream) {
Ok(s) => StreamWrapper::Secure(s),
Err(e) => {
ret_value.set_str(&to_utf16(&format!("Failed to establish SSL connection: {}", e)));
return true;
}
}
} else {
StreamWrapper::Plain(stream)
};
// Отправляем сообщение
if let Err(e) = stream.write_all(message.as_ref()) {
ret_value.set_str(&to_utf16(&format!("Failed to send message: {}", e)));
return true;
}
// Читаем ответ
let mut response = Vec::new();
match stream.read_to_end(&mut response) {
Ok(_) => { Ok(_) => {
let mut buffer = Vec::new(); match String::from_utf8(response) {
match stream.read_to_end(&mut buffer) { Ok(s) => {
Ok(_) => { let _ = ret_value.set_str(&to_utf16(&s));
// Ответ получен }
match String::from_utf8(buffer) { Err(e) => {
Ok(response) => { let _ = ret_value.set_str(&to_utf16(&format!("Failed to decode response: {}", e)));
ret_value.set_str(response.encode_utf16().collect::<Vec<u16>>().as_slice()); }
}
true true
} }
Err(_) => { Err(e) => {
ret_value.set_str("Неко UTF-8 response".encode_utf16().collect::<Vec<u16>>().as_slice()); ret_value.set_str(&to_utf16(&format!("Failed to read response: {}", e)));
true true
} }
} }
} }
Err(_) => {
// Ошибка чтения ответа (таймаут или другая ошибка) enum StreamWrapper {
ret_value.set_str("Server did not respond in time".encode_utf16().collect::<Vec<u16>>().as_slice()); Plain(TcpStream),
true Secure(TlsStream<TcpStream>),
}
impl Read for StreamWrapper {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
StreamWrapper::Plain(stream) => stream.read(buf),
StreamWrapper::Secure(stream) => stream.read(buf),
} }
} }
} }
Err(_) => {
ret_value.set_str("Failed to send message".encode_utf16().collect::<Vec<u16>>().as_slice()); impl Write for StreamWrapper {
true fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
} match self {
} StreamWrapper::Plain(stream) => stream.write(buf),
} StreamWrapper::Secure(stream) => stream.write(buf),
Err(_) => { }
// Ошибка подключения (таймаут или сервер не доступен) }
ret_value.set_str("Server is unreachable or connection timeout".encode_utf16().collect::<Vec<u16>>().as_slice());
true fn flush(&mut self) -> io::Result<()> {
match self {
StreamWrapper::Plain(stream) => stream.flush(),
StreamWrapper::Secure(stream) => stream.flush(),
} }
} }
} }