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

虚幻大学 xuhss 201℃ 0评论

? 优质资源分享 ?

学习路线指引(点击解锁) 知识定位 人群定位
? Python实战微信订餐小程序 ? 进阶级 本课程是python flask+微信小程序的完美结合,从项目搭建到腾讯云部署上线,打造一个全栈订餐系统。
?Python量化交易实战? 入门级 手把手带你打造一个易扩展、更安全、效率更高的量化交易系统

在项目上经常要用到身份证阅读器、护照阅读仪、指纹仪等各种品牌硬件,假如每套系统的都做集成开发那代码的维护成本将变得很高,为此采用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命令,我们在target\debug目录下可以看到编译后的结果。
二、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() + "\0";
    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 = 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> = OnceCell::new();
static V7\_CLOSE: OnceCell> = OnceCell::new();
static V7\_SET\_MODE: OnceCell> = OnceCell::new();
static V7\_WAIT\_DOCINT: OnceCell> = OnceCell::new();
static V7\_WAIT\_DOCOUT: OnceCell> = OnceCell::new();
static V7\_PROCESS: OnceCell> = OnceCell::new();
static V7\_GET\_CARDTYPE: OnceCell> = OnceCell::new();
static V7\_VIS\_SAVECOLOR: OnceCell> = OnceCell::new();
static V7\_VIS\_SAVEIR: OnceCell> = OnceCell::new();
static V7\_VIS\_GETMRZTEXT: OnceCell> = OnceCell::new();
static V7\_RDO\_getBytesByIndex: OnceCell> = OnceCell::new();
static V7\_VIS\_getBytesByIndex: OnceCell> = OnceCell::new();
static V7\_RF\_active: OnceCell> = 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 {
 //外部传进来的参数(根据自己的需要来定义)
 let directory = cx.argument::(0)?.value(&mut cx);
 let userid = cx.argument::(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::(b"S2V7\_open").unwrap() });
 println!("S2V7\_close");
 V7\_CLOSE.get\_or\_init(|| unsafe { library.get::(b"S2V7\_close").unwrap() });
 println!("S2V7\_set\_mode");
 V7\_SET\_MODE.get\_or\_init(|| unsafe {library.get::(b"S2V7\_set\_mode").unwrap()});
 println!("S2V7\_wait\_DocIn");
 V7\_WAIT\_DOCINT.get\_or\_init(|| unsafe { library.get::(b"S2V7\_wait\_DocIn").unwrap() });
 println!("S2V7\_wait\_DocOut");
 V7\_WAIT\_DOCOUT.get\_or\_init(|| unsafe { library.get::(b"S2V7\_wait\_DocOut").unwrap() });
 V7\_PROCESS.get\_or\_init(|| unsafe { library.get::(b"S2V7\_process").unwrap() });
 V7\_GET\_CARDTYPE.get\_or\_init(|| unsafe { library.get::(b"S2V7\_get\_cardType").unwrap() });
 V7\_VIS\_SAVECOLOR.get\_or\_init(|| unsafe { library.get::(b"S2V7\_VIS\_saveColor").unwrap() });
 V7\_VIS\_SAVEIR.get\_or\_init(|| unsafe { library.get::(b"S2V7\_VIS\_saveIR").unwrap() });
 V7\_VIS\_GETMRZTEXT.get\_or\_init(|| unsafe { library.get::(b"S2V7\_VIS\_getMRZtext").unwrap() });
 V7\_RDO\_getBytesByIndex.get\_or\_init(|| unsafe { library.get::(b"S2V7\_RDO\_getBytesByIndex").unwrap() });
 V7\_VIS\_getBytesByIndex.get\_or\_init(|| unsafe { library.get::(b"S2V7\_VIS\_getBytesByIndex").unwrap() });
 V7\_RF\_active.get\_or\_init(|| unsafe { library.get::(b"S2V7\_RF\_active").unwrap() });

 unsafe {
 INITDLL = true;
 }
 Ok(true)
}
折叠 
//创建新线程来监测设备读证操作
fn start(mut cx: FunctionContext) -> JsResult {
 let callback = cx.argument::(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, 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() + "\0";
    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 = 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> = OnceCell::new();
static V7\_CLOSE: OnceCell> = OnceCell::new();
static V7\_SET\_MODE: OnceCell> = OnceCell::new();
static V7\_WAIT\_DOCINT: OnceCell> = OnceCell::new();
static V7\_WAIT\_DOCOUT: OnceCell> = OnceCell::new();
static V7\_PROCESS: OnceCell> = OnceCell::new();
static V7\_GET\_CARDTYPE: OnceCell> = OnceCell::new();
static V7\_VIS\_SAVECOLOR: OnceCell> = OnceCell::new();
static V7\_VIS\_SAVEIR: OnceCell> = OnceCell::new();
static V7\_VIS\_GETMRZTEXT: OnceCell> = OnceCell::new();
static V7\_RDO\_getBytesByIndex: OnceCell> = OnceCell::new();
static V7\_VIS\_getBytesByIndex: OnceCell> = OnceCell::new();
static V7\_RF\_active: OnceCell> = 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::(b"S2V7\_open").unwrap() });
 println!("S2V7\_close");
 V7\_CLOSE.get\_or\_init(|| unsafe { library.get::(b"S2V7\_close").unwrap() });
 println!("S2V7\_set\_mode");
 V7\_SET\_MODE.get\_or\_init(|| unsafe {library.get::(b"S2V7\_set\_mode").unwrap()});
 println!("S2V7\_wait\_DocIn");
 V7\_WAIT\_DOCINT.get\_or\_init(|| unsafe { library.get::(b"S2V7\_wait\_DocIn").unwrap() });
 println!("S2V7\_wait\_DocOut");
 V7\_WAIT\_DOCOUT.get\_or\_init(|| unsafe { library.get::(b"S2V7\_wait\_DocOut").unwrap() });
 V7\_PROCESS.get\_or\_init(|| unsafe { library.get::(b"S2V7\_process").unwrap() });
 V7\_GET\_CARDTYPE.get\_or\_init(|| unsafe { library.get::(b"S2V7\_get\_cardType").unwrap() });
 V7\_VIS\_SAVECOLOR.get\_or\_init(|| unsafe { library.get::(b"S2V7\_VIS\_saveColor").unwrap() });
 V7\_VIS\_SAVEIR.get\_or\_init(|| unsafe { library.get::(b"S2V7\_VIS\_saveIR").unwrap() });
 V7\_VIS\_GETMRZTEXT.get\_or\_init(|| unsafe { library.get::(b"S2V7\_VIS\_getMRZtext").unwrap() });
 V7\_RDO\_getBytesByIndex.get\_or\_init(|| unsafe { library.get::(b"S2V7\_RDO\_getBytesByIndex").unwrap() });
 V7\_VIS\_getBytesByIndex.get\_or\_init(|| unsafe { library.get::(b"S2V7\_VIS\_getBytesByIndex").unwrap() });
 V7\_RF\_active.get\_or\_init(|| unsafe { library.get::(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 {
 let directory = cx.argument::(0)?.value(&mut cx);
 let userid = cx.argument::(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 {
 let callback = cx.argument::(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, 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 {
 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(())
}

折叠 

转载请注明:xuhss » 使用rust调用c++静态库并编译nodejs包

喜欢 (0)

您必须 登录 才能发表评论!