UNPKG

@waiting/fingerprint-reader-bp8903

Version:
166 lines (149 loc) 4.57 kB
/** * @waiting/fingerprint-reader-bp8903 * 南天 BP8903 集成键盘 指纹采集、验证 * * @version 2.1.2 * @author waiting * @license MIT * @link https://github.com/waitingsong/node-fingerprint-reader-bp8903#readme */ import { DTypes } from 'win32-def'; import { info } from '@waiting/log'; import { validateDllFile, normalize } from '@waiting/shared-core'; import { Library } from 'ffi'; import { of, forkJoin } from 'rxjs'; import { tap, retry, mergeMap } from 'rxjs/operators'; /** 初始化参数 */ const initialOpts = { dllTxt: '', dllSearchPath: '', debug: false, port: 0, searchAll: false, }; const dllFuncs = { ABC_GetFeature: [DTypes.INT, [DTypes.BYTE, DTypes.POINT, DTypes.INT]], ABC_GetTemplate: [DTypes.INT, [DTypes.BYTE, DTypes.POINT, DTypes.INT]], ABC_Match: [DTypes.INT, [DTypes.POINT, DTypes.POINT]], }; function findDeviceList(deviceOpts, apib) { const arr = []; if (deviceOpts.port > 0) { const device = findDevice(deviceOpts.port, deviceOpts, apib); if (device.openPort > 0) { arr.push(device); } } else { throw new Error('deviceOpts.port must be specified') } return arr } function findDevice(port, deviceOpts, apib) { const device = { apib, deviceOpts, inUse: false, openPort: port, }; return device } /** Sampling fingerprint once, return base64 */ function readOnce(device, bufLen = 1024) { device.deviceOpts.debug && info('staring read once...'); const buf = Buffer.alloc(bufLen); const code = device.apib.ABC_GetFeature(device.openPort, buf, bufLen); const ret = code === 1 ? buf : Buffer.alloc(0); if (device.deviceOpts.debug) { info(`Fingerprint readOnce code: ${code}. (1:succeed, 0/others:failed)`); } return ret } /** Sampling fingerprint 3times, return base64 */ function readThrice(device, bufLen = 1024) { device.deviceOpts.debug && info('staring read thrice...'); const buf = Buffer.alloc(bufLen); const code = device.apib.ABC_GetTemplate(device.openPort, buf, bufLen); const ret = code === 1 ? buf : Buffer.alloc(0); if (device.deviceOpts.debug) { info(`Fingerprint readThice code: ${code}. (1:succeed, 0/others:failed)`); } return ret } function compareFP(device, fp1, fp2) { return new Promise(resolve => { // const code = device.apib.ABC_Match(fp1, fp2) device.apib.ABC_Match.async(fp1, fp2, (err, code) => { resolve(code === 1 ? true : false); return code }); }) } async function init(options) { const deviceOpts = parseDeviceOpts(options); const { debug } = deviceOpts; if (debug) { info(deviceOpts); } await validateDllFile(deviceOpts.dllTxt); const apib = Library(deviceOpts.dllTxt, dllFuncs); const devices = findDeviceList(deviceOpts, apib); if (devices && devices.length) { return devices } else { throw new Error('未找到读卡设备') } } /** * Sample fingprint * * mode (default: strict): * - simple: read once * - strict: read 3 times */ function sampleFP(device, mode = 'strict') { const buf = mode === 'simple' ? readOnce(device) : readThrice(device); const ret = parseResultBuffer(buf); return Promise.resolve(ret) } function verifyFP(device, fp) { const fp1$ = of(readOnce(device)).pipe(tap(buf => { if (!buf.byteLength) { throw new Error('Sampling result empty. will retry once') } }), retry(1), tap(buf => { if (!buf.byteLength) { throw new Error('Sampling result empty') } })); const fp2$ = of(Buffer.from(fp)).pipe(tap(buf => { if (!buf.byteLength) { throw new Error('Input fingerprint key being validated is invalid') } })); const ret$ = forkJoin(fp1$, fp2$).pipe(mergeMap(([fp1, fp2]) => compareFP(device, fp1, fp2))); return ret$.toPromise() } function parseDeviceOpts(options) { const deviceOpts = Object.assign({}, initialOpts, options); if (!options.dllTxt) { throw new Error('params dllTxt undefined or blank') } else { deviceOpts.dllTxt = normalize(deviceOpts.dllTxt); } return deviceOpts } /** convert sampling result to base64 */ function parseResultBuffer(buf) { const ret = buf.byteLength ? buf.toString().replace(/\0+$/, '') : ''; return ret } export { initialOpts, init, sampleFP, verifyFP };