1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2025-01-12 04:34:10 +02:00

Правка структуры компонент, компонента TCP сервера

This commit is contained in:
Anton Titovets 2024-12-20 10:04:42 +03:00
parent bcd825b147
commit c2826a8b40
22 changed files with 602 additions and 8 deletions

118
src/addins/tcp_server/Cargo.lock generated Normal file
View File

@ -0,0 +1,118 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "addin1c"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef34e8b7ff4c43e87491a4cc30a4779a9f67c50db43378a36362c7a56246e05b"
dependencies = [
"smallvec",
"utf16_lit",
]
[[package]]
name = "itoa"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "opi_addin"
version = "0.1.0"
dependencies = [
"addin1c",
"serde_json",
]
[[package]]
name = "proc-macro2"
version = "1.0.92"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
dependencies = [
"proc-macro2",
]
[[package]]
name = "ryu"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
[[package]]
name = "serde"
version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.216"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.133"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377"
dependencies = [
"itoa",
"memchr",
"ryu",
"serde",
]
[[package]]
name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
[[package]]
name = "syn"
version = "2.0.90"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "unicode-ident"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
[[package]]
name = "utf16_lit"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14706d2a800ee8ff38c1d3edb873cd616971ea59eb7c0d046bb44ef59b06a1ae"

View File

@ -0,0 +1,17 @@
[package]
name = "opi_addin"
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.5.0"
serde_json = "1.0.133"

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<bundle xmlns='http://v8.1c.ru/8.2/addin/bundle' name='OPIADDIN'>
<component os='Windows' path='AddIn_x86_windows.dll' type='native' arch='i386' />
<component os='Windows' path='AddIn_x64_windows.dll' type='native' arch='x86_64' />
<component os='Linux' path='AddIn_x86_linux.so' type='native' arch='i386' />
<component os='Linux' path='AddIn_x64_linux.so' type='native' arch='x86_64' />
</bundle>

View File

@ -0,0 +1,63 @@
@echo off
:: Установить переменную
set LIB_NAME=opi_addin
set OPENSSL_DIR=C:\msys64\mingw64
set OPENSSL_LIB_DIR=%OPENSSL_DIR%\lib
set OPENSSL_INCLUDE_DIR=%OPENSSL_DIR%\include
:: Перейти в директорию проекта
cd /d "%~dp0"
:: Создать папку для артефактов
set OUTPUT_DIR=artifacts
if not exist "%OUTPUT_DIR%" mkdir "%OUTPUT_DIR%"
:: Сборка для x86_64-pc-windows-msvc
cargo build --release --target x86_64-pc-windows-msvc
if errorlevel 1 goto :error
:: Сборка для x86_64-unknown-linux-gnu
cargo zigbuild --release --target x86_64-unknown-linux-gnu
if errorlevel 1 goto :error
:: Сборка для i686-pc-windows-msvc
cargo build --release --target i686-pc-windows-msvc
if errorlevel 1 goto :error
:: Сборка для i686-unknown-linux-gnu
cargo zigbuild --release --target i686-unknown-linux-gnu
if errorlevel 1 goto :error
:: Копирование файлов .dll и .so
copy /y target\x86_64-pc-windows-msvc\release\%LIB_NAME%.dll "%OUTPUT_DIR%\AddIn_x64_windows.dll"
if errorlevel 1 goto :error
copy /y target\i686-pc-windows-msvc\release\%LIB_NAME%.dll "%OUTPUT_DIR%\AddIn_x86_windows.dll"
if errorlevel 1 goto :error
copy /y target\x86_64-unknown-linux-gnu\release\lib%LIB_NAME%.so "%OUTPUT_DIR%\AddIn_x64_linux.so"
if errorlevel 1 goto :error
copy /y target\i686-unknown-linux-gnu\release\lib%LIB_NAME%.so "%OUTPUT_DIR%\AddIn_x86_linux.so"
if errorlevel 1 goto :error
copy /y MANIFEST.XML "%OUTPUT_DIR%\MANIFEST.XML"
if errorlevel 1 goto :error
:: Архивация
set ZIP_NAME=addin.zip
powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%ZIP_NAME%'"
if errorlevel 1 goto :error
if exist "%OUTPUT_DIR%" (
rmdir /S /Q "%OUTPUT_DIR%"
)
@echo Build and packaging completed successfully.
exit /b 0
:error
@echo An error occurred during the build or packaging process.
exit /b 1

View File

@ -0,0 +1,101 @@
use std::net::{TcpListener, TcpStream};
use std::io::{Read, Write};
use std::time::Instant;
use serde_json::json;
use crate::component::AddIn;
pub enum ServerEvent {
NewConnection(String),
MessageReceived(String, Vec<u8>),
}
pub fn start_server(addin: &mut AddIn) -> String {
let addr = format!("0.0.0.0:{}", addin.port);
let listener = TcpListener::bind(&addr);
match listener {
Ok(listener) => {
let sender = addin.sender.clone();
std::thread::spawn(move || {
for stream in listener.incoming() {
if let Ok(mut stream) = stream {
let addr = stream.peer_addr().unwrap().to_string();
sender.send(ServerEvent::NewConnection(addr.clone())).unwrap();
let sender = sender.clone();
std::thread::spawn(move || {
let mut buffer = [0; 1024];
while let Ok(bytes_read) = stream.read(&mut buffer) {
if bytes_read == 0 {
break;
}
sender
.send(ServerEvent::MessageReceived(
addr.clone(),
buffer[..bytes_read].to_vec(),
))
.unwrap();
}
});
}
}
});
"Success".to_string()
}
Err(e) => e.to_string(),
}
}
pub fn await_connections(addin: &mut AddIn, timeout: i32) -> String {
let start_time = Instant::now();
let mut active_connections = Vec::new();
while start_time.elapsed().as_secs() < timeout as u64 {
if let Ok(event) = addin.receiver.try_recv() {
match event {
ServerEvent::NewConnection(addr) => {
active_connections.push(addr.clone());
addin.connections.insert(addr, TcpStream::connect("127.0.0.1:0").unwrap());
}
ServerEvent::MessageReceived(addr, _data) => {
if !active_connections.contains(&addr) {
active_connections.push(addr);
}
}
}
} else {
std::thread::sleep(std::time::Duration::from_millis(100));
}
}
json!(active_connections).to_string()
}
pub fn receive_message(addin: &mut AddIn, addr: &str) -> Vec<u8> {
if let Some(stream) = addin.connections.get_mut(addr) {
let mut buffer = [0; 1024];
if let Ok(bytes_read) = stream.read(&mut buffer) {
if bytes_read > 0 {
return buffer[..bytes_read].to_vec();
}
}
}
vec![]
}
pub fn send_response(addin: &mut AddIn, addr: &str, data: &[u8]) -> String {
if let Some(stream) = addin.connections.get_mut(addr) {
if stream.write_all(data).is_ok() {
return "Success".to_string();
}
}
"Failed to send response".to_string()
}
pub fn stop(addin: &mut AddIn) -> String {
addin.connections.clear();
"Success".to_string()
}

View File

@ -0,0 +1,108 @@
mod methods;
use addin1c::{name, Variant};
use crate::core::getset;
use std::collections::HashMap;
use std::net::TcpStream;
use std::sync::mpsc::{Sender, Receiver};
use self::methods::{ServerEvent};
// МЕТОДЫ КОМПОНЕНТЫ -------------------------------------------------------------------------------
// Синонимы
pub const METHODS: &[&[u16]] = &[
name!("Start"),
name!("Await"),
name!("ReceiveMessage"),
name!("SendResponse"),
name!("Stop"),
];
// Число параметров функций компоненты
pub fn get_params_amount(num: usize) -> usize {
match num {
0 => 0,
1 => 1,
2 => 1,
3 => 2,
4 => 0,
_ => 0,
}
}
// Соответствие функций Rust функциям компоненты
// Вызовы должны быть обернуты в Box::new
pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn getset::ValueType> {
match num {
0 => Box::new(methods::start_server(obj)),
1 => {
let timeout = params[0].get_i32().unwrap_or(0);
Box::new(methods::await_connections(obj, timeout))
}
2 => {
let addr = params[0].get_string().unwrap_or("".to_string());
Box::new(methods::receive_message(obj, &addr))
}
3 =>{
let empty_array: [u8; 0] = [];
let addr = params[0].get_string().unwrap_or("".to_string());
let data = params[1].get_blob().unwrap_or(&empty_array);
Box::new(methods::send_response(obj, &addr, data))
}
4 => Box::new(methods::stop(obj)),
_ => Box::new(false), // Неверный номер команды
}
}
// -------------------------------------------------------------------------------------------------
// ПОЛЯ КОМПОНЕНТЫ ---------------------------------------------------------------------------------
// Синонимы
pub const PROPS: &[&[u16]] = &[
name!("Port")
];
pub struct AddIn {
pub port: i32,
pub connections: HashMap<String, TcpStream>,
pub sender: Sender<ServerEvent>,
pub receiver: Receiver<ServerEvent>,
}
impl AddIn {
pub fn new() -> Self {
let (sender, receiver) = std::sync::mpsc::channel();
AddIn {
port: 0,
connections: HashMap::new(),
sender,
receiver,
}
}
pub fn get_field_ptr(&self, index: usize) -> *const dyn getset::ValueType {
match index {
0 => &self.port as &dyn getset::ValueType as *const _,
_ => panic!("Index out of bounds"),
}
}
pub fn get_field_ptr_mut(&mut self, index: usize) -> *mut dyn getset::ValueType { self.get_field_ptr(index) as *mut _ }
}
// -------------------------------------------------------------------------------------------------
// Обработка удаления объекта
impl Drop for AddIn {
fn drop(&mut self) {
methods::stop(self);
}
}

View File

@ -0,0 +1,78 @@
use addin1c::{Variant, Tm};
pub trait ValueType {
fn get_value(&self, val: &mut Variant) -> bool;
fn set_value(&mut self, val: &Variant);
}
// Реализация для i32
impl ValueType for i32 {
fn get_value(&self, val: &mut Variant) -> bool {
val.set_i32(*self);
true
}
fn set_value(&mut self, val: &Variant) {
*self = val.get_i32().unwrap_or(0);
}
}
// Реализация для f64
impl ValueType for f64 {
fn get_value(&self, val: &mut Variant) -> bool {
val.set_f64(*self);
true
}
fn set_value(&mut self, val: &Variant) {
*self = val.get_f64().unwrap_or(0.0);
}
}
// Реализация для bool
impl ValueType for bool {
fn get_value(&self, val: &mut Variant) -> bool {
val.set_bool(*self);
true
}
fn set_value(&mut self, val: &Variant) {
*self = val.get_bool().unwrap_or(false);
}
}
// Реализация для tm
impl ValueType for Tm {
fn get_value(&self, val: &mut Variant) -> bool {
val.set_date(*self);
true
}
fn set_value(&mut self, val: &Variant) {
*self = val.get_date().unwrap_or(Tm::default());
}
}
// Реализация для String
impl ValueType for String {
fn get_value(&self, val: &mut Variant) -> bool {
let s: Vec<u16> = self.encode_utf16().collect();
val.set_str1c(s.as_slice()).is_ok()
}
fn set_value(&mut self, val: &Variant) {
*self = val.get_string().unwrap_or("".to_string());
}
}
// Реализация для Vec<u8>
impl ValueType for Vec<u8> {
fn get_value(&self, val: &mut Variant) -> bool {
val.set_blob(self.as_slice()).is_ok()
}
fn set_value(&mut self, val: &Variant) {
*self = val.get_blob().unwrap_or(&[]).to_vec()
}
}

View File

@ -0,0 +1,53 @@
pub mod getset;
use addin1c::{name, RawAddin, Variant};
use crate::component::METHODS;
use crate::component::PROPS;
use crate::component::get_params_amount;
use crate::component::cal_func;
use crate::component::AddIn;
// Определение класса
impl RawAddin for AddIn {
fn register_extension_as(&mut self) -> &'static [u16] {
name!("Main")
}
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 {let field: &dyn getset::ValueType = &self[num]; field.get_value(val) }
fn set_prop_val(&mut self, num: usize, val: &Variant) -> bool {let field: &mut dyn getset::ValueType = &mut self[num]; field.set_value(val); true }
fn is_prop_readable(&mut self, _nm: usize) -> bool { true }
fn is_prop_writable(&mut self, num: usize) -> bool { true }
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 { get_params_amount(num) }
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 { true }
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 { cal_func(self, num, params).get_value(ret_value) }
}
impl std::ops::Index<usize> for AddIn {
type Output = dyn getset::ValueType;
fn index(&self, index: usize) -> &Self::Output {
unsafe { &*self.get_field_ptr(index) }
}
}
impl std::ops::IndexMut<usize> for AddIn {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
unsafe { &mut *self.get_field_ptr_mut(index) }
}
}

View File

@ -0,0 +1,48 @@
pub mod component;
mod core;
use std::{
ffi::{c_int, c_long, c_void},
sync::atomic::{AtomicI32, Ordering},
};
use component::AddIn;
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 = AddIn::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!("Main").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

@ -60,4 +60,11 @@ impl AddIn {
}
pub fn get_field_ptr_mut(&mut self, index: usize) -> *mut dyn getset::ValueType { self.get_field_ptr(index) as *mut _ }
}
// -------------------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------------------
// УНИЧТОЖЕНИЕ ОБЪЕКТА -----------------------------------------------------------------------------
// Обработка удаления объекта
impl Drop for AddIn {
fn drop(&mut self) {}
}

View File

@ -8,12 +8,6 @@ use crate::component::get_params_amount;
use crate::component::cal_func;
use crate::component::AddIn;
// Обработка удаления объекта
impl Drop for AddIn {
fn drop(&mut self) {}
}
// Определение класса
impl RawAddin for AddIn {

View File

@ -31,7 +31,7 @@ pub unsafe extern "C" fn DestroyObject(component: *mut *mut c_void) -> c_long {
#[no_mangle]
pub extern "C" fn GetClassNames() -> *const u16 {
// small strings for performance
name!("Client").as_ptr()
name!("Main").as_ptr()
}
#[allow(non_snake_case)]