javascript

Работа с периферией из JavaScript: от теории к практике

  • пятница, 16 июня 2017 г. в 03:13:39
https://habrahabr.ru/company/efs/blog/330374/
  • Программирование
  • ReactJS
  • JavaScript
  • Блог компании Программа «Единая фронтальная система»


Работа сотрудника банка опасна и трудна. В Единой фронтальной системе мы стараемся помочь сотруднику банка и автоматизировать его работу. Одна из многочисленных задач, которую нам нужно решить, — доработать тонкий клиент для возможности работы с периферийным банковским оборудованием. Но сделать это не так-то просто. В данной статье мы расскажем, как мы пытались решить задачу, и к чему это привело.

Статья будет полезна архитекторам и опытным front-end разработчикам систем масштаба предприятий, столкнувшихся с проблемой доступа к периферийному оборудованию из тонкого клиента своей системы.



И да, скажем сразу, задача усложняется тем, что стандартные подходы с применением ActiveX, Java Applet, плагина браузера нас не устраивают по соображениям безопасности, универсальности и сложностей с  управляемостью и сопровождаемостью.

Представьте себе скромный (по китайским меркам) банк, в отделениях которого работают более 100 тыс. операторов. У них есть рабочие места, на которых они обслуживают клиентов, а  к рабочим местам подключены различные периферийные устройства:

  1. Сетевой/локальный принтер.
  2. Чековый принтер (Epson-M950 или Olivetti).
  3. POS-терминал (Verifone VX820).
  4. Устройство для чтения «таблеток» (touch memory с ЭЦП).
  5. Сканеры разных типов (для штрих-кодов, паспортов или просто документов).
  6. Веб-камера (фотографировать потенциальных заемщиков).
  7. Специфическое банковское оборудование – cash dispenser/receiver и т.п.

Внушительный список, не правда ли? И со всем этим нужно взаимодействовать из работающего в браузере react-приложения.

Работа с устройствами на низком уровне осуществляется через драйвера производителей оборудования или native библиотеки внутренней разработки. Установка и обновление драйверов и другого ПО на рабочих местах осуществляются централизованно. На рабочих местах стоят Windows и Internet Explorer 11 или 8. Обсуждается возможность перехода на Linux и Chrome/Firefox. Отсюда возникает требование кросс-платформенности и кросс-браузерности.

Проблема разнородности устройств и их отказов более-менее решена, но требуется мониторинг работы устройств, включая возможность забирать логи с рабочего места. Также требуется централизованное управление настройками работы с периферией.

Требования безопасности заключаются в контроле целостности кода, запускаемого на клиенте, ограничении доступа к периферии (доступ должен быть только с локального рабочего места) и ряда специфичных требований к работе с touch memory.

Отдельный вопрос – работа планшета с периферией. Идея в том, чтобы заменить компьютеры на мобильные девайсы, перенеся на них весь функционал оператора, включая совершение банковских операций. В этой статье мы не будем подробно говорить про планшеты, обязательно расскажем об этом в другой статье, просто обозначим, что здесь возникают как вопросы подключения самого планшета к внутренней банковской сети по wi-fi, так и вопросы работы с устройствами, подключаемыми непосредственно к планшету, например, mPOS-терминалами.

Как мы пытались все это приручить, почему не сразу получилось


Из условий эксплуатации следует схема работы с периферией:

Мы попытались найти решение проблемы и проработали несколько вариантов.

HTML5


Хотя в нем потенциально есть работа с периферийными устройствами, текущие реализации заточены под мобильные устройства или аудио/видео,  и для наших задач не подходят от слова «совсем».

WebUSB


https://wicg.github.io/webusb/ — во-первых, не все устройства подключаются через USB. Во-вторых, поддержки WebUSB на текущий момент нет нигде, кроме экспериментальной feature в Chrome. Так что тоже нам не подходит.

ActiveX


Способ старинный и проверенный – делаются обертки над драйверами, устанавливаемые как локальные OCX или DLL, обращение к которым идет через ActiveXObject:

var printer = new ActiveXObject("LocalPrinterComponent.Printer");
printer.print(data + "\r\n");

Но он работает только в IE и Windows. Несмотря на попытки сделать технологию ActiveX переносимой,  Microsoft отказалась от развития ActiveX в пользу технологии плагинов.

Плагины браузера


Это тоже нам не подходит, не является целевым, привязывает к браузеру и ограничивает универсальность.

Нативные компоненты на Java


На localhost выставляется cервис, который доступен из JavaScript. От этого тоже решили отказаться, т.к. реализация более трудоемкая, требуется использовать веб-сервер либо писать свой.

Applet


Не целевой, возникают проблемы с правами доступа на локальном устройстве.

И что же делать?


В итоге мы остановились на следующей архитектуре работы с периферийными устройствами:



Клиентское приложение в JavaScript обращается к локальному сервису через модуль работы с периферийным API, который является обвязкой над клиентской частью socket.io.

На рабочие места устанавливается node.js, который запускается под сервисной учетной записью при старте операционки. В node.js работает наш модуль bootstrap, отвечающий за загрузку npm-модулей для работы с периферийными устройствами с сервера в локальную файловую систему. Клиентский код генерирует event, в качестве атрибутов передается код и версия модуля, который работает с устройством, вызываемый метод и его параметры:



Также bootstrap отвечает за работу с платформенными сервисами (выгрузку логов с рабочего места по запросу администратора и т.п.)

Для каждого периферийного устройства  имеется свой модуль работы с ним, исполняемый в node.js. Bootstrap проксирует вызов в метод модуля:





Модуль работает с низкоуровневым API операционной системы или драйвера через npm модуль node.js «ffi»:



Когда клиентское приложение обращается к bootstrap, передавая модуль и версию, bootstrap проверяет локальное хранилище. Если нужного модуля нет в локальном хранилище, он выкачивается его с сервера. Таким образом, централизованно устанавливаются только драйвера и node.js с bootstrap’ом, а npm-модули для работы с устройствами скачиваются в рантайме. Но данная функция вряд ли будет использоваться в промышленной конфигурации, так что предполагаем, что при удаленной инсталляции драйверов устройств на рабочие места сотрудников будет устанавливаться и соответствующий npm модуль периферийного API, представляющий собой JS bundle.

Решение пока еще не реализовано, мы работаем над этим и обязательно расскажем о результатах в другой статье. А пока хотим спросить у вас, что вы думаете о выбранном подходе? Какие подводные камни нас ждут? Приглашаем всех принять участие в дискуссии в комментариях.