使用rust调用c++静态库并编译nodejs包

在项目上经常要用到身份证阅读器、护照阅读仪、指纹仪等各种品牌硬件,假如每套系统的都做集成开发那代码的维护成本将变得很高,为此采用rust来调用厂家提供的sdk c++开发包并封装成nodejs包,用fastify来开发成web api独立的服务形式。这样我们开发系统时只需调用web接口即可,跨平台又可共用,方便快捷,话不多说来看代码如何实现。

一、创建项目
安装rust后,打开vs新建一个工程目录,我们通过cargo new创建的一个package项目,加上--lib参数后创建的项目就是库项目(library package)。
cargo new --lib reader
package 就是一个项目,因此它包含有独立的 Cargo.toml 文件,用于项目配置。库项目只能作为三方库被其它项目引用,而不能独立运行,即src/lib.rs。
典型的package
如果一个 package 同时拥有 src/main.rs 和 src/lib.rs,那就意味着它包含两个包:库包和二进制包,这两个包名也都是 test_math —— 都与 package 同名。
一个真实项目中典型的 package,会包含多个二进制包,这些包文件被放在 src/bin 目录下,每一个文件都是独立的二进制包,同时也会包含一个库包,该包只能存在一个 src/lib.rs:
.
├── Cargo.toml
├── Cargo.lock
├── src
│ ├── main.rs
│ ├── lib.rs
│ └── bin
│ └── main1.rs
│ └── main2.rs
├── tests
│ └── some_integration_tests.rs
├── benches
│ └── simple_bench.rs
└── examples
└── simple_example.rs

唯一库包:src/lib.rs
默认二进制包:src/main.rs,编译后生成的可执行文件与package同名
其余二进制包:src/bin/main1.rs 和 src/bin/main2.rs,它们会分别生成一个文件同名的二进制可执行文件
集成测试文件:tests 目录下
性能测试benchmark文件:benches 目录下
项目示例:examples 目录下
这种目录结构基本上是 Rust 的标准目录结构,在 github 的大多数项目上,你都将看到它的身影。
运行Cargo build命令,我们在targetdebug目录下可以看到编译后的结果。
二、Cargo.toml

[package] name = "reader" version = "0.1.0" edition = "2018" exclude = ["reader.node"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html  [dependencies] libc = "0.2.9" libloading = "0.7" once_cell = "1.8" serde = { version = "1.0", features = ["derive"] } widestring = "0.5.1" serde_json = "1.0" base64 = "0.13" hex="0.4.2" encoding = "0.2" tokio={version="1.18.0",features = ["full"]}  [dependencies.neon] version = "0.9" default-features = false features = ["napi-5", "channel-api"]  [lib] crate-type = ["cdylib"] 

三、package.json

{   "name": "reader",   "version": "0.1.0",   "description": "",   "main": "index.node",   "scripts": {     "build": "cargo-cp-artifact -nc index.node -- cargo build --message-format=json-render-diagnostics",     "build-debug": "npm run build --",     "build-release": "npm run build -- --release",     "build_win32": "npm run build -- --release --target=i686-pc-windows-msvc",     "test": "cargo test",     "run": "cargo run"   },   "author": "",   "license": "ISC",   "devDependencies": {     "cargo-cp-artifact": "^0.1"   },   "dependencies": {     "express": "^4.17.3"   } } 

我们可以打印rust看看编译输出支持哪些架构
rustc --print target-list
//添加 x86编译链接器
rustup target add i686-pc-windows-msvc

四、代码分析

use std::collections::HashMap; use std::str; use std::fmt::Write; use std::io::{Error};  extern crate encoding; use encoding::all::GB18030; use encoding::{DecoderTrap,EncoderTrap,Encoding};  use tokio::time::{sleep, Duration,Instant}; use libc::{c_int, c_void}; use libloading::{Library, Symbol}; use neon::prelude::*; use once_cell::sync::OnceCell; use serde::{Deserialize, Serialize};  use widestring::{WideCStr, WideCString, WideChar}; // 编码转换 utf8 -> utf16le fn encode(source: &str) -> WideCString {     let string_source = source.to_string() + "";     WideCString::from_str(&string_source).unwrap() } // 解码转换 utf16le -> utf8 fn decode(source: &[WideChar]) -> String {     WideCStr::from_slice_truncate(source)         .unwrap()         .to_string()         .unwrap() } // 加载 dll static LIBRARY: OnceCell<Library> = OnceCell::new();  //指定编译架构 static MACHINE_KIND: &str = if cfg!(target_os = "windows") {     if cfg!(target_arch = "x86") {         "win32"     } else if cfg!(target_arch = "x86_x64") {         "win64"     } else {         "other"     } } else if cfg!(target_os = "linux") {     if cfg!(target_arch = "x86") {         "linux32"     } else if cfg!(target_arch = "x86_64") {         "linux64"     } else if cfg!(target_arch = "aarch64") {         "aarch64"     } else if cfg!(target_arch = "arm") {         "arm"     } else {         "other"     } } else {     "other" };  
//定义函数方法名,这里要根据c++库的函数名和参数来定义,函数名和参数类型务必要一致。 type LPCTSTR = *const WideChar; type BOOL = c_int; type INITPTR = *const i8; type CANRST = *mut WideChar;  // 打开设备 type S2V7_open = unsafe extern "system" fn() -> c_int; // 关闭设备 type S2V7_close = unsafe extern "system" fn() -> c_int;   //【set mode  设置读证功能】 type S2V7_set_mode =     unsafe extern "system" fn(flg_takeColor: c_int, flg_takeUV: c_int, flg_readChipInfo: c_int, flg_readChipFace: c_int) -> c_int; // Type = 0 即可  //【wait Doc. in 等待放卡】 type S2V7_wait_DocIn = unsafe extern "system" fn(timeout: f64, flg_in: INITPTR) -> c_int; // Type = 0 即可   //【wait Doc. out 等待拿卡】 type S2V7_wait_DocOut = unsafe extern "system" fn(timeout: f64, flg_out: INITPTR) -> c_int; // Type = 0 即可   //【process  执行读卡过程】 type S2V7_process = unsafe extern "system" fn() -> c_int;   //读取卡类型 type S2V7_get_cardType = unsafe extern "system" fn() -> c_int;  //保存彩照 type S2V7_VIS_saveColor = unsafe extern "system" fn(imgPath: LPCTSTR) -> c_int; //保存红外照 type S2V7_VIS_saveIR = unsafe extern "system" fn(imgPath: LPCTSTR) -> c_int;  //【get MRZ text 获取OCR文字信息】 type S2V7_VIS_getMRZtext = unsafe extern "system" fn(text: LPCTSTR) -> c_int;  //show text information  文字信息 type S2V7_RDO_getBytesByIndex = unsafe extern "system" fn(index: c_int,data: LPCTSTR) -> c_int; type S2V7_VIS_getBytesByIndex = unsafe extern "system" fn(index: c_int,data: LPCTSTR) -> c_int;  type S2V7_RF_active = unsafe extern "system" fn(antenna: c_int,atr: LPCTSTR, atr_len: c_int) -> c_int;  //构建函数实例 static V7_OPEN: OnceCell<Symbol<S2V7_open>> = OnceCell::new(); static V7_CLOSE: OnceCell<Symbol<S2V7_close>> = OnceCell::new(); static V7_SET_MODE: OnceCell<Symbol<S2V7_set_mode>> = OnceCell::new(); static V7_WAIT_DOCINT: OnceCell<Symbol<S2V7_wait_DocIn>> = OnceCell::new(); static V7_WAIT_DOCOUT: OnceCell<Symbol<S2V7_wait_DocOut>> = OnceCell::new(); static V7_PROCESS: OnceCell<Symbol<S2V7_process>> = OnceCell::new(); static V7_GET_CARDTYPE: OnceCell<Symbol<S2V7_get_cardType>> = OnceCell::new(); static V7_VIS_SAVECOLOR: OnceCell<Symbol<S2V7_VIS_saveColor>> = OnceCell::new(); static V7_VIS_SAVEIR: OnceCell<Symbol<S2V7_VIS_saveIR>> = OnceCell::new(); static V7_VIS_GETMRZTEXT: OnceCell<Symbol<S2V7_VIS_getMRZtext>> = OnceCell::new(); static V7_RDO_getBytesByIndex: OnceCell<Symbol<S2V7_RDO_getBytesByIndex>> = OnceCell::new(); static V7_VIS_getBytesByIndex: OnceCell<Symbol<S2V7_VIS_getBytesByIndex>> = OnceCell::new(); static V7_RF_active: OnceCell<Symbol<S2V7_RF_active>> = OnceCell::new();  
// 对外导出函数方法 #[neon::main] fn main(mut cx: ModuleContext) -> NeonResult<()> {     cx.export_function("init", init_by_node)?;     cx.export_function("start", start)?; }  //加载dll并对函数进行初始化操作 pub fn init_by_node(mut cx: FunctionContext) -> JsResult<JsNumber> { 	//外部传进来的参数(根据自己的需要来定义)     let directory = cx.argument::<JsString>(0)?.value(&mut cx);     let userid = cx.argument::<JsString>(1)?.value(&mut cx);     unsafe {         DIRECTORY_PATH.take();         DIRECTORY_PATH.set(directory).unwrap();         USER_ID.take();         USER_ID.set(userid).unwrap();     };     let result = init() as f64;     Ok(cx.number(result)) }  //核心代码,加载dll函数并映射 fn init() -> c_int {     let directory = unsafe { DIRECTORY_PATH.get().unwrap() };     let userid = unsafe { USER_ID.get().unwrap() };     let directory_path = std::path::Path::new(directory).join(MACHINE_KIND);     if directory_path.exists() {         let dll_path = directory_path.join(libloading::library_filename("STAR200_V7_DRV"));         println!("dll_path: {:?}", dll_path);         if dll_path.exists() {             match init_dll(dll_path.to_str().unwrap()).is_ok() {                 true => {                     // 打开设备                     let init_result = unsafe {V7_OPEN.get_unchecked()()};                     if init_result == 0 {                         println!("设备打开成功");                         return ResultType::Success as c_int;                     } else {                         println!("设备打开失败,代码:{:?}",init_result);                         return ResultType::DeviceNotFound as c_int;                     }                 }                 false => {                     return ResultType::INITDLLFail as c_int;                 }             }         } else {             return ResultType::DllPathNotExist as c_int;         }     } else {         println!("{:?}", directory_path);         return ResultType::DirectoryPathNotExist as c_int;     } }  // 加载dll fn init_dll(dll_path: &str) -> Result<bool, Box<dyn std::error::Error>> {     unsafe {         if INITDLL {             return Ok(true);         }     }     println!("加载dll");     println!("dll_path");     let library = LIBRARY.get_or_init(|| unsafe { Library::new(dll_path).unwrap() });     println!("S2V7_open");     V7_OPEN.get_or_init(|| unsafe { library.get::<S2V7_open>(b"S2V7_open").unwrap() });     println!("S2V7_close");     V7_CLOSE.get_or_init(|| unsafe { library.get::<S2V7_close>(b"S2V7_close").unwrap() });     println!("S2V7_set_mode");     V7_SET_MODE.get_or_init(|| unsafe {library.get::<S2V7_set_mode>(b"S2V7_set_mode").unwrap()});     println!("S2V7_wait_DocIn");     V7_WAIT_DOCINT.get_or_init(|| unsafe { library.get::<S2V7_wait_DocIn>(b"S2V7_wait_DocIn").unwrap() });     println!("S2V7_wait_DocOut");     V7_WAIT_DOCOUT.get_or_init(|| unsafe { library.get::<S2V7_wait_DocOut>(b"S2V7_wait_DocOut").unwrap() });     V7_PROCESS.get_or_init(|| unsafe { library.get::<S2V7_process>(b"S2V7_process").unwrap() });     V7_GET_CARDTYPE.get_or_init(|| unsafe { library.get::<S2V7_get_cardType>(b"S2V7_get_cardType").unwrap() });     V7_VIS_SAVECOLOR.get_or_init(|| unsafe { library.get::<S2V7_VIS_saveColor>(b"S2V7_VIS_saveColor").unwrap() });     V7_VIS_SAVEIR.get_or_init(|| unsafe { library.get::<S2V7_VIS_saveIR>(b"S2V7_VIS_saveIR").unwrap() });     V7_VIS_GETMRZTEXT.get_or_init(|| unsafe { library.get::<S2V7_VIS_getMRZtext>(b"S2V7_VIS_getMRZtext").unwrap() });     V7_RDO_getBytesByIndex.get_or_init(|| unsafe { library.get::<S2V7_RDO_getBytesByIndex>(b"S2V7_RDO_getBytesByIndex").unwrap() });     V7_VIS_getBytesByIndex.get_or_init(|| unsafe { library.get::<S2V7_VIS_getBytesByIndex>(b"S2V7_VIS_getBytesByIndex").unwrap() });     V7_RF_active.get_or_init(|| unsafe { library.get::<S2V7_RF_active>(b"S2V7_RF_active").unwrap() });      unsafe {         INITDLL = true;     }     Ok(true) } 
//创建新线程来监测设备读证操作 fn start(mut cx: FunctionContext) -> JsResult<JsUndefined> {     let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);     let mut channel = cx.channel();     channel.reference(&mut cx);     println!("start {}", channel.has_ref());     let index = unsafe {         DEVICE_START_INDEX += 1;         DEVICE_START_INDEX     };     std::thread::spawn(move || {         // Do the heavy lifting inside the background thread.         device_start(callback, channel, index);     });     Ok(cx.undefined()) }  use std::sync::{Arc, Mutex}; fn device_start(callback: Root<JsFunction>, channel: Channel, index: u64) {     let index = index;     let callback = Arc::new(Mutex::new(callback));      //设置读证功能     unsafe { V7_SET_MODE.get_unchecked()(1,1,1,1) };      loop {         if index != unsafe { DEVICE_START_INDEX } {             break;         };         let callback_clone = Arc::clone(&callback);         let mut result = RecogIDCardEXResult::default();         let mut flg_in:i8=0;         match unsafe { V7_WAIT_DOCINT.get_unchecked()(5.0,&mut flg_in) } {             // 设备正常 检测是否有放入证件             0 => {                 if flg_in==0{                     //检查是否放入超时                     result.record_type = ResultType::CheckCardNotInOrOut as i32;                     break;                 }                 result.device_online = true;                 result.device_name =unsafe { DEVCIE_NAME.get_or_init(|| "".to_string()).to_string() };                                  match unsafe { V7_PROCESS.get_unchecked()() } {                     // 证件有放入                     0 => {                         result.record_type = ResultType::CheckCardInput as i32;                     }                     // 未检测到OCR区域                     -1 => {                         result.record_type = ResultType::OCRFail as i32;                     }                     // 设备离线                     -3 => {                         result.device_online = false;                         result.record_type = init();                     }                     _ => {                         result.record_type = ResultType::Unknown as i32;                     }                 }              }             -3 => {                 //设备离线                 let init = init();                 result.device_online = false;                 result.record_type = init;             }             _ => {                 //未知错误                 result.record_type = ResultType::Unknown as i32;             }         };          if unsafe { *NEED_RECORD.get_or_init(|| false) } {             println!("手工点击识别+1");             result.record_type = ResultType::CheckCardInput as i32;         }           // let time_now = std::time::Instant::now();         if result.record_type == ResultType::CheckCardInput as i32 {             let _result = recog_card();             result.success = _result.success;             result.img_base64 = _result.img_base64;             result.reg_info = _result.reg_info;             result.card_type = _result.card_type;             result.card_name = _result.card_name;         }         let neet_sendinfo = if Some(true) == unsafe { NEED_RECORD.take() } {             true         } else {             false         };          // let elapsed = time_now.elapsed();         // println!("识别时间结束时间 {:.6?}", elapsed);         if result.record_type != ResultType::CheckCardNotInOrOut as i32             && (*unsafe { RESULT_TYPE.get_or_init(|| -10000) } != result.record_type                 || result.record_type == ResultType::CheckCardInput as i32                 || neet_sendinfo)         {             unsafe {                 RESULT_TYPE.take();                 RESULT_TYPE.set(result.record_type).unwrap();             }             channel.send(move |mut cx| {                 let result_json = serde_json::to_string(&result).unwrap();                 let callback = callback_clone.lock().unwrap().to_inner(&mut cx);                 let this = cx.undefined();                 let args = vec![cx.string(&result_json)];                 callback.call(&mut cx, this, args)?;                 Ok(())             });         }         std::thread::sleep(std::time::Duration::from_millis(20));     } } 

完整源码

点击查看代码
use std::collections::HashMap;  use libc::{c_int, c_void}; use libloading::{Library, Symbol}; use neon::prelude::*; use once_cell::sync::OnceCell; use serde::Serialize;  extern crate encoding; use encoding::all::GB18030; use encoding::{DecoderTrap,EncoderTrap,Encoding};  use widestring::{WideCStr, WideCString, WideChar}; // 编码转换 utf8 -> utf16le fn encode(source: &str) -> WideCString {     let string_source = source.to_string() + "";     WideCString::from_str(&string_source).unwrap() } // 解码转换 utf16le -> utf8 fn decode(source: &[WideChar]) -> String {     WideCStr::from_slice_truncate(source)         .unwrap()         .to_string()         .unwrap() } // 加载 dll static LIBRARY: OnceCell<Library> = OnceCell::new();  static MACHINE_KIND: &str = if cfg!(target_os = "windows") {     if cfg!(target_arch = "x86") {         "win32"     } else if cfg!(target_arch = "x86_x64") {         "win64"     } else {         "other"     } } else if cfg!(target_os = "linux") {     if cfg!(target_arch = "x86") {         "linux32"     } else if cfg!(target_arch = "x86_64") {         "linux64"     } else if cfg!(target_arch = "aarch64") {         "aarch64"     } else if cfg!(target_arch = "arm") {         "arm"     } else {         "other"     } } else {     "other" };  //设置识别的证件 ID // 设置当前要识别的证件类型,并将 // 之前已经设置的证件类型清除。 // nMainID 主要识别类型,nSubID 子类型 //  nSubID 头指针,默认将数组 // nSubID 第 一 个 元 素 赋 值 为 0 即 // nSubID[0]=0 // type S = c_int[];  type LPCTSTR = *const WideChar; type BOOL = c_int; type INITPTR = *const i8; type CANRST = *mut WideChar;  // 打开设备 type S2V7_open = unsafe extern "system" fn() -> c_int; // 关闭设备 type S2V7_close = unsafe extern "system" fn() -> c_int;   //【set mode  设置读证功能】 type S2V7_set_mode =     unsafe extern "system" fn(flg_takeColor: c_int, flg_takeUV: c_int, flg_readChipInfo: c_int, flg_readChipFace: c_int) -> c_int; // Type = 0 即可  //【wait Doc. in 等待放卡】 type S2V7_wait_DocIn = unsafe extern "system" fn(timeout: f64, flg_in: INITPTR) -> c_int; // Type = 0 即可   //【wait Doc. out 等待拿卡】 type S2V7_wait_DocOut = unsafe extern "system" fn(timeout: f64, flg_out: INITPTR) -> c_int; // Type = 0 即可   //【process  执行读卡过程】 type S2V7_process = unsafe extern "system" fn() -> c_int;   //读取卡类型 type S2V7_get_cardType = unsafe extern "system" fn() -> c_int;  //保存彩照 type S2V7_VIS_saveColor = unsafe extern "system" fn(imgPath: LPCTSTR) -> c_int; //保存红外照 type S2V7_VIS_saveIR = unsafe extern "system" fn(imgPath: LPCTSTR) -> c_int;  //【get MRZ text 获取OCR文字信息】 type S2V7_VIS_getMRZtext = unsafe extern "system" fn(text: LPCTSTR) -> c_int;  //show text information  文字信息 type S2V7_RDO_getBytesByIndex = unsafe extern "system" fn(index: c_int,data: LPCTSTR) -> c_int; type S2V7_VIS_getBytesByIndex = unsafe extern "system" fn(index: c_int,data: LPCTSTR) -> c_int;  type S2V7_RF_active = unsafe extern "system" fn(antenna: c_int,atr: LPCTSTR, atr_len: c_int) -> c_int;  static V7_OPEN: OnceCell<Symbol<S2V7_open>> = OnceCell::new(); static V7_CLOSE: OnceCell<Symbol<S2V7_close>> = OnceCell::new(); static V7_SET_MODE: OnceCell<Symbol<S2V7_set_mode>> = OnceCell::new(); static V7_WAIT_DOCINT: OnceCell<Symbol<S2V7_wait_DocIn>> = OnceCell::new(); static V7_WAIT_DOCOUT: OnceCell<Symbol<S2V7_wait_DocOut>> = OnceCell::new(); static V7_PROCESS: OnceCell<Symbol<S2V7_process>> = OnceCell::new(); static V7_GET_CARDTYPE: OnceCell<Symbol<S2V7_get_cardType>> = OnceCell::new(); static V7_VIS_SAVECOLOR: OnceCell<Symbol<S2V7_VIS_saveColor>> = OnceCell::new(); static V7_VIS_SAVEIR: OnceCell<Symbol<S2V7_VIS_saveIR>> = OnceCell::new(); static V7_VIS_GETMRZTEXT: OnceCell<Symbol<S2V7_VIS_getMRZtext>> = OnceCell::new(); static V7_RDO_getBytesByIndex: OnceCell<Symbol<S2V7_RDO_getBytesByIndex>> = OnceCell::new(); static V7_VIS_getBytesByIndex: OnceCell<Symbol<S2V7_VIS_getBytesByIndex>> = OnceCell::new(); static V7_RF_active: OnceCell<Symbol<S2V7_RF_active>> = OnceCell::new();  // static static mut INITDLL: bool = false; static mut DEVICE_START_INDEX: u64 = 0; static mut DIRECTORY_PATH: OnceCell<String> = OnceCell::new(); static mut USER_ID: OnceCell<String> = OnceCell::new(); static mut DEVCIE_NAME: OnceCell<String> = OnceCell::new(); static mut RESULT_TYPE: OnceCell<i32> = OnceCell::new(); static mut NEED_RECORD: OnceCell<bool> = OnceCell::new(); // 初始化dll fn init_dll(dll_path: &str) -> Result<bool, Box<dyn std::error::Error>> {     unsafe {         if INITDLL {             return Ok(true);         }     }     println!("加载dll");     println!("dll_path");     let library = LIBRARY.get_or_init(|| unsafe { Library::new(dll_path).unwrap() });     println!("S2V7_open");     V7_OPEN.get_or_init(|| unsafe { library.get::<S2V7_open>(b"S2V7_open").unwrap() });     println!("S2V7_close");     V7_CLOSE.get_or_init(|| unsafe { library.get::<S2V7_close>(b"S2V7_close").unwrap() });     println!("S2V7_set_mode");     V7_SET_MODE.get_or_init(|| unsafe {library.get::<S2V7_set_mode>(b"S2V7_set_mode").unwrap()});     println!("S2V7_wait_DocIn");     V7_WAIT_DOCINT.get_or_init(|| unsafe { library.get::<S2V7_wait_DocIn>(b"S2V7_wait_DocIn").unwrap() });     println!("S2V7_wait_DocOut");     V7_WAIT_DOCOUT.get_or_init(|| unsafe { library.get::<S2V7_wait_DocOut>(b"S2V7_wait_DocOut").unwrap() });     V7_PROCESS.get_or_init(|| unsafe { library.get::<S2V7_process>(b"S2V7_process").unwrap() });     V7_GET_CARDTYPE.get_or_init(|| unsafe { library.get::<S2V7_get_cardType>(b"S2V7_get_cardType").unwrap() });     V7_VIS_SAVECOLOR.get_or_init(|| unsafe { library.get::<S2V7_VIS_saveColor>(b"S2V7_VIS_saveColor").unwrap() });     V7_VIS_SAVEIR.get_or_init(|| unsafe { library.get::<S2V7_VIS_saveIR>(b"S2V7_VIS_saveIR").unwrap() });     V7_VIS_GETMRZTEXT.get_or_init(|| unsafe { library.get::<S2V7_VIS_getMRZtext>(b"S2V7_VIS_getMRZtext").unwrap() });     V7_RDO_getBytesByIndex.get_or_init(|| unsafe { library.get::<S2V7_RDO_getBytesByIndex>(b"S2V7_RDO_getBytesByIndex").unwrap() });     V7_VIS_getBytesByIndex.get_or_init(|| unsafe { library.get::<S2V7_VIS_getBytesByIndex>(b"S2V7_VIS_getBytesByIndex").unwrap() });     V7_RF_active.get_or_init(|| unsafe { library.get::<S2V7_RF_active>(b"S2V7_RF_active").unwrap() });      unsafe {         INITDLL = true;     }     Ok(true) } fn init() -> c_int {     let directory = unsafe { DIRECTORY_PATH.get().unwrap() };     let userid = unsafe { USER_ID.get().unwrap() };     let directory_path = std::path::Path::new(directory).join(MACHINE_KIND);     if directory_path.exists() {         let dll_path = directory_path.join(libloading::library_filename("STAR200_V7_DRV"));         println!("dll_path: {:?}", dll_path);         if dll_path.exists() {             match init_dll(dll_path.to_str().unwrap()).is_ok() {                 true => {                     // 打开设备                     let init_result = unsafe {V7_OPEN.get_unchecked()()};                     if init_result == 0 {                         println!("设备打开成功");                         return ResultType::Success as c_int;                     } else {                         println!("设备打开失败,代码:{:?}",init_result);                         return ResultType::DeviceNotFound as c_int;                     }                 }                 false => {                     return ResultType::INITDLLFail as c_int;                 }             }         } else {             return ResultType::DllPathNotExist as c_int;         }     } else {         println!("{:?}", directory_path);         return ResultType::DirectoryPathNotExist as c_int;     } } pub fn init_by_node(mut cx: FunctionContext) -> JsResult<JsNumber> {     let directory = cx.argument::<JsString>(0)?.value(&mut cx);     let userid = cx.argument::<JsString>(1)?.value(&mut cx);     unsafe {         DIRECTORY_PATH.take();         DIRECTORY_PATH.set(directory).unwrap();         USER_ID.take();         USER_ID.set(userid).unwrap();     };     let result = init() as f64;     Ok(cx.number(result)) } #[allow(dead_code)] // 允许dead_code enum ResultType {     DirectoryPathNotExist = -2003, // 找不到运行目录     DllPathNotExist = -2001,       // 找不到dll文件     INITDLLFail = -2000,           // 初始化dll     Success = 0,                   // 成功     UserIdFail = 2001,             //用户 ID 错误     DeviceInitFail = 2002,         //  设备初始化失败     DeviceKernelInitFail = 2003,   // 初始化核心失败     DeviceDatInitFail = 2004,      //未找到授权文件     DeviceNotInit = 2101,          // 设备未初始化     DeviceNotFound = 2102,         // 没有找到设备     DeviceReConnect = 2103,        // 重新连接设备     Unknown = -100,                // 未知错误     CheckCardInput = 3001,         // 证件放入设备     CheckCardOut = 3002,           // 证件移出设备     CheckCardNotInOrOut = 3000,    // 证件无放入或拿出     CheckCardBarCode = 3003,       // 检测到手机条码     OCRFail=-1,                    // 未检测到OCR区域 }  type RecogIDCardEXResultItem = HashMap<i32, [String; 2]>; #[derive(Default, Serialize)] pub struct RecogIDCardEXResultObject {     pub viz_result: RecogIDCardEXResultItem,     pub viz_orc_result: RecogIDCardEXResultItem,     pub mrz_result: RecogIDCardEXResultItem,     pub mrz_ocr_result: RecogIDCardEXResultItem,     pub chip_result: RecogIDCardEXResultItem, }  #[derive(Default, Serialize)] pub struct RecogIDCardEXResult {     pub device_name: String,     pub device_online: bool,     pub reg_info: RecogIDCardEXResultObject,     pub img_base64: HashMap<String, String>,     pub card_type: i32,     pub record_type: i32,     pub card_name: String,     pub success: bool, // 识别是否成功 }  static SAVE_IMAGE_REUSLT_NAME: [&str; 5] = [     "tempHeadEC.jpg",     "tempHead.jpg",     "tempUV.jpg",     "tempIR.jpg",     "temp.jpg", ];  fn start(mut cx: FunctionContext) -> JsResult<JsUndefined> {     let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);     let mut channel = cx.channel();     channel.reference(&mut cx);     println!("start {}", channel.has_ref());     let index = unsafe {         DEVICE_START_INDEX += 1;         DEVICE_START_INDEX     };     std::thread::spawn(move || {         // Do the heavy lifting inside the background thread.         device_start(callback, channel, index);     });     Ok(cx.undefined()) }  use std::sync::{Arc, Mutex}; fn device_start(callback: Root<JsFunction>, channel: Channel, index: u64) {     let index = index;     let callback = Arc::new(Mutex::new(callback));      //设置读证功能     unsafe { V7_SET_MODE.get_unchecked()(1,1,1,1) };      loop {         if index != unsafe { DEVICE_START_INDEX } {             break;         };         let callback_clone = Arc::clone(&callback);         let mut result = RecogIDCardEXResult::default();         let mut flg_in:i8=0;         match unsafe { V7_WAIT_DOCINT.get_unchecked()(5.0,&mut flg_in) } {             // 设备正常 检测是否有放入证件             0 => {                 if flg_in==0{                     //检查是否放入超时                     result.record_type = ResultType::CheckCardNotInOrOut as i32;                     break;                 }                 result.device_online = true;                 result.device_name =unsafe { DEVCIE_NAME.get_or_init(|| "".to_string()).to_string() };                                  match unsafe { V7_PROCESS.get_unchecked()() } {                     // 证件有放入                     0 => {                         result.record_type = ResultType::CheckCardInput as i32;                     }                     // 未检测到OCR区域                     -1 => {                         result.record_type = ResultType::OCRFail as i32;                     }                     // 未找到非接卡                     // v if v/10 == -21 => {                     //     result.record_type = ResultType::OCRFail as i32;                     // }                     // 设备离线                     -3 => {                         result.device_online = false;                         result.record_type = init();                     }                     _ => {                         result.record_type = ResultType::Unknown as i32;                     }                 }              }             -3 => {                 //设备离线                 let init = init();                 result.device_online = false;                 result.record_type = init;             }             _ => {                 //未知错误                 result.record_type = ResultType::Unknown as i32;             }         };          if unsafe { *NEED_RECORD.get_or_init(|| false) } {             println!("手工点击识别+1");             result.record_type = ResultType::CheckCardInput as i32;         }           // let time_now = std::time::Instant::now();         if result.record_type == ResultType::CheckCardInput as i32 {             let _result = recog_card();             result.success = _result.success;             result.img_base64 = _result.img_base64;             result.reg_info = _result.reg_info;             result.card_type = _result.card_type;             result.card_name = _result.card_name;         }         let neet_sendinfo = if Some(true) == unsafe { NEED_RECORD.take() } {             true         } else {             false         };          // let elapsed = time_now.elapsed();         // println!("识别时间结束时间 {:.6?}", elapsed);         if result.record_type != ResultType::CheckCardNotInOrOut as i32             && (*unsafe { RESULT_TYPE.get_or_init(|| -10000) } != result.record_type                 || result.record_type == ResultType::CheckCardInput as i32                 || neet_sendinfo)         {             unsafe {                 RESULT_TYPE.take();                 RESULT_TYPE.set(result.record_type).unwrap();             }             channel.send(move |mut cx| {                 let result_json = serde_json::to_string(&result).unwrap();                 let callback = callback_clone.lock().unwrap().to_inner(&mut cx);                 let this = cx.undefined();                 let args = vec![cx.string(&result_json)];                 callback.call(&mut cx, this, args)?;                 Ok(())             });         }         std::thread::sleep(std::time::Duration::from_millis(20));     } }   // 白光图、红外 // 图、紫外图、版面头像和芯片头像 pub fn recog_card() -> RecogIDCardEXResult {     let time_now = std::time::Instant::now();     let mut result = RecogIDCardEXResult::default();     result.device_online = true;      let img_path_directory = std::path::Path::new(unsafe { DIRECTORY_PATH.get().unwrap() });      let ir_img_path = img_path_directory.join("ir.jpg");     let color_img_path = img_path_directory.join("color.jpg");      //显示红外照     let irResult = unsafe {V7_VIS_SAVEIR.get_unchecked()(encode(ir_img_path.to_str().unwrap()).as_ptr() as LPCTSTR)};     //显示彩照     let colorResult = unsafe {V7_VIS_SAVECOLOR.get_unchecked()(encode(color_img_path.to_str().unwrap()).as_ptr() as LPCTSTR)};      if irResult==0{         if ir_img_path.exists() {             match std::fs::read(&ir_img_path) {                 Ok(image_data) => {                     println!("读取照片成功");                     let image_data = base64::encode(&image_data);                     let base64_string = String::from("data:image/jpg;base64,");                     std::fs::remove_file(ir_img_path).unwrap();                     result.img_base64.insert("0".to_string(), base64_string + &image_data);                 }                 Err(e) => {                     println!("读取照片抛异常");                     println!(                         "{:?} {:?}",                         e,                         "ir.jpg",                     );                 }             };         }     }      if colorResult==0{         if color_img_path.exists() {             match std::fs::read(&color_img_path) {                 Ok(image_data) => {                     println!("读取照片成功");                     let image_data = base64::encode(&image_data);                     let base64_string = String::from("data:image/jpg;base64,");                     std::fs::remove_file(color_img_path).unwrap();                     result.img_base64.insert("1".to_string(), base64_string + &image_data);                 }                 Err(e) => {                     println!("读取照片抛异常");                     println!(                         "{:?} {:?}",                         e,                         "color.jpg",                     );                 }             };         }     }      let mut ocritem = RecogIDCardEXResultObject::default();      let mut index: c_int = 0;      //orc识别文字     let mut mrztext = [0; 1024];     let x = unsafe {V7_VIS_GETMRZTEXT.get_unchecked()(mrztext.as_mut_ptr())};     if x==0{         let result_item = ["MRZ".to_string(), decode(&mrztext)];         ocritem.mrz_result.insert(index, result_item);         index+=1;     }      let mut data:[u16; 256] = [0; 256];     let mut len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(0,data.as_mut_ptr())};     if len>0{         ocritem.mrz_result.insert(index, ["编号".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(1,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["国籍".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(2,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["民族".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(3,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["姓名".to_string(), decode(&data)]);         index+=1;           len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(4,data.as_mut_ptr())};         let cardType= unsafe {V7_GET_CARDTYPE.get_unchecked()()};         if cardType==101{             //身份证是UTF8格式             ocritem.mrz_result.insert(index, ["中文名".to_string(), decode(&data)]);         }else{             ocritem.mrz_result.insert(index, ["中文名".to_string(), decode(&data)]);             // //中国护照的中文姓名 是GBK编码的             // let name=GB18030.decode(&data, DecoderTrap::Strict).unwrap();             // ocritem.mrz_result.insert(index, ["中文名".to_string(), name.replace("u{0}","")]);         }         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(5,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["性别".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(6,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["出生日期".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(7,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["地址".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(8,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["签发机关".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(9,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["有效期始".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(10,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["有效期止".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_RDO_getBytesByIndex.get_unchecked()(20,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["港澳台ID".to_string(), decode(&data)]);         index+=1;     }     else{         len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(0,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["编号".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(1,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["国籍".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(2,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["民族".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(3,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["姓名".to_string(), decode(&data)]);         index+=1;                   //中国护照的中文姓名 是GBK编码的, 身份证不会执行到这里         len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(4,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["中文名".to_string(), decode(&data)]);         // let name=GB18030.decode(&data, DecoderTrap::Strict).unwrap();         // ocritem.mrz_result.insert(index, ["中文名".to_string(), name.replace("u{0}","")]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(5,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["性别".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(6,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["出生日期".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(7,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["地址".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(8,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["签发机关".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(9,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["有效期始".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(10,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["有效期止".to_string(), decode(&data)]);         index+=1;          len = unsafe {V7_VIS_getBytesByIndex.get_unchecked()(20,data.as_mut_ptr())};         ocritem.mrz_result.insert(index, ["港澳台ID".to_string(), decode(&data)]);         index+=1;     }          result.reg_info=ocritem;     result.success = true;      result.card_type = unsafe {V7_GET_CARDTYPE.get_unchecked()()};     let elapsed = time_now.elapsed();     println!("{:.6?}", elapsed);     return result; }  pub fn regcord_by_node(mut cx: FunctionContext) -> JsResult<JsNull> {     println!("regcord_by_node");     unsafe {         NEED_RECORD.take();         NEED_RECORD.set(true).unwrap();     };     Ok(cx.null()) } #[neon::main] fn main(mut cx: ModuleContext) -> NeonResult<()> {     cx.export_function("init", init_by_node)?;     cx.export_function("start", start)?;     cx.export_function("regcord_by_node", regcord_by_node)?;     Ok(()) }  
发表评论

评论已关闭。

相关文章