diff --git a/.gitignore b/.gitignore index b872144c1f..dce515cf62 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ target/ !oscript.exe addin.zip src/addins/tcp_server/OPI_TCPServer.zip +src/addins/sqlite/OPI_SQLite.zip diff --git a/src/addins/sqlite/Cargo.lock b/src/addins/sqlite/Cargo.lock new file mode 100644 index 0000000000..3be5158974 --- /dev/null +++ b/src/addins/sqlite/Cargo.lock @@ -0,0 +1,275 @@ +# 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 = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cc" +version = "1.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + +[[package]] +name = "fallible-streaming-iterator" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashlink" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" +dependencies = [ + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" + +[[package]] +name = "libsqlite3-sys" +version = "0.30.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149" +dependencies = [ + "cc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "opi_sqlite" +version = "0.1.0" +dependencies = [ + "addin1c", + "base64", + "rusqlite", + "serde_json", + "serde_rusqlite", +] + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[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.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rusqlite" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e" +dependencies = [ + "bitflags", + "fallible-iterator", + "fallible-streaming-iterator", + "hashlink", + "libsqlite3-sys", + "smallvec", +] + +[[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.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.217" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.134" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00f4175c42ee48b15416f6193a959ba3a0d67fc699a0db9ad12df9f83991c7d" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_rusqlite" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b741cc5ef185cd96157e762c3bba743c4e94c8dc6af0edb053c48d2b3c27e691" +dependencies = [ + "rusqlite", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[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.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ae51629bf965c5c098cc9e87908a3df5301051a9e087d6f9bef5c9771ed126" +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" + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/src/addins/sqlite/Cargo.toml b/src/addins/sqlite/Cargo.toml new file mode 100644 index 0000000000..7689397d55 --- /dev/null +++ b/src/addins/sqlite/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "opi_sqlite" +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" +rusqlite = { version = "0.32.1", features = ["bundled"]} +serde_json = "1.0" +serde_rusqlite = "0.36.0" +base64 = "0.22.1" \ No newline at end of file diff --git a/src/addins/sqlite/MANIFEST.XML b/src/addins/sqlite/MANIFEST.XML new file mode 100644 index 0000000000..eb28e4669f --- /dev/null +++ b/src/addins/sqlite/MANIFEST.XML @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/addins/sqlite/release.bat b/src/addins/sqlite/release.bat new file mode 100644 index 0000000000..ca42221645 --- /dev/null +++ b/src/addins/sqlite/release.bat @@ -0,0 +1,69 @@ +@echo off + +:: Установить переменную +set CARGO_NAME=opi_sqlite +set LIB_NAME=OPI_SQLite +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\%CARGO_NAME%.dll "%OUTPUT_DIR%\AddIn_x64_windows.dll" +if errorlevel 1 goto :error + +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%CARGO_NAME%.so "%OUTPUT_DIR%\AddIn_x64_linux.so" +if errorlevel 1 goto :error + +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" +if errorlevel 1 goto :error + +:: Архивация +powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%LIB_NAME%.zip'" +if errorlevel 1 goto :error + +copy /y "%LIB_NAME%.zip" "../../ru/OInt/addins/%LIB_NAME%.zip" +copy /y "%LIB_NAME%.zip" "../../en/OInt/addins/%LIB_NAME%.zip" + +copy /y "%LIB_NAME%.zip" "../../ru/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin" +copy /y "%LIB_NAME%.zip" "../../en/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin" + +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 diff --git a/src/addins/sqlite/src/component/methods.rs b/src/addins/sqlite/src/component/methods.rs new file mode 100644 index 0000000000..5e94977757 --- /dev/null +++ b/src/addins/sqlite/src/component/methods.rs @@ -0,0 +1,126 @@ +use rusqlite::{types::ValueRef}; +use serde_json::{Value, json, Map}; +use crate::component; +use serde_rusqlite::{to_params}; +use base64::{engine::general_purpose, Engine as _}; + +pub fn execute_query( + client: &mut component::AddIn, + query: String, + params_json: String, +) -> String { + + let conn = match client.get_connection() { + Some(c) => c, + None => return r#"{"result": false, "error": "No connection initialized"}"#.to_string(), + }; + + // Парсинг JSON параметров + let parsed_params: Value = match serde_json::from_str(¶ms_json) { + Ok(params) => params, + Err(e) => { + return format!( + r#"{{"result": false, "error": "Invalid JSON parameters: {}"}}"#, + e.to_string() + ); + } + }; + + let params_array = match parsed_params.as_array() { + Some(array) => array, + None => { + return r#"{"result": false, "error": "Parameters must be a JSON array"}"#.to_string(); + } + }; + + + let convert = to_params(params_array).unwrap(); + + // Определяем тип запроса + if query.trim_start().to_uppercase().starts_with("SELECT") { + // Выполняем SELECT + match conn.prepare(&query) { + Ok(mut query_result) => { + + let cols: Vec = query_result + .column_names() + .iter() + .map(|name| name.to_string()) + .collect(); + + let res = query_result.query(convert); + + match res{ + Ok(mut rows) => { + rows_to_json_array(&mut rows, &cols) + } + Err(e) => { + format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string()) + } + } + + } + Err(e) => { + format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string()) + } + } + } else { + + match conn.execute(&query, convert) { + Ok(_) => r#"{"result": true}"#.to_string(), + Err(e) => format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string()), + } + } +} + +fn rows_to_json_array(rows: &mut rusqlite::Rows, cols: &Vec) -> String { + + let mut json_array = Vec::new(); + + loop { + + let mut current: Map = Map::new(); + + match rows.next() { + + Ok(Some(row)) => { + + for i in 0..cols.len() { + + let val = row.get_ref_unwrap(i); + let jval = from_sql_to_json(val); + + current.insert(cols[i].to_string(), jval); + }; + + json_array.push(current); + + } + + Ok(None) => break, + Err(e) => { + current.insert("error".to_string(), Value::String(e.to_string())); + } + + } + } + + json!(json_array).to_string() +} + +fn from_sql_to_json(value: ValueRef) -> Value { + match value { + ValueRef::Null => Value::Null, + ValueRef::Integer(i) => Value::Number(i.into()), + ValueRef::Real(f) => { + serde_json::Number::from_f64(f).map(Value::Number).unwrap_or(Value::Null) + } + ValueRef::Text(t) => Value::String(String::from_utf8_lossy(t).into_owned()), + ValueRef::Blob(b) => { + let base64_string = general_purpose::STANDARD.encode(b); // Кодируем в Base64 + let mut blob_object = serde_json::Map::new(); + blob_object.insert("blob".to_string(), Value::String(base64_string)); // Оборачиваем в объект + Value::Object(blob_object) + }, + } +} \ No newline at end of file diff --git a/src/addins/sqlite/src/component/mod.rs b/src/addins/sqlite/src/component/mod.rs new file mode 100644 index 0000000000..ca589d55fb --- /dev/null +++ b/src/addins/sqlite/src/component/mod.rs @@ -0,0 +1,108 @@ +mod methods; + +use addin1c::{name, Variant}; +use crate::core::getset; +use rusqlite::{Connection}; + +// МЕТОДЫ КОМПОНЕНТЫ ------------------------------------------------------------------------------- + +// Синонимы +pub const METHODS: &[&[u16]] = &[ + name!("Connect"), + name!("Execute"), // 0 + +]; + +// Число параметров функций компоненты +pub fn get_params_amount(num: usize) -> usize { + match num { + 0 => 0, + 1 => 2, + _ => 0, + } +} + +// Соответствие функций Rust функциям компоненты +// Вызовы должны быть обернуты в Box::new +pub fn cal_func(obj: &mut AddIn, num: usize, params: &mut [Variant]) -> Box { + + match num { + + 0 =>{ + Box::new(obj.initialize()) + }, + + 1 => { + + let query = params[0].get_string().unwrap_or("".to_string()); + let params_json = params[1].get_string().unwrap_or("".to_string()); + + Box::new(methods::execute_query(obj, query, params_json)) + }, + _ => Box::new(false), // Неверный номер команды + } + +} + +// ------------------------------------------------------------------------------------------------- + +// ПОЛЯ КОМПОНЕНТЫ --------------------------------------------------------------------------------- + +// Синонимы +pub const PROPS: &[&[u16]] = &[ + name!("Database") +]; + + +pub struct AddIn { + connection_string: String, + connection: Option, +} + +impl AddIn { + /// Создает новый объект + pub fn new() -> Self { + AddIn { + connection_string: String::new(), + connection: None, + } + } + + pub fn initialize(&mut self) -> String { + let conn_result = if self.connection_string.is_empty() { + Connection::open_in_memory() + } else { + Connection::open(&self.connection_string) + }; + + match conn_result { + Ok(conn) => { + self.connection = Some(conn); + r#"{"result": true}"#.to_string() + } + Err(e) => { + format!(r#"{{"result": false, "error": "{}"}}"#, e.to_string()) + } + } + } + + pub fn get_connection(&self) -> Option<&Connection> { + self.connection.as_ref() + } + + pub fn get_field_ptr(&self, index: usize) -> *const dyn getset::ValueType { + match index { + 0 => &self.connection_string 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) {} +} \ No newline at end of file diff --git a/src/addins/sqlite/src/core/getset.rs b/src/addins/sqlite/src/core/getset.rs new file mode 100644 index 0000000000..dfb6f65bc8 --- /dev/null +++ b/src/addins/sqlite/src/core/getset.rs @@ -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 = 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 +impl ValueType for Vec { + 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() + } +} \ No newline at end of file diff --git a/src/addins/sqlite/src/core/mod.rs b/src/addins/sqlite/src/core/mod.rs new file mode 100644 index 0000000000..9f8e10c39f --- /dev/null +++ b/src/addins/sqlite/src/core/mod.rs @@ -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 { + 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, _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 { 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 for AddIn { + type Output = dyn getset::ValueType; + + fn index(&self, index: usize) -> &Self::Output { + unsafe { &*self.get_field_ptr(index) } + } +} + +impl std::ops::IndexMut for AddIn { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + unsafe { &mut *self.get_field_ptr_mut(index) } + } +} + + diff --git a/src/addins/sqlite/src/lib.rs b/src/addins/sqlite/src/lib.rs new file mode 100644 index 0000000000..6b7c2f62a1 --- /dev/null +++ b/src/addins/sqlite/src/lib.rs @@ -0,0 +1,49 @@ +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] +#[allow(static_mut_refs)] +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 +} diff --git a/src/addins/tmpl/release.bat b/src/addins/tmpl/release.bat index 648eb36f3b..62534a5e06 100644 --- a/src/addins/tmpl/release.bat +++ b/src/addins/tmpl/release.bat @@ -1,7 +1,8 @@ @echo off :: Установить переменную -set LIB_NAME=opi_addin +set CARGO_NAME=opi_addin +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 @@ -31,26 +32,31 @@ 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" if errorlevel 1 goto :error :: Архивация -set ZIP_NAME=addin.zip -powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%ZIP_NAME%'" +powershell -Command "Compress-Archive -Path '%OUTPUT_DIR%\*' -Force -DestinationPath '%LIB_NAME%.zip'" if errorlevel 1 goto :error +copy /y "%LIB_NAME%.zip" "../../ru/OInt/addins/%LIB_NAME%.zip" +copy /y "%LIB_NAME%.zip" "../../en/OInt/addins/%LIB_NAME%.zip" + +copy /y "%LIB_NAME%.zip" "../../ru/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin" +copy /y "%LIB_NAME%.zip" "../../en/OPI/src/CommonTemplates/%LIB_NAME%/Template.addin" + if exist "%OUTPUT_DIR%" ( rmdir /S /Q "%OUTPUT_DIR%" ) diff --git a/src/addins/tmpl/src/core/mod.rs b/src/addins/tmpl/src/core/mod.rs index 1ab84b1e86..9f8e10c39f 100644 --- a/src/addins/tmpl/src/core/mod.rs +++ b/src/addins/tmpl/src/core/mod.rs @@ -24,13 +24,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 { 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) } diff --git a/src/addins/tmpl/src/lib.rs b/src/addins/tmpl/src/lib.rs index d08fdf4a06..f13725c068 100644 --- a/src/addins/tmpl/src/lib.rs +++ b/src/addins/tmpl/src/lib.rs @@ -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) @@ -35,6 +35,7 @@ pub extern "C" fn GetClassNames() -> *const u16 { } #[allow(non_snake_case)] +#[allow(static_mut_refs)] #[no_mangle] pub unsafe extern "C" fn SetPlatformCapabilities(capabilities: c_int) -> c_int { PLATFORM_CAPABILITIES.store(capabilities, Ordering::Relaxed); diff --git a/src/en/OInt/addins/OPI_SQLite.zip b/src/en/OInt/addins/OPI_SQLite.zip new file mode 100644 index 0000000000..6b8624c1ec Binary files /dev/null and b/src/en/OInt/addins/OPI_SQLite.zip differ diff --git a/src/ru/OInt/addins/OPI_SQLite.zip b/src/ru/OInt/addins/OPI_SQLite.zip new file mode 100644 index 0000000000..6b8624c1ec Binary files /dev/null and b/src/ru/OInt/addins/OPI_SQLite.zip differ diff --git a/src/ru/OPI/src/CommonTemplates/OPI_SQLite/OPI_SQLite.mdo b/src/ru/OPI/src/CommonTemplates/OPI_SQLite/OPI_SQLite.mdo new file mode 100644 index 0000000000..145767257c --- /dev/null +++ b/src/ru/OPI/src/CommonTemplates/OPI_SQLite/OPI_SQLite.mdo @@ -0,0 +1,9 @@ + + + OPI_SQLite + + ru + SQLite + + AddIn + diff --git a/src/ru/OPI/src/CommonTemplates/OPI_SQLite/Template.addin b/src/ru/OPI/src/CommonTemplates/OPI_SQLite/Template.addin new file mode 100644 index 0000000000..6b8624c1ec Binary files /dev/null and b/src/ru/OPI/src/CommonTemplates/OPI_SQLite/Template.addin differ diff --git a/src/ru/OPI/src/Configuration/Configuration.mdo b/src/ru/OPI/src/Configuration/Configuration.mdo index 0550a7374d..41168b860a 100644 --- a/src/ru/OPI/src/Configuration/Configuration.mdo +++ b/src/ru/OPI/src/Configuration/Configuration.mdo @@ -40,6 +40,7 @@ Subsystem.OPI_Интеграция CommonTemplate.OPI_TCPClient + CommonTemplate.OPI_SQLite CommonModule.OPI_Инструменты CommonModule.OPI_Криптография CommonModule.OPI_ПреобразованиеТипов