idcard-reader
Version:
通过二代身份证机具读取二代身份证信息
204 lines (203 loc) • 6.83 kB
JavaScript
import { error, info } from '@waiting/log';
import { dirname } from '@waiting/shared-core';
import { of, range, timer } from 'rxjs';
import { concatMap, defaultIfEmpty, filter, map, mergeMap, take, tap, timeout, } from 'rxjs/operators';
export function connectDevice(device, port) {
if (device && device.inUse) {
device.deviceOpts.debug && info('Cautiton: connectDevice() device in use');
return 0;
}
const openRet = device.apib.SDT_OpenPort(port);
device.deviceOpts.debug && info(`open device port ret: ${openRet}`);
return openRet === 144 ? port : 0;
}
export function disconnectDevice(device) {
const ret = device.apib.SDT_ClosePort(device.openPort);
device.deviceOpts.debug && info(`disconnectDevice at port: ${device.openPort}, ret: ${ret} `);
device.inUse = false;
return ret === 144;
}
export function resetDevice(device, port) {
if (port && port > 0) {
const ret = device.apib.SDT_ResetSAM(port, 0);
info(`reset ${port} ret: ${ret}`);
}
else {
for (let i = 1; i <= 16; i += 1) {
const ret = device.apib.SDT_ResetSAM(i, 0);
info(`reset ${i} ret: ${ret}`);
}
for (let i = 1001; i <= 1016; i += 1) {
const ret = device.apib.SDT_ResetSAM(i, 0);
info(`reset ${i} ret: ${ret}`);
}
}
device.deviceOpts.debug && info(`reset device at port: ${device.openPort}`);
device.inUse = false;
}
export function findDeviceList(deviceOpts, compositeOpts, apib) {
const arr = [];
if (deviceOpts.port > 0) {
// 仅USB接口
const device = findDevice(deviceOpts.port, deviceOpts, compositeOpts, apib, true);
if (device.openPort > 0) {
arr.push(device);
}
}
else {
// 必须先检测usb端口
for (let i = 1001; i <= 1016; i += 1) {
const device = findDevice(i, deviceOpts, compositeOpts, apib, true);
if (device.openPort > 0) {
// device.simid = getSamid(device)
arr.push(device);
if (!deviceOpts.searchAll) {
break;
}
}
}
if (!deviceOpts.searchAll && arr.length) {
return arr;
}
// 检测串口
for (let i = 1; i <= 16; i += 1) {
const device = findDevice(i, deviceOpts, compositeOpts, apib, false);
if (device.openPort > 0) {
arr.push(device);
if (!deviceOpts.searchAll) {
break;
}
}
}
}
return arr;
}
export function findDevice(openPort, deviceOpts, compositeOpts, apib, useUsb) {
const device = {
apib,
apii: null,
deviceOpts,
compositeOpts,
inUse: false,
openPort: 0,
useUsb,
};
const port = connectDevice(device, openPort);
if (port > 0) {
device.inUse = true;
device.openPort = port;
deviceOpts.debug && info(`Found device at serial/usb port: ${port}`);
disconnectDevice(device);
}
return device;
}
/** 读取二代证基础信息 */
export function readDataBase(device) {
const path = dirname(device.deviceOpts.dllTxt);
process.env.PATH = `${process.env.PATH};${path}`;
// const srcDir = path.replace(/\\/g, '/') + '/'
// const targetPath = normalize(device.deviceOpts.imgSaveDir + '/').replace(/\\/g, '/')
if (device.deviceOpts.debug) {
info('starting reading readCard ');
// info('IDCard_GetInformation() src path:' + srcDir)
// info('IDCard_GetInformation() target path:' + targetPath)
}
const open = connectDevice(device, device.openPort);
if (!open) {
throw new Error(`打开端口失败 readDataBase() port: ${device.openPort}`);
}
const cardReady$ = findCard(device).pipe(mergeMap((found) => {
if (found) {
return of(selectCard(device)).pipe(timeout(1500));
}
else {
throw new Error('findCard() 未能找到指定设备');
}
}), tap((ready) => {
if (!ready) {
throw new Error('二代证无效,请确保证件处于机具读卡区域内');
}
}));
const ret$ = cardReady$.pipe(map(() => readCard(device)), tap((raw) => {
if (device.deviceOpts.debug) {
// info(`readDataBase bufLen: ${buf.byteLength}`)
info('readDataBase ret');
info(raw);
}
}));
return ret$;
}
/** 检测卡是否可读取状态 */
export function findCard(device) {
const { findCardRetryTimes } = device.deviceOpts;
const findRet$ = range(0, findCardRetryTimes > 0 ? findCardRetryTimes + 1 : 1).pipe(concatMap((_, index) => {
if (index > 0 && index >= findCardRetryTimes) {
throw new Error(`findCard fail over ${findCardRetryTimes} times`);
}
// 移动中读取到卡 延迟执行选卡
const delay$ = timer(index === 0 ? 0 : 1000);
return delay$.pipe(mergeMap(() => of(_findCard(device))));
}));
const ret$ = findRet$.pipe(tap((ret) => {
device.deviceOpts.debug && info(`findStatus: ${ret}`);
}), filter(ret => ret === 159), take(1), defaultIfEmpty(0), map(ret => ret > 0));
return ret$;
}
function _findCard(device) {
try {
const buf = Buffer.alloc(4);
return device.apib.SDT_StartFindIDCard(device.openPort, buf, 1);
}
catch (ex) {
device.deviceOpts.debug && error(ex);
return 0;
}
}
/** 选卡 */
export function selectCard(device) {
const buf = Buffer.alloc(4);
const res = device.apib.SDT_SelectIDCard(device.openPort, buf, 1);
return res === 144;
}
function readCard(device) {
const opts = {
pucCHMsg: Buffer.alloc(1024),
puiCHMsgLen: Buffer.from([1024]),
pucPHMsg: Buffer.alloc(1024),
puiPHMsgLen: Buffer.from([1024]),
};
// console.log(opts)
const data = {
err: 1,
code: 0,
text: opts.pucCHMsg,
image: opts.pucPHMsg,
imagePath: '',
};
try {
data.code = device.apib.SDT_ReadBaseMsg(device.openPort, opts.pucCHMsg, opts.puiCHMsgLen, opts.pucPHMsg, opts.puiPHMsgLen, 1);
}
catch (ex) {
console.error(ex);
}
if (data.code === 144) {
data.err = 0;
}
else {
resetDevice(device, device.openPort);
}
return data;
}
export function getSamid(device) {
const buf = Buffer.alloc(128);
const res = device.apib.SDT_GetSAMIDToStr(device.openPort, buf, 1);
let samid = '';
if (res === 144) {
samid = buf.toString('utf8');
const pos = samid.indexOf('\0');
if (pos >= 0) {
samid = samid.slice(0, pos);
}
}
return samid;
}