1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2025-08-24 19:49:22 +02:00

Компонента RCON

This commit is contained in:
Anton Titovets
2025-03-16 14:28:33 +03:00
parent 3f81469096
commit 2aee7f2e87
12 changed files with 297 additions and 152 deletions

View File

@@ -2,13 +2,6 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "OPI_TCPClient"
version = "0.1.0"
dependencies = [
"addin1c",
]
[[package]]
name = "addin1c"
version = "0.5.0"
@@ -19,14 +12,234 @@ dependencies = [
"utf16_lit",
]
[[package]]
name = "bytes"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
name = "itoa"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "libc"
version = "0.2.171"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
[[package]]
name = "memchr"
version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "opi_rcon"
version = "0.1.0"
dependencies = [
"addin1c",
"rcon-client",
"serde_json",
]
[[package]]
name = "ppv-lite86"
version = "0.2.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
dependencies = [
"zerocopy",
]
[[package]]
name = "proc-macro2"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"libc",
"rand_chacha",
"rand_core",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom",
]
[[package]]
name = "rcon-client"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d9b4e2e51166f5ceae4582950d7775f1d8cd6ce6e2e1435c586940db685dd63"
dependencies = [
"bytes",
"rand",
"serde",
"thiserror",
]
[[package]]
name = "ryu"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "serde"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.219"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
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.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]]
name = "utf16_lit"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14706d2a800ee8ff38c1d3edb873cd616971ea59eb7c0d046bb44ef59b06a1ae"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "zerocopy"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd97444d05a4328b90e75e503a34bad781f14e28a823ad3557f0750df1ebcbc6"
dependencies = [
"zerocopy-derive",
]
[[package]]
name = "zerocopy-derive"
version = "0.8.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6352c01d0edd5db859a63e2605f4ea3183ddbd15e2c4a9e7d32184df75e4f154"
dependencies = [
"proc-macro2",
"quote",
"syn",
]

View File

@@ -1,5 +1,5 @@
[package]
name = "OPI_TCPClient"
name = "opi_rcon"
version = "0.1.0"
edition = "2021"
@@ -13,4 +13,6 @@ panic = "abort" # Abort on panic
strip = true # Automatically strip symbols from the binary.
[dependencies]
addin1c = "0.5.0"
addin1c = "0.5.0"
rcon-client = "0.1.3"
serde_json = "1.0"

Binary file not shown.

View File

@@ -1,6 +1,7 @@
@echo off
:: Установить переменную
set CARGO_NAME=opi_rcon
set LIB_NAME=OPI_RCON
set OPENSSL_DIR=C:\msys64\mingw64
set OPENSSL_LIB_DIR=%OPENSSL_DIR%\lib
@@ -31,16 +32,16 @@ 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"
copy /y target\x86_64-pc-windows-msvc\release\%CARGO_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"
copy /y target\i686-pc-windows-msvc\release\%CARGO_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"
copy /y target\x86_64-unknown-linux-gnu\release\lib%CARGO_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"
copy /y target\i686-unknown-linux-gnu\release\lib%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x86_linux.so"
if errorlevel 1 goto :error
copy /y MANIFEST.XML "%OUTPUT_DIR%\MANIFEST.XML"

View File

@@ -1,78 +1,56 @@
use std::io::{Read, Write};
use std::net::{Shutdown, TcpStream};
use std::time::{Duration, Instant};
use crate::component::AddIn;
use rcon_client::{AuthRequest, RCONClient, RCONConfig, RCONRequest};
use serde_json;
use serde_json::json;
/// Отправляет данные
pub fn send(connection: &mut TcpStream, data: Vec<u8>, timeout_ms: i32) -> bool {
pub fn connect(obj: &mut AddIn, url: &str, password: &str, read_timeout: i32, write_timeout: i32) -> String {
if timeout_ms > 0 {
let timeout = Duration::from_millis(timeout_ms as u64);
connection.set_write_timeout(Some(timeout)).ok();
let mut client = match RCONClient::new(RCONConfig {
url: url.to_string(),
read_timeout: Some(read_timeout as u64),
write_timeout: Some(write_timeout as u64),
}){
Ok(client) => client,
Err(e) => {return process_error(e.to_string())}
};
match connection.write(&data) {
Ok(_) => connection.flush().is_ok(),
Err(_) => false, // Ошибка при отправке данных
let auth_result = match client.auth(AuthRequest::new(password.to_string())){
Ok(auth_result) => auth_result,
Err(e) => {return process_error(e.to_string())}
};
match auth_result.is_success(){
true => {
obj.client = Some(client);
json!({"result": true}).to_string()
}
false => {
let response_type = auth_result.response_type;
process_error(format!("Unexpected authorisation rejection (type {})", response_type))
}
}
}
pub fn execute_command(obj: &mut AddIn, command: &str) -> String {
if let Some(client) = &mut obj.client {
match client.execute(RCONRequest::new(command.to_string())){
Ok(response) => { process_success(response.body) }
Err(e) => { process_error(e.to_string()) }
}
}else{
process_error("No client found. Initialize connection first".to_string())
}
}
/// Считывает данные
pub fn receive(
connection: &mut TcpStream,
max_data_size: i32,
end_marker: Vec<u8>,
timeout_ms: i32
) -> Vec<u8> {
const BUFFER_SIZE: usize = 1024; // Размер временного буфера
const MIN_READ_TIMEOUT_MS: u64 = 200; // Минимальный таймаут для чтения
let mut result = Vec::new();
let mut buffer = vec![0u8; BUFFER_SIZE];
// Устанавливаем общее время ожидания
let total_timeout = Duration::from_millis(timeout_ms as u64);
let start_time = Instant::now(); // Время начала работы функции
let min_read_timeout = Duration::from_millis(MIN_READ_TIMEOUT_MS);
let marker_exists = !end_marker.is_empty();
connection.set_read_timeout(Some(min_read_timeout)).ok();
loop {
// Проверяем общее время выполнения
if start_time.elapsed() >= total_timeout {
break; // Прерываем, если общее время истекло
}
// Завершаем цикл, если превышен лимит данных
if max_data_size > 0 && result.len() >= max_data_size as usize {
break;
}
match connection.read(&mut buffer) {
Ok(0) => break, // EOF — конец данных
Ok(size) => {
result.extend_from_slice(&buffer[..size]);
// Завершаем цикл, если получен конец сообщения (если end_marker задан)
if marker_exists && result.ends_with(&end_marker) {
break;
}
}
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => continue,
Err(_) => break, // Любая другая ошибка завершает чтение
}
}
result
fn process_error(e: String) -> String {
json!({"result": false, "error": e}).to_string()
}
/// Закрывает соединение
pub fn disconnect(add_in: &mut crate::component::AddIn) -> bool {
add_in.connection = None;
true
fn process_success(data: String) -> String {
json!({"result": true, "data": data}).to_string()
}
/// Закрытие потока записи
pub fn close_output(connection: &mut TcpStream) -> bool {
connection.shutdown(Shutdown::Write).is_ok()
}

View File

@@ -1,29 +1,23 @@
mod methods;
use addin1c::{name, Variant};
use rcon_client::RCONClient;
use crate::core::getset;
use std::net::TcpStream;
use crate::component::methods::disconnect;
// МЕТОДЫ КОМПОНЕНТЫ -------------------------------------------------------------------------------
// Синонимы
pub const METHODS: &[&[u16]] = &[
name!("Connect"), // 0
name!("Disconnect"), // 1
name!("Read"), // 2
name!("Send"), // 3
name!("CloseOutput") // 4
name!("Command") // 1
];
// Число параметров функций компоненты
pub fn get_params_amount(num: usize) -> usize {
match num {
0 => 0,
1 => 0,
2 => 3,
3 => 2,
4 => 0,
0 => 4,
1 => 1,
_ => 0,
}
}
@@ -32,45 +26,22 @@ pub fn get_params_amount(num: usize) -> usize {
// Вызовы должны быть обернуты в Box::new
pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn getset::ValueType> {
let empty_array: [u8; 0] = [];
match num {
0 => Box::new(obj.connect()),
0 => {
let url = params[0].get_string().unwrap_or("".to_string());
let password = params[0].get_string().unwrap_or("".to_string());
let read_timeout = params[2].get_i32().unwrap_or(0);
let write_timeout = params[2].get_i32().unwrap_or(0);
Box::new(methods::connect(obj, &url, &password, read_timeout, write_timeout))
},
1 => {
disconnect(obj);
Box::new(true) // Возвращаем true для обозначения успешного выполнения
let command = params[0].get_string().unwrap_or("".to_string());
Box::new(methods::execute_command(obj, &command))
},
2 => {
let maxsize = params[0].get_i32().unwrap_or(0);
let marker = params[1].get_blob().unwrap_or(&empty_array);
let timeout = params[2].get_i32().unwrap_or(0);
if let Some(ref mut connection) = obj.connection {
Box::new(methods::receive(connection, maxsize, marker.to_vec(), timeout))
} else {
Box::new("OPI: Connection closed".as_bytes().to_vec())
}
},
3 => {
let data = params[0].get_blob().unwrap_or(&empty_array);
let timeout = params[1].get_i32().unwrap_or(0);
if let Some(ref mut connection) = obj.connection {
Box::new(methods::send(connection, data.to_vec(), timeout))
} else {
Box::new(false) // Если соединения нет, возвращаем false
}
},
4 =>{
if let Some(ref mut connection) = obj.connection {
Box::new(methods::close_output(connection))
} else {
Box::new(false)
}
}
_ => Box::new(false), // Неверный номер команды
}
@@ -81,44 +52,23 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn
// ПОЛЯ КОМПОНЕНТЫ ---------------------------------------------------------------------------------
// Синонимы
pub const PROPS: &[&[u16]] = &[
name!("Address")
];
pub const PROPS: &[&[u16]] = &[];
pub struct AddIn {
pub address: String,
connection: Option<TcpStream>,
client: Option<RCONClient>,
}
impl AddIn {
/// Создает новый объект
pub fn new() -> Self {
AddIn {
address: String::new(),
connection: None,
client: None,
}
}
/// Подключается к серверу
pub fn connect(&mut self) -> bool {
if self.address.is_empty() {
return false; // Ошибка: пустой адрес
}
match TcpStream::connect(&self.address) {
Ok(tcp_stream) => {
self.connection = Some(tcp_stream);
true
}
Err(_) => false, // Ошибка при подключении
}
}
pub fn get_field_ptr(&self, index: usize) -> *const dyn getset::ValueType {
match index {
0 => &self.address as &dyn getset::ValueType as *const _,
_ => panic!("Index out of bounds"),
}
}

View File

@@ -30,13 +30,13 @@ impl RawAddin for AddIn {
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, _num: usize) -> bool { true }
fn is_prop_writable(&mut self, num: 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 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) }

View File

@@ -14,7 +14,7 @@ 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 {
pub unsafe extern "C" fn GetClassObject(_name: *const u16, component: *mut *mut c_void) -> c_long {
let addin = AddIn::new();
create_component(component, addin)
@@ -36,6 +36,7 @@ pub extern "C" fn GetClassNames() -> *const u16 {
#[allow(non_snake_case)]
#[no_mangle]
#[allow(static_mut_refs)]
pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int {
PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed);
3

BIN
src/en/OInt/addins/OPI_RCON.zip vendored Normal file

Binary file not shown.

BIN
src/ru/OInt/addins/OPI_RCON.zip vendored Normal file

Binary file not shown.