@digitalpersona/devices
Version:
DigitalPersona Security Devices support library
230 lines (211 loc) • 10.9 kB
text/typescript
import { Base64Url, Utf8 } from '@digitalpersona/core';
import { Handler, MultiCastEventSource } from '../../private';
import { Command, Request, Channel } from '../websdk';
import { Event, CommunicationFailed, CommunicationEventSource } from '../../common';
import { DeviceConnected, DeviceDisconnected, DeviceEventSource } from '../events';
import { ErrorOccurred,
SamplesAcquired, QualityReported,
AcquisitionStarted, AcquisitionStopped,
} from './events';
import { FingerprintsEventSource } from './eventSource';
import {
Method, NotificationType, Notification, EnumerateDevicesResponse,
Completed, Error, Quality } from './messages';
import { DeviceInfo } from './device';
import { SampleFormat } from './sample';
/**
* A fingerprint reader API.
* An instance of this class allows to subscribe to finerprint reader events and read fingerprint data.
* The fingerprint reader API uses DigitalPersona WebSDK to communicate with fingerprint reader drivers and hardware.
*/
export class FingerprintReader
extends MultiCastEventSource
// implements FingerprintsEventSource, DeviceEventSource, CommunicationEventSource
{
/** A WebSdk channel. */
private readonly channel: Channel;
/**
* Constructs a new fingerprint reader API object.
* @param options - options for the `WebSdk` channel.
*/
constructor(
private readonly options?: WebSdk.WebChannelOptions,
) {
super();
this.channel = new Channel("fingerprints", this.options);
this.channel.onCommunicationError = this.onConnectionFailed.bind(this);
this.channel.onNotification = this.processNotification.bind(this);
}
/** An event handler for the {@link DeviceConnected} event.
* @remarks This is a unicast subscription, i.e. only one handler can be registered at once.
* For multicast subscription use {@link FingerprintReader.on} and {@link FingerprintReader.off}.
*/
public onDeviceConnected: Handler<DeviceConnected>;
/** An event handler for the {@link DeviceDisconnected} event.
* @remarks This is a unicast subscription, i.e. only one handler can be registered at once.
* For multicast subscription use {@link FingerprintReader.on} and {@link FingerprintReader.off}.
*/
public onDeviceDisconnected: Handler<DeviceDisconnected>;
/** An event handler for the {@link SamplesAcquired} event.
* @remarks This is a unicast subscription, i.e. only one handler can be registered at once.
* For multicast subscription use {@link FingerprintReader.on} and {@link FingerprintReader.off}.
*/
public onSamplesAcquired: Handler<SamplesAcquired>;
/** An event handler for the {@link QualityReported} event.
* @remarks This is a unicast subscription, i.e. only one handler can be registered at once.
* For multicast subscription use {@link FingerprintReader.on} and {@link FingerprintReader.off}.
*/
public onQualityReported: Handler<QualityReported>;
/** An event handler for the {@link ErrorOccurred} event.
* @remarks This is a unicast subscription, i.e. only one handler can be registered at once.
* For multicast subscription use {@link FingerprintReader.on} and {@link FingerprintReader.off}.
*/
public onErrorOccurred: Handler<ErrorOccurred>;
/** An event handler for the {@link AcquisitionStarted} event.
* @remarks This is a unicast subscription, i.e. only one handler can be registered at once.
* For multicast subscription use {@link FingerprintReader.on} and {@link FingerprintReader.off}.
*/
public onAcquisitionStarted: Handler<AcquisitionStarted>;
/** An event handler for the {@link AcquisitionStopped} event.
* @remarks This is a unicast subscription, i.e. only one handler can be registered at once.
* For multicast subscription use {@link FingerprintReader.on} and {@link FingerprintReader.off}.
*/
public onAcquisitionStopped: Handler<AcquisitionStopped>;
/** An event handler for the {@link CommunicationFailed} event.
* @remarks This is a unicast subscription, i.e. only one handler can be registered at once.
* For multicast subscription use {@link FingerprintReader.on} and {@link FingerprintReader.off}.
*/
public onCommunicationFailed: Handler<CommunicationFailed>;
/**
* Adds an event handler for the event.
* This is a multicast subscription, i.e. many handlers can be registered at once.
*
* @param event - a name of the event to subscribe, e.g. "SampleAcquired"
* @param handler - an event handler.
* @returns an event handler reference.
* Store the reference and pass it to the {@link FingerprintReader.off} to unsubscribe from the event.
*
* @example
* ```
* class FingerprintComponent
* {
* private reader: FingerprintReader;
*
* private onDeviceConnected = (event: DeviceConnected) => { ... };
* private onDeviceDisconnected = (event: DeviceDisconnected) => { ... };
* private onSamplesAcquired = (event: SampleAquired) => { ... };
* ...
*
* public async $onInit() {
* this.reader = new FingerprintReader();
* this.reader.on("DeviceConnected", onDeviceConnected);
* this.reader.on("DeviceDisconnected", onDeviceDisconnected);
* this.reader.on("SamplesAcquired", onSamplesAcquired);
* ...
* await this.fingerprintReader.startAcquisition(SampleFormat.Intermediate);
* }
* public async $onDestroy() {
* await this.fingerprintReader.stopAcquisition();
* this.reader.off("DeviceConnected", onDeviceConnected);
* this.reader.off("DeviceDisconnected", onDeviceDisconnected);
* this.reader.off("SamplesAcquired", onSamplesAcquired);
* ...
* // alternatively, call this.reader.off() to unsubscribe from all events at once.
* delete this.reader;
* }
* }
* ```
*/
public on<E extends Event>(event: string, handler: Handler<E>): Handler<E> { return this._on(event, handler); }
/** Deletes an event handler for the event.
* @param event - a name of the event to subscribe.
* @param handler - an event handler added with the {@link FingerprintReader.on} method.
*/
public off<E extends Event>(event?: string, handler?: Handler<E>): this { return this._off(event, handler); }
/** Lists all connected fingerprint readers.
* @returns a promise to return a list of fingerprint reader names.
*/
public enumerateDevices(): Promise<string[]> {
return this.channel.send(new Request(new Command(
Method.EnumerateDevices,
)))
.then(response => {
if (!response) return [];
const deviceList: EnumerateDevicesResponse = JSON.parse(Utf8.fromBase64Url(response.Data || "{}"));
return JSON.parse(deviceList.DeviceIDs || "[]");
});
}
/** Reads a fingerprint reader device information.
* @param deviceUid - a fingerprint reader ID.
* @returns a promise to return a device information.
* The promise can be fulfilled but return `null` if the reader provides no information.
* The promise will be rejected if a reader is not found or in case of a reading error.
*/
public getDeviceInfo(deviceUid: string): Promise<DeviceInfo|null> {
return this.channel.send(new Request(new Command(
Method.GetDeviceInfo,
Base64Url.fromJSON({ DeviceID: deviceUid }),
)))
.then(response => {
const deviceInfo: DeviceInfo = JSON.parse(Utf8.fromBase64Url(response.Data || "null"));
return deviceInfo;
});
}
/** Activate a fingerprint acquisition mode.
* This call will produce a {@link AcquisitionStarted} event if activation was successful.
* After that the reader will wait for a finger placed on the reader.
* When a finger is placed, a {@link QualityReported} event will report a scan quality,
* and a {@link SamplesAcquired} event will return a scanned sample in case of a successful scan.
*/
public startAcquisition(sampleFormat: SampleFormat, deviceUid?: string): Promise<void> {
return this.channel.send(new Request(new Command(
Method.StartAcquisition,
Base64Url.fromJSON({
DeviceID: deviceUid ? deviceUid : "00000000-0000-0000-0000-000000000000",
SampleType: sampleFormat,
}),
)))
.then();
}
/** Deactivates a fingerprint acquisition mode.
* This call will produce a {@link AcquisitionStopped} event if deactivation was successful.
* After that the reader will stop waiting for a finger.
*/
public stopAcquisition(deviceUid?: string): Promise<void> {
return this.channel.send(new Request(new Command(
Method.StopAcquisition,
Base64Url.fromJSON({
DeviceID: deviceUid ? deviceUid : "00000000-0000-0000-0000-000000000000",
}),
)))
.then();
}
/** Converts WebSdk connectivity error to a fingerprint API event. */
private onConnectionFailed(): void {
this.emit(new CommunicationFailed());
}
/** Converts WebSdk notification to fingerprint API events. */
private processNotification(notification: Notification): void {
switch (notification.Event) {
case NotificationType.Completed:
const completed: Completed = JSON.parse(Utf8.fromBase64Url(notification.Data || ""));
return this.emit(new SamplesAcquired(notification.Device, completed.SampleFormat, completed.Samples));
case NotificationType.Error:
const error: Error = JSON.parse(Utf8.fromBase64Url(notification.Data || ""));
return this.emit(new ErrorOccurred(notification.Device, error.uError));
case NotificationType.Disconnected:
return this.emit(new DeviceDisconnected(notification.Device));
case NotificationType.Connected:
return this.emit(new DeviceConnected(notification.Device));
case NotificationType.Quality:
const quality: Quality = JSON.parse(Utf8.fromBase64Url(notification.Data || ""));
return this.emit(new QualityReported(notification.Device, quality.Quality));
case NotificationType.Stopped :
return this.emit(new AcquisitionStopped(notification.Device));
case NotificationType.Started:
return this.emit(new AcquisitionStarted(notification.Device));
default:
console.log(`Unknown notification: ${notification.Event}`);
}
}
}