1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2024-12-29 02:57:35 +02:00

Попытка в TCP клиент на раст

This commit is contained in:
Anton Titovets 2024-12-07 16:06:47 +03:00
parent 2267867e2f
commit cdf64b5017
7 changed files with 353 additions and 1 deletions

View File

@ -0,0 +1,17 @@
[package]
name = "opi_tcp"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[profile.release]
lto = true # Enable Link Time Optimization
codegen-units = 1 # Reduce number of codegen units to increase optimizations.
panic = "abort" # Abort on panic
strip = true # Automatically strip symbols from the binary.
[dependencies]
addin1c = "0.1"
native-tls = "0.2.12"

View File

@ -0,0 +1,46 @@
mod opi_tcp;
use std::{
ffi::{c_int, c_long, c_void},
sync::atomic::{AtomicI32, Ordering},
};
use opi_tcp::OpiTcp;
use addin1c::{create_component, destroy_component, name, AttachType};
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn GetClassObject(name: *const u16, component: *mut *mut c_void) -> c_long {
let addin = OpiTcp::new();
create_component(component, addin)
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn DestroyObject(component: *mut *mut c_void) -> c_long {
destroy_component(component)
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn GetClassNames() -> *const u16 {
// small strings for performance
name!("Client").as_ptr()
}
#[allow(non_snake_case)]
#[no_mangle]
pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int {
PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed);
3
}
#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn GetAttachType() -> AttachType {
AttachType::Any
}

View File

@ -0,0 +1,235 @@
use addin1c::{name, ParamValue, RawAddin, Tm, Variant};
use std::io::{Read, Write};
use std::net::{TcpStream, ToSocketAddrs};
use std::time::Duration;
// Свойства объекта
const PROPS: &[&[u16]] = &[
name!("Адрес"),
name!("Порт")
];
// Объявление методов
const METHODS: &[&[u16]] = &[
name!("ОтправитьСообщение")
];
// Определение типов свойств
pub struct OpiTcp {
address: String,
port: i32,
}
// Конструктор
impl OpiTcp {
pub fn new() -> OpiTcp {
OpiTcp {
address: String::from(""),
port: 0,
}
}
}
// Обработка удаления объекта
impl Drop for OpiTcp {
fn drop(&mut self) {}
}
// Определение класса
impl RawAddin for OpiTcp {
fn register_extension_as(&mut self) -> &'static [u16] {
name!("Client")
}
fn get_n_props(&mut self) -> usize {
PROPS.len()
}
fn find_prop(&mut self, name: &[u16]) -> Option<usize> {
PROPS.iter().position(|&x| x == name)
}
fn get_prop_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> {
PROPS.get(num).copied()
}
// Геттеры
fn get_prop_val(&mut self, num: usize, val: &mut Variant) -> bool {
match num {
0 => {
let s: Vec<u16> = self.address.encode_utf16().collect();
return val.set_str(s.as_slice());
}
1 => val.set_i32(self.port),
_ => return false,
};
true
}
// Сеттеры
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool {
match num {
0 => match val {
ParamValue::Str(x) => {
self.address = String::from_utf16(x).unwrap();
true
}
_ => false,
},
1 => match val {
ParamValue::I32(x) => {
self.port = *x;
true
}
_ => false,
},
_ => false,
}
}
fn is_prop_readable(&mut self, _num: usize) -> bool {
true
}
fn is_prop_writable(&mut self, num: usize) -> bool {
match num {
0 => true,
1 => true,
_ => false,
}
}
fn get_n_methods(&mut self) -> usize {
METHODS.len()
}
fn find_method(&mut self, name: &[u16]) -> Option<usize> {
METHODS.iter().position(|&x| x == name)
}
fn get_method_name(&mut self, num: usize, _alias: usize) -> Option<&'static [u16]> {
METHODS.get(num).copied()
}
fn get_n_params(&mut self, num: usize) -> usize {
match num {
0 => 2,
_ => 0,
}
}
fn get_param_def_value(
&mut self,
_method_num: usize,
_param_num: usize,
_value: Variant,
) -> bool {
true
}
fn has_ret_val(&mut self, num: usize) -> bool {
match num {
0 => true,
1 => true,
_ => false,
}
}
fn call_as_proc(&mut self, _num: usize, _params: &mut [Variant]) -> bool {
false
}
fn call_as_func(
&mut self,
num: usize,
params: &mut [Variant],
ret_value: &mut Variant,
) -> bool {
match num {
0 => {
// Проверяем, является ли первый параметр строкой или бинарными данными
let message: Vec<u8> = match params.get(0).map(|p| p.get()) {
Some(ParamValue::Str(str_message)) => {
// Преобразуем строку из &[u16] в Vec<u8>
String::from_utf16(str_message)
.unwrap_or_default()
.into_bytes()
},
Some(ParamValue::Blob(blob_message)) => {
// Просто передаем бинарные данные
blob_message.to_vec()
},
_ => return false, // Неверный тип данных
};
// Извлекаем таймаут из второго параметра
let ParamValue::I32(timeout) = params.get(1).map(|p| p.get()).unwrap_or(ParamValue::I32(0)) else {
return false; // Неверный тип для таймаута
};
// Вызываем send_message с address, port, извлечённым message и timeout
send_message(&self.address, self.port, &message, timeout as u64, ret_value)
},
_ => false,
}
}
}
fn send_message(
address: &str,
port: i32,
message: &dyn AsRef<[u8]>, // Используем trait, чтобы поддерживать как строку, так и бинарные данные
timeout_secs: u64,
ret_value: &mut Variant
) -> bool {
let server_addr = format!("{}:{}", address, port);
// Устанавливаем таймауты для подключения и операций чтения/записи
let timeout = Duration::new(timeout_secs, 0); // Таймаут в секундах
// Проверка доступности порта на сервере с таймаутом
match TcpStream::connect_timeout(&server_addr.to_socket_addrs().unwrap().next().unwrap(), timeout) {
Ok(mut stream) => {
// Устанавливаем таймауты на операции с соединением
stream.set_read_timeout(Some(timeout)).unwrap();
stream.set_write_timeout(Some(timeout)).unwrap();
// Отправляем сообщение с таймаутом
match stream.write_all(message.as_ref()) {
Ok(_) => {
let mut buffer = Vec::new();
match stream.read_to_end(&mut buffer) {
Ok(_) => {
// Ответ получен
match String::from_utf8(buffer) {
Ok(response) => {
ret_value.set_str(response.encode_utf16().collect::<Vec<u16>>().as_slice());
true
}
Err(_) => {
ret_value.set_str("Неко UTF-8 response".encode_utf16().collect::<Vec<u16>>().as_slice());
true
}
}
}
Err(_) => {
// Ошибка чтения ответа (таймаут или другая ошибка)
ret_value.set_str("Server did not respond in time".encode_utf16().collect::<Vec<u16>>().as_slice());
true
}
}
}
Err(_) => {
ret_value.set_str("Failed to send message".encode_utf16().collect::<Vec<u16>>().as_slice());
true
}
}
}
Err(_) => {
// Ошибка подключения (таймаут или сервер не доступен)
ret_value.set_str("Server is unreachable or connection timeout".encode_utf16().collect::<Vec<u16>>().as_slice());
true
}
}
}

View File

@ -1,4 +1,4 @@
// OneScript: ./OInt/tools/Modules/internal/Modules/OPI_Инструменты.os
// OneScript: ./OInt/tools/Modules/internal/Modules/OPI_Инструменты.os
// MIT License
@ -1012,6 +1012,21 @@
КонецПроцедуры
Функция ПолучитьКомпонентуНаСервере(Знач ИмяМакета, Знач ИмяКомпоненты, Знач Класс, Знач Переустановка = Ложь) Экспорт
Компонента = Неопределено;
Если Не ИнициализироватьВнешнююКомпоненту(ИмяКомпоненты, Класс, Компонента) Или Переустановка Тогда
ПодключитьКомпонентуНаСервере(ИмяМакета, ИмяКомпоненты);
ИнициализироватьВнешнююКомпоненту(ИмяКомпоненты, Класс, Компонента);
КонецЕсли;
Возврат Компонента;
КонецФункции
#КонецОбласти
#КонецОбласти
@ -1480,6 +1495,35 @@
КонецПроцедуры
#Область РаботаСВнешнимиКомпонентами
Функция ИнициализироватьВнешнююКомпоненту(Знач ИмяКомпоненты, Знач Класс, Компонента)
Попытка
Компонента = Новый("AddIn." + ИмяКомпоненты + "." + Класс);
Возврат Ложь;
Исключение
Возврат Ложь;
КонецПопытки;
КонецФункции
Процедура ПодключитьКомпонентуНаСервере(Знач ИмяМакета, Знач ИмяКомпоненты)
МакетВнешнейКомпоненты = ПолучитьОбщийМакет(ИмяМакета);
АдресВоВременномХранилище = ПоместитьВоВременноеХранилище(МакетВнешнейКомпоненты, Новый УникальныйИдентификатор);
КомпонентаПодключена = ПодключитьВнешнююКомпоненту(
АдресВоВременномХранилище,
ИмяКомпоненты,
ТипВнешнейКомпоненты.Native
);
КонецПроцедуры
#КонецОбласти
#Область GZip
// Описание структур см. здесь https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<mdclass:CommonTemplate xmlns:mdclass="http://g5.1c.ru/v8/dt/metadata/mdclass" uuid="c61532fa-8d2c-4b20-8609-b1ad7beac4f1">
<name>OPI_TCPКлиент</name>
<synonym>
<key></key>
<value>OPI TCPКлиент</value>
</synonym>
<templateType>BinaryData</templateType>
</mdclass:CommonTemplate>

View File

@ -39,6 +39,7 @@
<value>https://github.com/Bayselonarrend/OpenIntegrations</value>
</configurationInformationAddress>
<subsystems>Subsystem.OPI_Интеграция</subsystems>
<commonTemplates>CommonTemplate.OPI_TCPКлиент</commonTemplates>
<commonModules>CommonModule.OPI_Инструменты</commonModules>
<commonModules>CommonModule.OPI_Криптография</commonModules>
<commonModules>CommonModule.OPI_ПреобразованиеТипов</commonModules>