Windows set up permission button #261 (#300)

* style(privilege): Fix typo 'excusive' -> 'exclusive'

* style(privilege): remove unused imports

* style(privilege): Fix typo 'initizalized$' -> 'initialized$'

* feat(log): Add application wide logger and error handler

It is help to debug electron install app on different device

* feat(privilege): Add windows USB driver installation

* build: I need the windows installer to test the app on windows

* fix(privilege): change wdi-simpler installer to zadic

* feat(log): change log level to debug in renderer process

* chore: Add author in package.json

* feat(privilege): Add privilege setter file as extraResource

* fix(log): Allowed transport level change only in main process

* fix(privilege): Fix app path calculation

* fix(privilege): Take the scriptPath between double quote

* build: revert the appveyor settings

* refactor(privilege): Extract vendor ID, product ID and MAX_PAYLOAD_SIZE into constants file

* refactor(privilege): Add both 32 and 64 bit zadics to extraResource of the installer

* feat(device): Add HID API communication protocol

* build: Fix npm install process

* build: Fix npm install process v2

* ci: Add libudev-dev as travis apt dependencies

* ci: Merge travis apt packages

* ci: remove node-hid from build:usb

* ci: try to fix linux build

* ci: node-hid use git repo

* ci: Add libusb-1.0-0-dev to travis apt dependency

* feat(device): Use logging service when communicate with the device

* build: create test build

* build: PUBLISH_FOR_PULL_REQUEST override

* build: revert TEST_BUILD to false

* build: node-hid use package version instead of git repo

* refactor: remove unused device store files from PR

* ci: Manage test build from environment variable

* fix(privilege): Set rules files dir base on dev or prod mode

* fix(log): Extract nested properties of the logged object

* feat(log): use util.inspect in logger service

* build: upgrade @types/node-hid -> 0.5.2

* fix(device): Add extra logging when try to open device.

* fix(device): log device description and not the device

* fix(device): add win specific write

* fix(device): add report id as first byte

* style(privilege): Reformat else and comment in privilege-checker component

* fix(privilege): Comment out windows branch
This commit is contained in:
Róbert Kiss
2017-07-02 20:33:28 +02:00
committed by László Monda
parent 84b13d3219
commit 2df8f2ea54
23 changed files with 556 additions and 214 deletions

View File

@@ -0,0 +1,142 @@
import { Inject, Injectable, NgZone, OnDestroy } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Subscriber } from 'rxjs/Subscriber';
import 'rxjs/add/observable/empty';
import 'rxjs/add/observable/timer';
import 'rxjs/add/operator/catch';
import 'rxjs/add/operator/concat';
import 'rxjs/add/operator/combineLatest';
import 'rxjs/add/operator/concatMap';
import 'rxjs/add/operator/first';
import 'rxjs/add/operator/publish';
import 'rxjs/add/operator/do';
import { Device, findByIds, InEndpoint, Interface, on, OutEndpoint } from 'usb';
import { ILogService, LOG_SERVICE } from '../shared/services/logger.service';
import { Constants } from '../shared/util';
import { UhkDeviceService } from './uhk-device.service';
@Injectable()
export class UhkLibUsbApiService extends UhkDeviceService implements OnDestroy {
private device: Device;
static isUhkDevice(device: Device) {
return device.deviceDescriptor.idVendor === Constants.VENDOR_ID &&
device.deviceDescriptor.idProduct === Constants.PRODUCT_ID;
}
constructor(zone: NgZone,
@Inject(LOG_SERVICE) protected logService: ILogService) {
super(logService);
this.initialize();
// The change detection doesn't work properly if the callbacks are called outside Angular Zone
on('attach', (device: Device) => zone.run(() => this.onDeviceAttach(device)));
on('detach', (device: Device) => zone.run(() => this.onDeviceDetach(device)));
}
initialize(): void {
if (this.initialized$.getValue()) {
return;
}
this.device = findByIds(Constants.VENDOR_ID, Constants.PRODUCT_ID);
this.connected$.next(!!this.device);
if (!this.device) {
return;
}
try {
this.device.open();
this.deviceOpened$.next(true);
} catch (error) {
this.logService.error(error);
return;
}
const usbInterface: Interface = this.device.interface(0);
// https://github.com/tessel/node-usb/issues/147
// The function 'isKernelDriverActive' is not available on Windows and not even needed.
if (usbInterface.isKernelDriverActive()) {
usbInterface.detachKernelDriver();
}
this.messageIn$ = Observable.create((subscriber: Subscriber<Buffer>) => {
const inEndPoint: InEndpoint = <InEndpoint>usbInterface.endpoints[0];
this.logService.info('Try to read');
inEndPoint.transfer(Constants.MAX_PAYLOAD_SIZE, (error: string, receivedBuffer: Buffer) => {
if (error) {
this.logService.error('reading error', error);
subscriber.error(error);
} else {
this.logService.info('read data', receivedBuffer);
subscriber.next(receivedBuffer);
subscriber.complete();
}
});
});
const outEndPoint: OutEndpoint = <OutEndpoint>usbInterface.endpoints[1];
const outSending = this.messageOut$.concatMap(senderPackage => {
return (<Observable<void>>Observable.create((subscriber: Subscriber<void>) => {
this.logService.info('transfering', senderPackage.buffer);
outEndPoint.transfer(senderPackage.buffer, error => {
if (error) {
this.logService.error('transfering errored', error);
subscriber.error(error);
} else {
this.logService.info('transfering finished');
subscriber.complete();
}
});
})).concat(this.messageIn$)
.do(buffer => senderPackage.observer.next(buffer) && senderPackage.observer.complete())
.catch((error: string) => {
senderPackage.observer.error(error);
return Observable.empty<void>();
});
}).publish();
this.outSubscription = outSending.connect();
this.initialized$.next(true);
}
hasPermissions(): Observable<boolean> {
return this.isConnected()
.combineLatest(this.deviceOpened$)
.map((latest: boolean[]) => {
const connected = latest[0];
const opened = latest[1];
if (!connected) {
return false;
} else if (opened) {
return true;
}
try {
this.device.open();
} catch (error) {
return false;
}
this.device.close();
return true;
});
}
onDeviceAttach(device: Device) {
if (!UhkLibUsbApiService.isUhkDevice(device)) {
return;
}
// Ugly hack: device is not openable (on Windows) right after the attach
Observable.timer(100)
.first()
.subscribe(() => this.initialize());
}
onDeviceDetach(device: Device) {
if (!UhkLibUsbApiService.isUhkDevice(device)) {
return;
}
this.disconnect();
}
}