1
0
mirror of https://github.com/Bayselonarrend/OpenIntegrations.git synced 2026-06-20 09:19:27 +02:00
This commit is contained in:
Anton Titovets
2025-08-09 00:03:32 +03:00
parent 66dc1d7b89
commit 011a6dda76
7 changed files with 283 additions and 73 deletions
+57
View File
@@ -243,6 +243,20 @@ dependencies = [
"syn",
]
[[package]]
name = "dashmap"
version = "7.0.0-rc2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4a1e35a65fe0538a60167f0ada6e195ad5d477f6ddae273943596d4a1a5730b"
dependencies = [
"cfg-if",
"crossbeam-utils",
"equivalent",
"hashbrown",
"lock_api",
"parking_lot_core",
]
[[package]]
name = "dateparser"
version = "0.2.1"
@@ -651,6 +665,16 @@ version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856"
[[package]]
name = "lock_api"
version = "0.4.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.26"
@@ -870,10 +894,25 @@ dependencies = [
"addin1c",
"base64",
"chrono",
"dashmap",
"dateparser",
"mysql",
"mysql_common",
"serde_json",
"uuid",
]
[[package]]
name = "parking_lot_core"
version = "0.9.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-targets",
]
[[package]]
@@ -998,6 +1037,15 @@ dependencies = [
"getrandom 0.2.15",
]
[[package]]
name = "redox_syscall"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
version = "1.11.1"
@@ -1067,6 +1115,12 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "security-framework"
version = "2.11.1"
@@ -1360,6 +1414,9 @@ name = "uuid"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
dependencies = [
"getrandom 0.3.2",
]
[[package]]
name = "vcpkg"
+3 -1
View File
@@ -20,4 +20,6 @@ serde_json = "1.0"
base64 = "0.22.1"
chrono = "0.4.40"
mysql_common = "0.34.1"
dateparser = "0.2.1"
dateparser = "0.2.1"
dashmap = "7.0.0-rc2"
uuid = { version = "1.16.0", features = ["v4"] }
+9 -9
View File
@@ -1,13 +1,13 @@
"MAIN ---"
linux-vdso.so.1 (0x00007fffd6965000)
libssl.so.3 => /lib64/libssl.so.3 (0x0000781f44600000)
libcrypto.so.3 => /lib64/libcrypto.so.3 (0x0000781f43e00000)
libm.so.6 => /lib64/libm.so.6 (0x0000781f43a00000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x0000781f43600000)
libc.so.6 => /lib64/libc.so.6 (0x0000781f43200000)
libdl.so.2 => /lib64/libdl.so.2 (0x0000781f42e00000)
/lib64/ld-linux-x86-64.so.2 (0x0000781f44c00000)
libz.so.1 => /lib64/libz.so.1 (0x0000781f42a00000)
linux-vdso.so.1 (0x00007ffe7cd0b000)
libssl.so.3 => /lib64/libssl.so.3 (0x00007066f1a00000)
libcrypto.so.3 => /lib64/libcrypto.so.3 (0x00007066f1200000)
libm.so.6 => /lib64/libm.so.6 (0x00007066f0e00000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007066f0a00000)
libc.so.6 => /lib64/libc.so.6 (0x00007066f0600000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007066f0200000)
/lib64/ld-linux-x86-64.so.2 (0x00007066f2000000)
libz.so.1 => /lib64/libz.so.1 (0x00007066efe00000)
GLIBC_2.2.5
GLIBC_2.3
GLIBC_2.3.4
+84
View File
@@ -0,0 +1,84 @@
use dashmap::DashMap;
use serde_json::Value;
use std::sync::Arc;
use uuid::Uuid;
pub struct Datasets {
data: Arc<DashMap<String, QueryData>>,
}
#[derive(Debug, Clone)]
pub struct QueryData {
pub results: Vec<Value>,
pub params: Vec<Value>,
pub text: String,
pub force_result: bool,
}
impl Datasets {
pub fn new() -> Self {
Self {
data: Arc::new(DashMap::new()),
}
}
pub fn init_query(&self) -> String {
let key = Uuid::new_v4().to_string();
let query = QueryData::new();
self.data.insert(key.clone(), query);
key
}
pub fn get_query(&self, key: &str) -> Option<QueryData> {
self.data.get(key).map(|guard| guard.value().clone())
}
pub fn set_results(&self, key: &str, values: Vec<Value>) {
if let Some(mut entry) = self.data.get_mut(key) {
entry.results = values;
}
}
pub fn add_param(&self, key: &str, value: Value) {
if let Some(mut entry) = self.data.get_mut(key) {
entry.params.push(value);
}
}
pub fn set_text(&self, key: &str, text: &str) {
if let Some(mut entry) = self.data.get_mut(key) {
entry.text = text.to_string();
}
}
pub fn set_force_result(&self, key: &str, enabled: bool) {
if let Some(mut entry) = self.data.get_mut(key) {
entry.force_result = enabled;
}
}
pub fn len(&self, key: &str) -> Option<usize> {
self.data.get(key).map(|entry| entry.results.len())
}
pub fn remove(&self, key: &str) {
self.data.remove(key);
}
pub fn get_row(&self, key: &str, index: usize) -> Option<String> {
let entry = self.data.get(key)?;
let value = entry.results.get(index)?;
serde_json::to_string(value).ok()
}
}
impl QueryData {
fn new() -> Self {
Self {
results: Vec::new(),
params: Vec::new(),
text: String::new(),
force_result: false,
}
}
}
+60 -24
View File
@@ -1,56 +1,91 @@
use serde_json::{Value, json};
use crate::component::format_json_error;
use crate::component::{format_json_error, AddIn};
use base64::{engine::general_purpose, Engine as _};
use mysql::prelude::Queryable;
use std::collections::HashMap;
use chrono::*;
use mysql::PooledConn;
use mysql_common::packets::Column;
use dateparser::parse;
pub fn init_query(add_in: &mut AddIn, text: &str, force_result: bool) -> String {
let key = add_in.datasets.init_query();
add_in.datasets.set_text(&key, text);
add_in.datasets.set_force_result(&key, force_result);
key
}
pub fn add_query_param(add_in: &mut AddIn, key: &str, param: String) -> String {
let value: Value = match serde_json::from_str(&param) {
Ok(param) => param,
Err(e) => return format_json_error(&e.to_string()),
};
add_in.datasets.add_param(key, value);
json!({"result": true}).to_string()
}
pub fn execute_query(
conn: &mut PooledConn,
query: String,
params_json: String,
force_result: bool
add_in: &mut AddIn,
key: &str
) -> String {
// Парсинг JSON параметров
let mut parsed_params: Value = match serde_json::from_str(&params_json) {
Ok(params) => params,
Err(e) => return format_json_error(e)
let mut conn = match add_in.get_connection(){
Ok(conn) => conn,
Err(e) => return format_json_error(e.to_string()),
};
let params_array = match parsed_params.as_array_mut() {
Some(array) => process_mysql_params(array),
None => return format_json_error("Parameters must be a JSON array")
let query = match add_in.datasets.get_query(key){
Some(q) => q,
None => return format_json_error(format!("No query found by key: {}", key).as_str()),
};
// Определяем тип запроса
if query.trim_start().to_uppercase().starts_with("SELECT") || force_result == true {
let mut params = query.params;
let text = query.text;
let force_result = query.force_result;
let mut rows: Vec<mysql::Row> = match conn.exec(query, params_array){
let params_array = process_mysql_params(&mut params);
let result = if text.trim_start().to_uppercase().starts_with("SELECT") || force_result == true {
let mut rows: Vec<mysql::Row> = match conn.exec(text, params_array){
Ok(rows) => rows,
Err(e) => return format_json_error(e)
};
rows_to_json_array(&mut rows)
match rows_to_json_array(&mut rows){
Ok(json) => {
add_in.datasets.set_results(&key, json);
json!({"result": true, "data": true}).to_string()
},
Err(e) => return format_json_error(e)
}
} else {
let exec_result = match params_array.len() == 0 {
true => conn.query_drop(query),
false => conn.exec_drop(query, params_array)
true => conn.query_drop(text),
false => conn.exec_drop(text, params_array)
};
match exec_result{
Ok(_) => json!({"result": true}).to_string(),
Ok(_) => json!({"result": true, "data": false}).to_string(),
Err(e) => format_json_error(e)
}
}
};
match conn.as_mut().ping(){
Ok(_) => add_in.connection = Some(conn),
Err(_) => drop(conn)
};
result
}
fn rows_to_json_array(rows: &mut Vec<mysql::Row>) -> String {
fn rows_to_json_array(rows: &mut Vec<mysql::Row>) -> Result<Vec<Value>, String> {
let mut json_array = Vec::new();
@@ -72,12 +107,13 @@ fn rows_to_json_array(rows: &mut Vec<mysql::Row>) -> String {
}
match serde_json::to_value(json_obj){
Ok(json) => json_array.push(json),
Err(e) => return format_json_error(e)
Err(e) => return Err(e.to_string())
}
}
json!({ "result": true, "data": json_array }).to_string()
Ok(json_array)
}
fn from_sql_to_json(value: mysql::Value, column: &Column) -> Value {
+53 -20
View File
@@ -1,11 +1,12 @@
mod methods;
mod dataset;
use addin1c::{name, Variant};
use crate::core::getset;
use serde_json::json;
use mysql::*;
use std::path::PathBuf;
use crate::component::dataset::Datasets;
// МЕТОДЫ КОМПОНЕНТЫ -------------------------------------------------------------------------------
// Синонимы
@@ -13,7 +14,12 @@ pub const METHODS: &[&[u16]] = &[
name!("Connect"),
name!("Close"),
name!("Execute"),
name!("SetTLS")
name!("SetTLS"),
name!("GetQueryResultRow"),
name!("GetQueryResultLength"),
name!("RemoveQuery"),
name!("InitQuery"),
name!("AddQueryParam"),
];
@@ -22,8 +28,13 @@ pub fn get_params_amount(num: usize) -> usize {
match num {
0 => 0,
1 => 0,
2 => 3,
2 => 1,
3 => 3,
4 => 2,
5 => 1,
6 => 1,
7 => 2,
8 => 2,
_ => 0,
}
}
@@ -38,24 +49,9 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn
1 => Box::new(obj.close_connection()),
2 => {
let query = params[0].get_string().unwrap_or("".to_string());
let params_json = params[1].get_string().unwrap_or("".to_string());
let force_result = params[2].get_bool().unwrap_or(false);
let key = params[0].get_string().unwrap_or("".to_string());
Box::new(methods::execute_query(obj, &key))
match obj.get_connection(){
Ok(mut conn) => {
let result = Box::new(methods::execute_query(&mut conn, query, params_json, force_result));
match conn.as_mut().ping(){
Ok(_) => obj.connection = Some(conn),
Err(_) => drop(conn)
}
result
},
Err(e) => Box::new(e),
}
},
3 => {
@@ -65,6 +61,41 @@ pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box<dyn
Box::new(obj.set_tls(use_tls, accept_invalid_certs, &ca_cert_path))
},
4 => {
let key = params[0].get_string().unwrap_or("".to_string());
let index = params[1].get_i32().unwrap_or(0);
Box::new(obj.datasets.get_row(&key, index as usize).unwrap_or_else(|| "".to_string()))
},
5 => {
let key = params[0].get_string().unwrap_or("".to_string());
match obj.datasets.len(&key){
Some(len) => Box::new(len as i32),
None => Box::new(json!(
{"result": false, "error": format!("Dataset {} not found", key)}
).to_string()),
}
},
6 => {
let key = params[0].get_string().unwrap_or("".to_string());
obj.datasets.remove(&key);
Box::new(json!({"result": true}).to_string())
},
7 => {
let text = params[0].get_string().unwrap_or("".to_string());
let force = params[1].get_bool().unwrap_or(false);
Box::new(methods::init_query(obj, &text, force))
},
8 => {
let key = params[0].get_string().unwrap_or("".to_string());
let param = params[1].get_string().unwrap_or("".to_string());
Box::new(methods::add_query_param(obj, &key, param))
}
_ => Box::new(false), // Неверный номер команды
}
@@ -88,6 +119,7 @@ pub struct AddIn {
use_tls: bool,
accept_invalid_certs: bool,
ca_cert_path: String,
datasets: Datasets,
}
impl AddIn {
@@ -100,6 +132,7 @@ impl AddIn {
use_tls: false,
accept_invalid_certs: false,
ca_cert_path: String::new(),
datasets: Datasets::new(),
}
}
@@ -144,11 +144,6 @@
, Знач Соединение = ""
, Знач Tls = "") Экспорт
OPI_ПреобразованиеТипов.ПолучитьСтроку(ТекстЗапроса, Истина);
OPI_ПреобразованиеТипов.ПолучитьБулево(ФорсироватьРезультат);
Параметры_ = ОбработатьПараметры(Параметры);
Если ЭтоКоннектор(Соединение) Тогда
ЗакрыватьСоединение = Ложь;
Коннектор = Соединение;
@@ -161,14 +156,16 @@
Возврат Коннектор;
КонецЕсли;
Результат = Коннектор.Execute(ТекстЗапроса, Параметры_, ФорсироватьРезультат);
OPI_ПреобразованиеТипов.ПолучитьСтроку(ТекстЗапроса, Истина);
OPI_ПреобразованиеТипов.ПолучитьБулево(ФорсироватьРезультат);
Параметры_ = ОбработатьПараметры(Параметры);
Результат = OPI_ЗапросыSQL.ВыполнитьЗапросСОбработкой(Коннектор, ТекстЗапроса, ФорсироватьРезультат, Параметры_);
Если ЗакрыватьСоединение Тогда
ЗакрытьСоединение(Коннектор);
КонецЕсли;
Результат = OPI_Инструменты.JsonВСтруктуру(Результат);
Возврат Результат;
КонецФункции
@@ -544,27 +541,28 @@
Функция ОбработатьПараметры(Знач Параметры)
Если Не ЗначениеЗаполнено(Параметры) Тогда
Возврат "[]";
Возврат Новый Массив;
КонецЕсли;
Параметры_ = Новый Массив;
OPI_ПреобразованиеТипов.ПолучитьМассив(Параметры);
Для Н = 0 По Параметры.ВГраница() Цикл
Счетчик = 0;
Для Каждого Параметр Из Параметры Цикл
ТекущийПараметр = Параметры[Н];
ТекущийПараметр = ОбработатьПараметр(Параметр);
ТекущийПараметр = OPI_Инструменты.JSONСтрокой(ТекущийПараметр, , Ложь);
ТекущийПараметр = ОбработатьПараметр(ТекущийПараметр);
Если СтрНачинаетсяС(ТекущийПараметр, "НЕ JSON") Тогда
ВызватьИсключение СтрШаблон("Ошибка валидации JSON параметра. Индекс массив %1", Счетчик);
Иначе
Параметры_.Добавить(ТекущийПараметр);
КонецЕсли;
Параметры[Н] = ТекущийПараметр;
Счетчик = Счетчик + 1;
КонецЦикла;
Параметры_ = OPI_Инструменты.JSONСтрокой(Параметры, , Ложь);
Если СтрНачинаетсяС(Параметры_, "НЕ JSON") Тогда
ВызватьИсключение "Ошибка валидации JSON массива параметров!";
КонецЕсли;
Возврат Параметры_;
КонецФункции