You've already forked native_api_1c_core
macro development iteration
This commit is contained in:
12
Cargo.toml
12
Cargo.toml
@ -1,11 +1,8 @@
|
||||
[package]
|
||||
name = "addin"
|
||||
name = "native_api_1c"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lib]
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
# from https://github.com/johnthagen/min-sized-rust
|
||||
[profile.release]
|
||||
opt-level = "z" # Optimize for size.
|
||||
@ -15,9 +12,6 @@ panic = "abort" # Abort on panic
|
||||
strip = true # Automatically strip symbols from the binary.
|
||||
|
||||
[dependencies]
|
||||
base64 = "0.21.2"
|
||||
color-eyre = "0.6.2"
|
||||
log = "0.4.19"
|
||||
log4rs = "1.2.0"
|
||||
ureq = "2.7.1"
|
||||
utf16_lit = "2.0"
|
||||
syn = { version = "2.0.28", features = ["full"] }
|
||||
quote = "1.0.32"
|
||||
|
@ -1,321 +0,0 @@
|
||||
use crate::ffi::{
|
||||
connection::Connection,
|
||||
types::{ParamValue, ReturnValue},
|
||||
utils::{from_os_string, os_string_nil},
|
||||
};
|
||||
use color_eyre::eyre::Result;
|
||||
|
||||
pub struct ComponentPropDescription {
|
||||
pub names: &'static [&'static str; 2],
|
||||
pub readable: bool,
|
||||
pub writable: bool,
|
||||
}
|
||||
|
||||
pub struct ComponentFuncDescription {
|
||||
pub names: &'static [&'static str; 2],
|
||||
pub params_count: usize,
|
||||
pub returns_val: bool,
|
||||
pub default_values: &'static [Option<ParamValue>],
|
||||
}
|
||||
impl ComponentFuncDescription {
|
||||
pub fn new<const PARAMS_COUNT: usize>(
|
||||
names: &'static [&'static str; 2],
|
||||
returns_val: bool,
|
||||
default_values: &'static [Option<ParamValue>; PARAMS_COUNT],
|
||||
) -> Self {
|
||||
Self {
|
||||
names,
|
||||
params_count: PARAMS_COUNT,
|
||||
returns_val,
|
||||
default_values,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait AddIn {
|
||||
fn init(&mut self, interface: &'static Connection) -> bool;
|
||||
fn add_in_name(&self) -> &'static [u16];
|
||||
fn list_parameters(&self) -> Vec<&ComponentPropDescription> {
|
||||
Vec::new()
|
||||
}
|
||||
fn list_functions(&self) -> Vec<&ComponentFuncDescription> {
|
||||
Vec::new()
|
||||
}
|
||||
fn get_parameter(&self, _name: &str) -> Option<ParamValue> {
|
||||
None
|
||||
}
|
||||
fn set_parameter(&mut self, _name: &str, _value: &ParamValue) -> bool {
|
||||
false
|
||||
}
|
||||
fn call_function(
|
||||
&mut self,
|
||||
_name: &str,
|
||||
_params: &[ParamValue],
|
||||
) -> Result<Option<ParamValue>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AddInContainer<T: AddIn> {
|
||||
add_in: T,
|
||||
}
|
||||
|
||||
impl<T: AddIn> AddInContainer<T> {
|
||||
pub fn new(add_in: T) -> Self {
|
||||
Self { add_in }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AddIn> AddInWrapper for AddInContainer<T> {
|
||||
fn init(&mut self, interface: &'static Connection) -> bool {
|
||||
self.add_in.init(interface)
|
||||
}
|
||||
|
||||
/// default 2000, don't use version 1000, because static objects are created
|
||||
fn get_info(&self) -> u16 {
|
||||
2000
|
||||
}
|
||||
|
||||
fn done(&mut self) {}
|
||||
|
||||
fn register_extension_as(&mut self) -> &'static [u16] {
|
||||
self.add_in.add_in_name()
|
||||
}
|
||||
|
||||
fn get_n_props(&self) -> usize {
|
||||
self.add_in.list_parameters().len()
|
||||
}
|
||||
|
||||
fn find_prop(&self, name: &[u16]) -> Option<usize> {
|
||||
let name_str = from_os_string(name);
|
||||
self.add_in
|
||||
.list_parameters()
|
||||
.iter()
|
||||
.position(|x| x.names.iter().any(|y| y == &name_str))
|
||||
}
|
||||
|
||||
fn get_prop_name(&self, num: usize, alias: usize) -> Option<Vec<u16>> {
|
||||
self.add_in
|
||||
.list_parameters()
|
||||
.get(num)
|
||||
.map(|x| os_string_nil(x.names[alias]))
|
||||
}
|
||||
|
||||
fn get_prop_val(&self, num: usize, val: ReturnValue) -> bool {
|
||||
let param_desc_binding = self.add_in.list_parameters();
|
||||
let Some(param_desc) = param_desc_binding.get(num) else {
|
||||
return false
|
||||
};
|
||||
if !param_desc.readable {
|
||||
return false;
|
||||
};
|
||||
|
||||
let Some(param_data) = self.add_in.get_parameter(param_desc.names[0]) else {
|
||||
return false
|
||||
};
|
||||
|
||||
match param_data {
|
||||
ParamValue::I32(data_unwrapped) => val.set_i32(data_unwrapped),
|
||||
ParamValue::Bool(data_unwrapped) => val.set_bool(data_unwrapped),
|
||||
ParamValue::F64(data_unwrapped) => val.set_f64(data_unwrapped),
|
||||
ParamValue::Date(data_unwrapped) => val.set_date(data_unwrapped),
|
||||
ParamValue::Str(data_unwrapped) => val.set_str(&data_unwrapped),
|
||||
ParamValue::Blob(data_unwrapped) => val.set_blob(&data_unwrapped),
|
||||
ParamValue::Empty => val.set_empty(),
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool {
|
||||
let param_desc_binding = self.add_in.list_parameters();
|
||||
let Some(param_desc) = param_desc_binding.get(num) else {
|
||||
return false
|
||||
};
|
||||
|
||||
if !param_desc.writable {
|
||||
return false;
|
||||
};
|
||||
|
||||
self.add_in.set_parameter(param_desc.names[0], val)
|
||||
}
|
||||
|
||||
fn is_prop_readable(&self, num: usize) -> bool {
|
||||
let param_desc_binding = self.add_in.list_parameters();
|
||||
let Some(param_desc) = param_desc_binding.get(num) else {
|
||||
return false
|
||||
};
|
||||
param_desc.readable
|
||||
}
|
||||
|
||||
fn is_prop_writable(&self, num: usize) -> bool {
|
||||
let param_desc_binding = self.add_in.list_parameters();
|
||||
let Some(param_desc) = param_desc_binding.get(num) else {
|
||||
return false
|
||||
};
|
||||
param_desc.writable
|
||||
}
|
||||
|
||||
fn get_n_methods(&self) -> usize {
|
||||
self.add_in.list_functions().len()
|
||||
}
|
||||
|
||||
fn find_method(&self, name: &[u16]) -> Option<usize> {
|
||||
let name_str = from_os_string(name);
|
||||
self.add_in
|
||||
.list_functions()
|
||||
.iter()
|
||||
.position(|x| x.names.iter().any(|y| y == &name_str))
|
||||
}
|
||||
|
||||
fn get_method_name(&self, num: usize, alias: usize) -> Option<Vec<u16>> {
|
||||
self.add_in
|
||||
.list_functions()
|
||||
.get(num)
|
||||
.map(|x| os_string_nil(x.names[alias]))
|
||||
}
|
||||
|
||||
fn get_n_params(&self, num: usize) -> usize {
|
||||
let binding = self.add_in.list_functions();
|
||||
let Some(func_desc) = binding.get(num) else {
|
||||
return 0
|
||||
};
|
||||
func_desc.params_count
|
||||
}
|
||||
|
||||
fn get_param_def_value(
|
||||
&self,
|
||||
method_num: usize,
|
||||
param_num: usize,
|
||||
value: ReturnValue,
|
||||
) -> bool {
|
||||
let func_desc_binding = self.add_in.list_functions();
|
||||
let Some(func_desc) = func_desc_binding.get(method_num) else {
|
||||
return false
|
||||
};
|
||||
let Some(default_value_option) = func_desc.default_values.get(param_num) else {
|
||||
return false
|
||||
};
|
||||
let Some(default_value) = default_value_option else {
|
||||
return false
|
||||
};
|
||||
|
||||
match default_value {
|
||||
ParamValue::Bool(data) => value.set_bool(*data),
|
||||
ParamValue::I32(data) => value.set_i32(*data),
|
||||
ParamValue::F64(data) => value.set_f64(*data),
|
||||
ParamValue::Date(data) => value.set_date(*data),
|
||||
ParamValue::Str(data) => value.set_str(data),
|
||||
ParamValue::Blob(data) => value.set_blob(data),
|
||||
ParamValue::Empty => value.set_empty(),
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
fn has_ret_val(&self, method_num: usize) -> bool {
|
||||
let func_desc_binding = self.add_in.list_functions();
|
||||
let Some(func_desc) = func_desc_binding.get(method_num) else {
|
||||
return false
|
||||
};
|
||||
func_desc.returns_val
|
||||
}
|
||||
|
||||
fn call_as_proc(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &[ParamValue],
|
||||
) -> bool {
|
||||
let func_desc_binding = self.add_in.list_functions();
|
||||
let Some(func_desc) = func_desc_binding.get(method_num) else {
|
||||
return false
|
||||
};
|
||||
|
||||
let _call_result =
|
||||
match self.add_in.call_function(func_desc.names[0], params) {
|
||||
Ok(r) => r,
|
||||
Err(err) => {
|
||||
log::error!("Error: {}", err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
true
|
||||
}
|
||||
|
||||
fn call_as_func(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &[ParamValue],
|
||||
val: ReturnValue,
|
||||
) -> bool {
|
||||
let func_desc_binding = self.add_in.list_functions();
|
||||
let Some(func_desc) = func_desc_binding.get(method_num) else {
|
||||
return false
|
||||
};
|
||||
if !func_desc.returns_val {
|
||||
return false;
|
||||
}
|
||||
|
||||
let call_result =
|
||||
match self.add_in.call_function(func_desc.names[0], params) {
|
||||
Ok(r) => r,
|
||||
Err(err) => {
|
||||
log::error!("Error: {}", err);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
let Some(return_value) = call_result else {return false};
|
||||
match return_value {
|
||||
ParamValue::Bool(data) => val.set_bool(data),
|
||||
ParamValue::I32(data) => val.set_i32(data),
|
||||
ParamValue::F64(data) => val.set_f64(data),
|
||||
ParamValue::Date(data) => val.set_date(data),
|
||||
ParamValue::Str(data) => val.set_str(&data),
|
||||
ParamValue::Blob(data) => val.set_blob(&data),
|
||||
ParamValue::Empty => val.set_empty(),
|
||||
}
|
||||
true
|
||||
}
|
||||
fn set_locale(&mut self, _loc: &[u16]) {}
|
||||
fn set_user_interface_language_code(&mut self, _lang: &[u16]) {}
|
||||
}
|
||||
|
||||
pub trait AddInWrapper {
|
||||
fn init(&mut self, interface: &'static Connection) -> bool;
|
||||
|
||||
/// default 2000, don't use version 1000, because static objects are created
|
||||
fn get_info(&self) -> u16 {
|
||||
2000
|
||||
}
|
||||
fn done(&mut self);
|
||||
fn register_extension_as(&mut self) -> &[u16];
|
||||
fn get_n_props(&self) -> usize;
|
||||
fn find_prop(&self, name: &[u16]) -> Option<usize>;
|
||||
fn get_prop_name(&self, num: usize, alias: usize) -> Option<Vec<u16>>;
|
||||
fn get_prop_val(&self, num: usize, val: ReturnValue) -> bool;
|
||||
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool;
|
||||
fn is_prop_readable(&self, num: usize) -> bool;
|
||||
fn is_prop_writable(&self, num: usize) -> bool;
|
||||
fn get_n_methods(&self) -> usize;
|
||||
fn find_method(&self, name: &[u16]) -> Option<usize>;
|
||||
fn get_method_name(&self, num: usize, alias: usize) -> Option<Vec<u16>>;
|
||||
fn get_n_params(&self, num: usize) -> usize;
|
||||
fn get_param_def_value(
|
||||
&self,
|
||||
method_num: usize,
|
||||
param_num: usize,
|
||||
value: ReturnValue,
|
||||
) -> bool;
|
||||
fn has_ret_val(&self, method_num: usize) -> bool;
|
||||
fn call_as_proc(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &[ParamValue],
|
||||
) -> bool;
|
||||
fn call_as_func(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &[ParamValue],
|
||||
val: ReturnValue,
|
||||
) -> bool;
|
||||
fn set_locale(&mut self, loc: &[u16]);
|
||||
fn set_user_interface_language_code(&mut self, lang: &[u16]);
|
||||
}
|
@ -4,11 +4,7 @@ use std::{
|
||||
};
|
||||
use utf16_lit::utf16_null;
|
||||
|
||||
use crate::{
|
||||
add_in::AddInContainer,
|
||||
ffi::{create_component, destroy_component, AttachType},
|
||||
init_my_add_in,
|
||||
};
|
||||
use crate::ffi::{destroy_component, AttachType};
|
||||
|
||||
pub static mut PLATFORM_CAPABILITIES: AtomicI32 = AtomicI32::new(-1);
|
||||
|
||||
@ -18,13 +14,7 @@ pub unsafe extern "C" fn GetClassObject(
|
||||
name: *const u16,
|
||||
component: *mut *mut c_void,
|
||||
) -> c_long {
|
||||
match *name as u8 {
|
||||
b'1' => {
|
||||
let my_add_in_container = AddInContainer::new(init_my_add_in());
|
||||
create_component(component, my_add_in_container)
|
||||
}
|
||||
_ => 0,
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::ffi::c_long;
|
||||
|
||||
use super::{connection::Connection, memory_manager::MemoryManager, This};
|
||||
use crate::add_in::AddInWrapper;
|
||||
use crate::interface::AddInWrapper;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct InitDoneBaseVTable<T: AddInWrapper> {
|
||||
|
@ -4,7 +4,7 @@ use std::{
|
||||
slice::from_raw_parts,
|
||||
};
|
||||
|
||||
use crate::add_in::AddInWrapper;
|
||||
use crate::interface::AddInWrapper;
|
||||
|
||||
use super::{
|
||||
get_str,
|
||||
|
@ -3,7 +3,7 @@ use std::{
|
||||
ptr,
|
||||
};
|
||||
|
||||
use crate::add_in::AddInWrapper;
|
||||
use crate::interface::AddInWrapper;
|
||||
|
||||
use self::{
|
||||
init_base::InitDoneBaseVTable, lang_extender::LanguageExtenderBaseVTable,
|
||||
|
46
src/interface.rs
Normal file
46
src/interface.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use crate::ffi::{
|
||||
connection::Connection,
|
||||
types::{ParamValue, ReturnValue},
|
||||
};
|
||||
|
||||
pub trait AddInWrapper {
|
||||
fn init(&mut self, interface: &'static Connection) -> bool;
|
||||
|
||||
/// default 2000, don't use version 1000, because static objects are created
|
||||
fn get_info(&self) -> u16 {
|
||||
2000
|
||||
}
|
||||
fn done(&mut self);
|
||||
fn register_extension_as(&mut self) -> &[u16];
|
||||
fn get_n_props(&self) -> usize;
|
||||
fn find_prop(&self, name: &[u16]) -> Option<usize>;
|
||||
fn get_prop_name(&self, num: usize, alias: usize) -> Option<Vec<u16>>;
|
||||
fn get_prop_val(&self, num: usize, val: ReturnValue) -> bool;
|
||||
fn set_prop_val(&mut self, num: usize, val: &ParamValue) -> bool;
|
||||
fn is_prop_readable(&self, num: usize) -> bool;
|
||||
fn is_prop_writable(&self, num: usize) -> bool;
|
||||
fn get_n_methods(&self) -> usize;
|
||||
fn find_method(&self, name: &[u16]) -> Option<usize>;
|
||||
fn get_method_name(&self, num: usize, alias: usize) -> Option<Vec<u16>>;
|
||||
fn get_n_params(&self, num: usize) -> usize;
|
||||
fn get_param_def_value(
|
||||
&self,
|
||||
method_num: usize,
|
||||
param_num: usize,
|
||||
value: ReturnValue,
|
||||
) -> bool;
|
||||
fn has_ret_val(&self, method_num: usize) -> bool;
|
||||
fn call_as_proc(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &[ParamValue],
|
||||
) -> bool;
|
||||
fn call_as_func(
|
||||
&mut self,
|
||||
method_num: usize,
|
||||
params: &[ParamValue],
|
||||
val: ReturnValue,
|
||||
) -> bool;
|
||||
fn set_locale(&mut self, loc: &[u16]);
|
||||
fn set_user_interface_language_code(&mut self, lang: &[u16]);
|
||||
}
|
14
src/lib.rs
14
src/lib.rs
@ -1,11 +1,3 @@
|
||||
pub mod add_in;
|
||||
mod export_functions;
|
||||
mod ffi;
|
||||
mod my_add_in;
|
||||
|
||||
use add_in::AddIn;
|
||||
use my_add_in::MyAddInDescription;
|
||||
|
||||
pub fn init_my_add_in() -> impl AddIn {
|
||||
MyAddInDescription::new()
|
||||
}
|
||||
pub mod export_functions;
|
||||
pub mod ffi;
|
||||
pub mod interface;
|
||||
|
@ -1,181 +0,0 @@
|
||||
use super::MyAddInDescription;
|
||||
use crate::add_in::ComponentFuncDescription;
|
||||
use crate::ffi::connection::Error;
|
||||
use crate::ffi::utils::os_string;
|
||||
use crate::ffi::{types::ParamValue, utils::from_os_string};
|
||||
use base64::{engine::general_purpose, Engine as _};
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use log::LevelFilter;
|
||||
use log4rs::{
|
||||
append::file::FileAppender,
|
||||
config::{Appender, Root},
|
||||
encode::pattern::PatternEncoder,
|
||||
Config,
|
||||
};
|
||||
use std::{path::PathBuf, thread, time::Duration};
|
||||
|
||||
pub struct FunctionListElement {
|
||||
pub description: ComponentFuncDescription,
|
||||
pub callback: fn(
|
||||
&mut MyAddInDescription,
|
||||
&[ParamValue],
|
||||
) -> Result<Option<ParamValue>>,
|
||||
}
|
||||
|
||||
impl MyAddInDescription {
|
||||
pub fn generate_func_list() -> Vec<FunctionListElement> {
|
||||
vec![
|
||||
FunctionListElement {
|
||||
description: ComponentFuncDescription::new::<0>(
|
||||
&["Итерировать", "Iterate"],
|
||||
false,
|
||||
&[],
|
||||
),
|
||||
callback: Self::iterate,
|
||||
},
|
||||
FunctionListElement {
|
||||
description: ComponentFuncDescription::new::<1>(
|
||||
&["Таймер", "Timer"],
|
||||
true,
|
||||
&[Some(ParamValue::I32(1000))],
|
||||
),
|
||||
callback: Self::timer,
|
||||
},
|
||||
FunctionListElement {
|
||||
description: ComponentFuncDescription::new::<0>(
|
||||
&["ПолучитьХэТэТэПэ", "FetchHTTP"],
|
||||
true,
|
||||
&[],
|
||||
),
|
||||
callback: Self::fetch,
|
||||
},
|
||||
FunctionListElement {
|
||||
description: ComponentFuncDescription::new::<1>(
|
||||
&["ПолучитьХэТэТэПэПараллельно", "FetchHTTPConcurrently"],
|
||||
true,
|
||||
&[None],
|
||||
),
|
||||
callback: Self::concurrent_fetch,
|
||||
},
|
||||
FunctionListElement {
|
||||
description: ComponentFuncDescription::new::<1>(
|
||||
&[("ИнициализироватьЛоггер"), ("InitLogger")],
|
||||
false,
|
||||
&[None],
|
||||
),
|
||||
callback: Self::init_logger,
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
fn iterate(
|
||||
&mut self,
|
||||
_params: &[ParamValue],
|
||||
) -> Result<Option<ParamValue>> {
|
||||
if self.some_prop_container >= 105 {
|
||||
return Err(eyre!("Prop is too big"));
|
||||
}
|
||||
self.some_prop_container += 1;
|
||||
log::info!("Prop is now {}", self.some_prop_container);
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn timer(&mut self, params: &[ParamValue]) -> Result<Option<ParamValue>> {
|
||||
let sleep_duration_ms = match params.get(0) {
|
||||
Some(ParamValue::I32(val)) => *val,
|
||||
_ => return Err(eyre!("Invalid parameter")),
|
||||
};
|
||||
if sleep_duration_ms < 0 {
|
||||
return Err(eyre!("Invalid parameter"));
|
||||
}
|
||||
if sleep_duration_ms > 100000 {
|
||||
return Err(eyre!("Too long"));
|
||||
}
|
||||
let sleep_duration_ms = sleep_duration_ms as u64;
|
||||
|
||||
let connection = self.connection.clone();
|
||||
let name = from_os_string(self.name);
|
||||
thread::spawn(move || {
|
||||
log::info!("Timer started");
|
||||
thread::sleep(Duration::from_millis(sleep_duration_ms));
|
||||
log::info!("Timer ended");
|
||||
if let Some(connection) = &*connection {
|
||||
connection.external_event(&name, "TimerEnd", "OK");
|
||||
connection.add_error(Error::DialogInfo, "Timer", "Time's up");
|
||||
}
|
||||
});
|
||||
|
||||
Ok(Some(ParamValue::I32(sleep_duration_ms as i32)))
|
||||
}
|
||||
|
||||
fn fetch(&mut self, _params: &[ParamValue]) -> Result<Option<ParamValue>> {
|
||||
let Ok(result) = ureq::post("https://echo.hoppscotch.io").send_string("smth") else {return Err(eyre!("Failed to fetch"));};
|
||||
let Ok(body) = result.into_string() else { return Err(eyre!("Failed to get body"));};
|
||||
Ok(Some(ParamValue::Str(os_string(&body))))
|
||||
}
|
||||
|
||||
fn concurrent_fetch(
|
||||
&mut self,
|
||||
params: &[ParamValue],
|
||||
) -> Result<Option<ParamValue>> {
|
||||
let request_count = match params.get(0) {
|
||||
Some(ParamValue::I32(val)) => *val,
|
||||
_ => return Err(eyre!("Invalid parameter")),
|
||||
};
|
||||
if request_count < 0 {
|
||||
return Err(eyre!("Invalid parameter"));
|
||||
}
|
||||
let request_count = request_count as u64;
|
||||
|
||||
let mut threads_handles = Vec::new();
|
||||
for _ in 0..request_count {
|
||||
let handle = thread::spawn(move || {
|
||||
let Ok(result) = ureq::post("https://echo.hoppscotch.io").send_string("smth") else {return Err(eyre!("Failed to fetch"));};
|
||||
let Ok(body) = result.into_string() else { return Err(eyre!("Failed to get body"));};
|
||||
Ok(body)
|
||||
});
|
||||
threads_handles.push(handle);
|
||||
}
|
||||
let results: Vec<String> = threads_handles
|
||||
.into_iter()
|
||||
.map(|h| -> String {
|
||||
let Ok(req_result) =
|
||||
h.join() else { return format!("ERR")};
|
||||
let Ok(req_text) = req_result else { return format!("ERR")};
|
||||
let base64_text =
|
||||
general_purpose::STANDARD_NO_PAD.encode(req_text);
|
||||
base64_text
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(Some(ParamValue::Str(os_string(&results.join(";")))))
|
||||
}
|
||||
|
||||
fn init_logger(
|
||||
&mut self,
|
||||
params: &[ParamValue],
|
||||
) -> Result<Option<ParamValue>> {
|
||||
let log_file_path = match params.get(0) {
|
||||
Some(ParamValue::Str(val)) => from_os_string(val),
|
||||
_ => return Err(eyre!("Invalid parameter")),
|
||||
};
|
||||
let log_file_path = PathBuf::from(log_file_path);
|
||||
if log_file_path.is_dir() {
|
||||
return Err(eyre!("Need a file path"));
|
||||
};
|
||||
|
||||
let log_file_appender = FileAppender::builder()
|
||||
.encoder(Box::new(PatternEncoder::new("{d} - {m}{n}")))
|
||||
.build(log_file_path)?;
|
||||
|
||||
let config = Config::builder()
|
||||
.appender(
|
||||
Appender::builder().build("file", Box::new(log_file_appender)),
|
||||
)
|
||||
.build(Root::builder().appender("file").build(LevelFilter::Info))?;
|
||||
|
||||
self.log_handle = Some(log4rs::init_config(config)?);
|
||||
log::info!("Logger initialized");
|
||||
Ok(None)
|
||||
}
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
mod func;
|
||||
mod props;
|
||||
|
||||
use crate::add_in::{
|
||||
AddIn, ComponentFuncDescription, ComponentPropDescription,
|
||||
};
|
||||
use crate::ffi::{connection::Connection, types::ParamValue};
|
||||
use color_eyre::eyre::{eyre, Result};
|
||||
use std::sync::Arc;
|
||||
use utf16_lit::utf16_null;
|
||||
|
||||
use self::func::FunctionListElement;
|
||||
use self::props::PropListElement;
|
||||
|
||||
pub struct MyAddInDescription {
|
||||
name: &'static [u16],
|
||||
connection: Arc<Option<&'static Connection>>,
|
||||
log_handle: Option<log4rs::Handle>,
|
||||
|
||||
functions: Vec<FunctionListElement>,
|
||||
props: Vec<PropListElement>,
|
||||
some_prop_container: i32,
|
||||
}
|
||||
|
||||
impl MyAddInDescription {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
name: &utf16_null!("MyAddIn"),
|
||||
connection: Arc::new(None),
|
||||
log_handle: None,
|
||||
functions: Self::generate_func_list(),
|
||||
props: Self::generate_prop_list(),
|
||||
|
||||
some_prop_container: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AddIn for MyAddInDescription {
|
||||
fn init(&mut self, interface: &'static Connection) -> bool {
|
||||
interface.set_event_buffer_depth(10);
|
||||
self.connection = Arc::new(Some(interface));
|
||||
self.some_prop_container = 100;
|
||||
true
|
||||
}
|
||||
|
||||
fn add_in_name(&self) -> &'static [u16] {
|
||||
self.name
|
||||
}
|
||||
|
||||
fn call_function(
|
||||
&mut self,
|
||||
name: &str,
|
||||
params: &[ParamValue],
|
||||
) -> Result<Option<ParamValue>> {
|
||||
let func = self
|
||||
.functions
|
||||
.iter()
|
||||
.find(|el| el.description.names.iter().any(|n| n == &name));
|
||||
|
||||
let Some(func) = func.map(|el| el.callback) else { return Err(eyre!("No function with such name")) };
|
||||
func(self, params)
|
||||
}
|
||||
|
||||
fn get_parameter(&self, name: &str) -> Option<ParamValue> {
|
||||
let prop = self
|
||||
.props
|
||||
.iter()
|
||||
.find(|el| el.description.names.iter().any(|n| n == &name));
|
||||
let Some(Some(get)) = prop.map(|el| el.get_callback) else { return None };
|
||||
get(self)
|
||||
}
|
||||
|
||||
fn set_parameter(&mut self, name: &str, value: &ParamValue) -> bool {
|
||||
let prop = self
|
||||
.props
|
||||
.iter()
|
||||
.find(|el| el.description.names.iter().any(|n| n == &name));
|
||||
let Some(Some(set)) = prop.map(|el| el.set_callback) else { return false };
|
||||
set(self, value)
|
||||
}
|
||||
|
||||
fn list_functions(&self) -> Vec<&ComponentFuncDescription> {
|
||||
self.functions.iter().map(|el| &el.description).collect()
|
||||
}
|
||||
|
||||
fn list_parameters(&self) -> Vec<&ComponentPropDescription> {
|
||||
self.props.iter().map(|el| &el.description).collect()
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
use crate::{add_in::ComponentPropDescription, ffi::types::ParamValue};
|
||||
|
||||
use super::MyAddInDescription;
|
||||
|
||||
pub struct PropListElement {
|
||||
pub description: ComponentPropDescription,
|
||||
pub get_callback: Option<fn(&MyAddInDescription) -> Option<ParamValue>>,
|
||||
pub set_callback: Option<fn(&mut MyAddInDescription, &ParamValue) -> bool>,
|
||||
}
|
||||
|
||||
impl MyAddInDescription {
|
||||
pub fn generate_prop_list() -> Vec<PropListElement> {
|
||||
vec![PropListElement {
|
||||
description: ComponentPropDescription {
|
||||
names: &["Property", "Свойство"],
|
||||
readable: true,
|
||||
writable: true,
|
||||
},
|
||||
get_callback: Some(Self::get_prop),
|
||||
set_callback: Some(Self::set_prop),
|
||||
}]
|
||||
}
|
||||
|
||||
fn get_prop(&self) -> Option<ParamValue> {
|
||||
Some(ParamValue::I32(self.some_prop_container))
|
||||
}
|
||||
|
||||
fn set_prop(&mut self, value: &ParamValue) -> bool {
|
||||
match value {
|
||||
ParamValue::I32(val) => {
|
||||
self.some_prop_container = *val;
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user