Files
rustdesk/src/server/printer_service.rs
2025-03-28 21:58:46 +08:00

165 lines
5.0 KiB
Rust

use super::service::{EmptyExtraFieldService, GenericService, Service};
use hbb_common::{bail, dlopen::symbor::Library, log, ResultType};
use std::{
sync::{Arc, Mutex},
thread,
time::Duration,
};
pub const NAME: &'static str = "remote-printer";
const LIB_NAME_PRINTER_DRIVER_ADAPTER: &str = "printer_driver_adapter";
// Return 0 if success, otherwise return error code.
pub type Init = fn(tag_name: *const i8) -> i32;
pub type Uninit = fn();
// dur_mills: Get the file generated in the last `dur_mills` milliseconds.
// data: The raw prn data, xps format.
// data_len: The length of the raw prn data.
pub type GetPrnData = fn(dur_mills: u32, data: *mut *mut i8, data_len: *mut u32);
// Free the prn data allocated by GetPrnData().
pub type FreePrnData = fn(data: *mut i8);
macro_rules! make_lib_wrapper {
($($field:ident : $tp:ty),+) => {
struct LibWrapper {
_lib: Option<Library>,
$($field: Option<$tp>),+
}
impl LibWrapper {
fn new() -> Self {
let lib_name = match get_lib_name() {
Ok(name) => name,
Err(e) => {
log::warn!("Failed to get lib name, {}", e);
return Self {
_lib: None,
$( $field: None ),+
};
}
};
let lib = match Library::open(&lib_name) {
Ok(lib) => Some(lib),
Err(e) => {
log::warn!("Failed to load library {}, {}", &lib_name, e);
None
}
};
$(let $field = if let Some(lib) = &lib {
match unsafe { lib.symbol::<$tp>(stringify!($field)) } {
Ok(m) => {
log::info!("method found {}", stringify!($field));
Some(*m)
},
Err(e) => {
log::warn!("Failed to load func {}, {}", stringify!($field), e);
None
}
}
} else {
None
};)+
Self {
_lib: lib,
$( $field ),+
}
}
}
impl Default for LibWrapper {
fn default() -> Self {
Self::new()
}
}
}
}
make_lib_wrapper!(
init: Init,
uninit: Uninit,
get_prn_data: GetPrnData,
free_prn_data: FreePrnData
);
lazy_static::lazy_static! {
static ref LIB_WRAPPER: Arc<Mutex<LibWrapper>> = Default::default();
}
fn get_lib_name() -> ResultType<String> {
let exe_file = std::env::current_exe()?;
if let Some(cur_dir) = exe_file.parent() {
let dll_name = format!("{}.dll", LIB_NAME_PRINTER_DRIVER_ADAPTER);
let full_path = cur_dir.join(dll_name);
if !full_path.exists() {
bail!("{} not found", full_path.to_string_lossy().as_ref());
} else {
Ok(full_path.to_string_lossy().into_owned())
}
} else {
bail!(
"Invalid exe parent for {}",
exe_file.to_string_lossy().as_ref()
);
}
}
pub fn init(app_name: &str) -> ResultType<()> {
let lib_wrapper = LIB_WRAPPER.lock().unwrap();
let Some(fn_init) = lib_wrapper.init.as_ref() else {
bail!("Failed to load func init");
};
let tag_name = std::ffi::CString::new(app_name)?;
let ret = fn_init(tag_name.as_ptr());
if ret != 0 {
bail!("Failed to init printer driver");
}
Ok(())
}
pub fn uninit() {
let lib_wrapper = LIB_WRAPPER.lock().unwrap();
if let Some(fn_uninit) = lib_wrapper.uninit.as_ref() {
fn_uninit();
}
}
fn get_prn_data(dur_mills: u32) -> ResultType<Vec<u8>> {
let lib_wrapper = LIB_WRAPPER.lock().unwrap();
if let Some(fn_get_prn_data) = lib_wrapper.get_prn_data.as_ref() {
let mut data = std::ptr::null_mut();
let mut data_len = 0u32;
fn_get_prn_data(dur_mills, &mut data, &mut data_len);
if data.is_null() || data_len == 0 {
return Ok(Vec::new());
}
let bytes =
Vec::from(unsafe { std::slice::from_raw_parts(data as *const u8, data_len as usize) });
lib_wrapper.free_prn_data.map(|f| f(data));
Ok(bytes)
} else {
bail!("Failed to load func get_prn_file");
}
}
pub fn new(name: String) -> GenericService {
let svc = EmptyExtraFieldService::new(name, false);
GenericService::run(&svc.clone(), run);
svc.sp
}
fn run(sp: EmptyExtraFieldService) -> ResultType<()> {
while sp.ok() {
let bytes = get_prn_data(1000)?;
if !bytes.is_empty() {
log::info!("Got prn data, data len: {}", bytes.len());
crate::server::on_printer_data(bytes);
}
thread::sleep(Duration::from_millis(300));
}
Ok(())
}