Считыватель отпечатков пальцев на node.js через.NET SDK
Я пытаюсь заставить приложение node.js взаимодействовать со считывателем отпечатков пальцев.NET SDK под названием U.are.U. SDK предоставляет библиотеки.dll (win32 и x64), Java и.NET. Я решил использовать.NET для простоты использования, имея все готовые интерфейсы и все.
Итак, текущая проблема, с которой я сталкиваюсь, заключается в том, как вызывать эти функции.NET и при этом сохранять асинхронную природу node.js. Поток приложений (на примере.NET) довольно прост, 3 обращения к библиотеке и проверка отпечатков пальцев завершена.
private IEnumerable<Fmd> CaptureAndExtractFmd()
{
while (!reset)
{
DataResult<Fmd> resultConversion;
try
{
if (count >= 8)
{
SendMessage("Enrollment was unsuccessful. Please try again.");
count = 0;
break;
}
Fid fid = null;
if (!_sender.CaptureFinger(ref fid))
break;
if (fid == null)
continue;
count++;
resultConversion = FeatureExtraction.CreateFmdFromFid(fid, Constants.Formats.Fmd.ANSI);
SendMessage("A finger was captured. \r\nCount: " + (count));
if (resultConversion.ResultCode != Constants.ResultCode.DP_SUCCESS)
break;
}
catch (Exception)
{
break;
}
yield return resultConversion.Data;
}
}
Как я могу изменить его, чтобы его можно было использовать в node.js вместо программы.NET GUI?
Также необходимо отметить, что node.js не всегда вызывает функцию в программе.NET для получения функции. Идентификационная часть программы происходит асинхронно и отключается, когда кто-то кладет палец на считыватель отпечатков пальцев, это означает, что часть node.js не знает, когда это произойдет. Поэтому я не могу полагаться на то, что запрашиваю данные в.NET-части все время, она должна вызывать обратные вызовы в node.js без запроса. По сути, это двусторонняя связь, не только по запросу, так как запрос с использованием веб-сервера будет намного проще.
Я нашел библиотеку node.js, которая может закрыть пробел между.NET и node.js, называемую edge.js, это поможет?
По сути, edge.js может заставить его работать вместе с node-webkit (который я буду поставлять для моего приложения), я могу вызывать API-интерфейсы узла прямо на странице, поэтому я могу обновить DOM в зависимости от результата из библиотеки, Мне нужно иметь возможность зарегистрировать асинхронную задачу, которая МОЖЕТ уведомить изнутри CLR коллеге node.js, либо отправив событие, либо вызвав обратный вызов!
По словам автора edge.js, это легко сделать https://github.com/tjanczuk/edge/issues/54 Мне просто не хватает навыков.NET для этого (из полноценного модуля) со всеми обратными вызовами.
4 ответа
После того, как этот вопрос был опубликован в течение долгого времени, я могу легко использовать edge.js для связи IN и OUT моего.NET UI (даже управляющего node.js в node-webkit из.NET UI) с помощью генератора событий узла:
// demo basic code in node.js
var
edge = require('edge'),
Bridge = edge.func('../path/to/compiled.dll'),
callback,
ev = new require('events').EventEmitter();
ev.on('acquire', function(fingerdata){
console.log(fingerdata);
});
ev.on('error', function(){
});
callback = function(event, report){
// report the result of the event emitter back to .NET
// you can even pass the "report" to the event handler, so you can return anything you want back to .NET, not just a boolean
report(null, ev.emit(event.name, event.data));
//ev.emit(event.name, {data: event.data, report: report});
};
var bridge = Bridge(callback, true);
// calling bridge(null, true); "releases" my device, should be called on process.on('exit')
И теперь вы можете вызывать / выводить из.NET, используя события, вместо вызова нативного кода (который не может быть потокобезопасным)
namespace Bridge
{
public class Startup
{
public async Task<object> Invoke(Func<object, Task<object>>callback)
{
Bridge.Base.setCallback(callback);
MainForm mainForm = new Bridge.MainForm();
Task.Run(async () =>
{
Application.Run(mainForm);
});
return (Func<object, Task<object>>)(async (i) => { Bridge.Base.release(); return null; });
}
}
}
// inside Bridge.Base
static public void setCallback(Func<object, Task<object>> cb)
{
if (callback == null)
{
callback = cb;
}
}
static public async void Emit(string name, object data)
{
return await Task.Run(async () =>
{
return await callback(new {
name = name,
data = data
});
});
}
static public Func<object, Task<object>> callback = null;
теперь могу позвонить Emit('error', "My error")
откуда угодно мои производные классы от Base
асинхронно. Просто обратите внимание, что я недавно начал работать в C#, и мой код, представленный здесь, может не подходить.
Использование библиотеки.NET этого SDK не является подходящим решением для этой проблемы.
Node.js сам по себе является приложением C++, и попытка правильно использовать библиотеку.NET просто требует огромного вреда, особенно когда SDK также предоставляет собственную библиотеку C/C++!
Конечно, вы не можете просто использовать библиотеку C++ напрямую; вам придется написать оболочку C++. В мире узлов они называются аддонами. Написание аддона не совсем просто, но даже тот, у кого мало опыта в C++, должен уметь следовать примерам в документации и что-то работать.
Получение встроенного аддона, встроенного в Windows, также может быть немного сложным; Вот несколько советов, которые помогут вам начать.
Поскольку используемый вами SDK находится за платным доступом, я не могу привести конкретные примеры. Тем не менее, я предполагаю, что ваш объект-оболочка C++ предоставит несколько методов, и вы также напишите JS-оболочку, чтобы представить чистый API. Например:
var uareu = require('./uareu.node') // the native C++ addon dll
, events = require('events')
, util = require('util');
function FingerprintReader() {
events.EventEmitter.call(this); // initialize the EventEmitter
// do stuff with the native module
// whenever a finger is placed on the reader:
this.emit('finger', { id: idFromSdk });
}
util.inherits(FingerprintReader, events.EventEmitter); // we want this module
// to be an EventEmitter
module.exports = FingerprintReader; // export for require()ing in your app
Теперь ваше приложение может просто:
var FingerprintReader = require('fingerprint')
, fp = new FingerprintReader();
fp.on('finger', function(d) {
// do something with `d.id`
});
Этот пример явно затуманивается, но должен дать вам хорошее представление о том, что должно произойти в конце JS. Что касается определения, когда на считыватель помещается палец, я не могу точно сказать, как вы будете это делать без доступа к SDK. Могу поспорить, что вы в итоге будете где-то опрашивать. Это должно быть сделано в отдельном потоке в вашем аддоне.
Бонус: переход на собственный маршрут означает, что вы, вероятно, также будете совместимы с Linux-версией SDK, поэтому ваше приложение будет работать и на Linux!
Интересная проблема. Можно ли было просто поместить интересующую вас функцию в файл ASHX (пользовательский обработчик HTTP), а затем опубликовать ее из приложения вашего узла? В зависимости от того, что вы хотите вернуть, вам может потребоваться выполнить сериализацию / десериализацию, но, похоже, это может быть самый простой способ запустить фрагмент кода C# из приложения Node....
У Microsoft есть довольно хороший набор учебников по пользовательским обработчикам HTTP, которые можно найти здесь.
Базовый скелет ASHX приведен ниже:
<%@ WebHandler Language="C#" Class="NodeHandler" %>
using System;
using System.Web;
public class NodeHandler : IHttpHandler {
public void ProcessRequest (HttpContext context) {
//Handle fingerprint stuff!!!
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World");
}
public bool IsReusable {
get {
return false;
}
}
}
Вы бы заменили содержимое ProcessRequest
с измененной версией вашей существующей функции.
Я бы создал либо самостоятельно размещенную службу WCF (т.е. службу Windows, которая имеет конечную точку wcf), либо использовал бы фреймворки, такие как OpenRasta или ServiceStack, для замены WCF.
Во всех трех случаях у меня был бы веб-сервис json, который возвращает результат последнего вызова CaptureAndExtractFmd
Тогда я бы использовал этот сервис в node.js
Если вам нужна дополнительная информация о том, как вы решили пойти, просто создайте другой вопрос.
Пример кода с WCF, часть C#
[ServiceContract]
public interface IFingerprintContrat {
[OperationContract]
Fmd[] GetLastFeature();
}
public class FingerprintService {
Fmd[] GetLastFeature() {
return CaptureAndExtractFmd().ToArray()
}
}
using (ServiceHost host = new ServiceHost(typeof(FingerprintService), baseAddress))
{
// Enable metadata publishing.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
host.Description.Behaviors.Add(smb);
host.Open();
Console.WriteLine("The service is ready at {0}", baseAddress);
Console.WriteLine("Press <Enter> to stop the service.");
Console.ReadLine();
// Close the ServiceHost.
host.Close();
}
Node.js часть
var request = require("request");
request.get("baseaddress/GetLastFeature", function (err, res, body) {
if (!err) {
var resultsObj = JSON.parse(body);
console.log(resultsObj);
}
});