UNPKG

@waiting/idcard-reader-bp8903

Version:
232 lines (207 loc) 7.84 kB
/** * @waiting/idcard-reader-bp8903 * 南天 BP8903 二代机具读卡 * * @version 2.3.2 * @author waiting * @license MIT * @link https://github.com/waitingsong/node-idcard-reader-bp8903#readme */ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var sharedCore = require('@waiting/shared-core'); var win32Def = require('win32-def'); var idcardReaderBase = require('@waiting/idcard-reader-base'); var log = require('@waiting/log'); var ffi = require('ffi'); var rxjs = require('rxjs'); var operators = require('rxjs/operators'); var iconv = require('iconv-lite'); const config = { appDir: '', tmpDir: sharedCore.join(sharedCore.tmpdir(), 'idcard-reader'), }; const dllFuncs = { OpenCom: [win32Def.DTypes.INT32, [win32Def.DTypes.INT32, win32Def.DTypes.POINT, win32Def.DTypes.INT32, win32Def.DTypes.INT32]], CloseCom: [win32Def.DTypes.INT32, []], IDCard_GetInformation: [win32Def.DTypes.INT32, [win32Def.DTypes.INT32, win32Def.DTypes.INT32, win32Def.DTypes.POINT, win32Def.DTypes.INT32, win32Def.DTypes.POINT, win32Def.DTypes.POINT, win32Def.DTypes.POINT]], }; function connectDevice(device, port) { if (device && device.inUse) { device.deviceOpts.debug && log.info('Cautiton: connectDevice() device in use'); return 0 } const openRet = device.apib.OpenCom(port, Buffer.from(''), 9600, 1); device.deviceOpts.debug && log.info(`open com ret: ${openRet}`); return openRet === 0 ? port : 0 } function disconnectDevice(device) { const ret = device.apib.CloseCom(); device.deviceOpts.debug && log.info(`disconnectDevice at port: ${device.openPort}, ret: ${ret} `); device.inUse = false; return true } function findDeviceList(deviceOpts, compositeOpts, apib) { const arr = []; if (deviceOpts.port > 0) { const device = findDevice(deviceOpts.port, deviceOpts, compositeOpts, apib); if (device.openPort > 0) { arr.push(device); } } else { // 检测串口. bp8903 为串口接口 for (let i = 1; i <= 16; i++) { const device = findDevice(i, deviceOpts, compositeOpts, apib); if (device.openPort > 0) { arr.push(device); if (!deviceOpts.searchAll) { break } } } } return arr } function findDevice(openPort, deviceOpts, compositeOpts, apib) { const device = { apib, deviceOpts, compositeOpts, inUse: false, openPort: 0, }; const port = connectDevice(device, openPort); if (port > 0) { device.inUse = true; device.openPort = port; deviceOpts.debug && log.info(`Found device at serial/usb port: ${port}`); disconnectDevice(device); } return device } /** 读取二代证基础信息 */ function readAll(device) { const path = sharedCore.dirname(device.deviceOpts.dllTxt); process.env.PATH = `${process.env.PATH};${path}`; const buf = Buffer.alloc(10240); const srcDir = path.replace(/\\/g, '/') + '/'; const targetPath = sharedCore.normalize(device.deviceOpts.imgSaveDir + '/').replace(/\\/g, '/'); if (device.deviceOpts.debug) { log.info('starting reading readCard ret'); log.info('IDCard_GetInformation() src path:' + srcDir); log.info('IDCard_GetInformation() target path:' + targetPath); } const code = device.apib.IDCard_GetInformation(device.openPort, 9600, Buffer.from(''), 3, buf, Buffer.from(srcDir), Buffer.from(targetPath)); const ret = iconv.decode(buf, 'gbk'); if (device.deviceOpts.debug) { log.info(`readDataBase code: ${code}`); log.info(`readDataBase bufLen: ${buf.byteLength}`); log.info(`readDataBase ret: ${ret}`); // info(buf.slice(80)) } return ret.replace(/\0/g, '') } async function init(options) { const deviceOpts = idcardReaderBase.parseDeviceOpts(options); const compositeOpts = idcardReaderBase.parseCompositeOpts(options); // 先清空 解决头像图片生成可能失败问题 // compositeOpts.fontHwxhei = '' // compositeOpts.fontOcrb = '' // compositeOpts.fontSimhei = '' const { debug } = deviceOpts; if (debug) { log.info(compositeOpts); log.info(deviceOpts); } await idcardReaderBase.validateDllFile(deviceOpts.dllTxt); // 允许 未指定照片解码dll if (deviceOpts.dllImage && compositeOpts.useComposite && !await sharedCore.isFileExists(deviceOpts.dllImage)) { throw new Error('File not exists: ' + deviceOpts.dllImage) } await idcardReaderBase.testWrite(deviceOpts.imgSaveDir); const apib = ffi.Library(deviceOpts.dllTxt, dllFuncs); const devices = findDeviceList(deviceOpts, compositeOpts, apib); if (devices && devices.length) { return devices } else { throw new Error('未找到读卡设备') } } /** Read card data */ function read(device) { if (device.openPort) { try { disconnectDevice(device); } catch (ex) { throw ex } const text$ = rxjs.of(readAll(device)).pipe(operators.timeout(2000)); const iddata$ = text$.pipe(operators.retry(device.deviceOpts.findCardRetryTimes), operators.map(text => { const base = pickFields(text); const imagePath = device.compositeOpts.useComposite ? genAvatarPath(device.deviceOpts.imgSaveDir, base.idc) : ''; const ret = Object.assign({}, idcardReaderBase.initialIDData, { base, imagePath }); return ret })); const ret$ = iddata$.pipe(operators.delay(device.compositeOpts.useComposite ? 300 : 0), operators.tap(() => { disconnectDevice(device); }), operators.mergeMap(data => { return sharedCore.fileExists(data.imagePath).pipe(operators.map(path => { data.imagePath = path; return data })) }), operators.mergeMap(data => { return !device.compositeOpts.useComposite || !data.imagePath ? rxjs.of(data) : idcardReaderBase.composite(data.imagePath, data.base, device.compositeOpts).pipe(operators.map(imgPath => { data.compositePath = imgPath; return data })) }), operators.timeout(20000), operators.catchError((err) => { disconnectDevice(device); throw err })); return ret$.toPromise() } else { throw new Error('设备端口未指定') } } /** Pick fields from origin text */ function pickFields(text) { const base = Object.assign({}, idcardReaderBase.initialDataBase); if (!text || !text.length) { return base } /** 姓名|身份证号|性别|民族|出生年月|住址|签发机关|起始日期|截至日期 */ const arr = text.split('|'); if (arr.length === 9) { base.name = arr[0].trim(); base.idc = arr[1]; base.genderName = arr[2]; base.nationName = arr[3]; base.birth = arr[4]; base.address = arr[5].trim(); base.regorg = arr[6].trim(); base.startdate = arr[7]; base.enddate = arr[8]; } return idcardReaderBase.formatBaseData(base) } function genAvatarPath(imgSaveDir, idc) { const path = sharedCore.join(imgSaveDir, `${idc}.bmp`); return path } // base directory of this module config.appDir = __dirname + '/..'; exports.initialCompositeOpts = idcardReaderBase.initialCompositeOpts; exports.initialOpts = idcardReaderBase.initialOpts; exports.nationMap = idcardReaderBase.nationMap; exports.init = init; exports.read = read; exports.genAvatarPath = genAvatarPath;