Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: delete device pairings #2500

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 73 additions & 0 deletions packages/uhk-agent/src/services/device.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { emptyDir } from 'fs-extra';
import { cloneDeep, isEqual } from 'lodash';
import os from 'os';
import {
AreBleAddressesPairedIpcResponse,
ALL_UHK_DEVICES,
BackupUserConfigurationInfo,
ChangeKeyboardLayoutIpcResponse,
Expand Down Expand Up @@ -125,6 +126,15 @@ export class DeviceService {
this.logService.misc('[DeviceService] Cannot query udev info:', error);
});

ipcMain.on(IpcEvents.device.areBleAddressesPaired, (...args: any[]) => {
this.queueManager.add({
method: this.areBleAddressesPaired,
bind: this,
params: args,
asynchronous: true
});
});

ipcMain.on(IpcEvents.device.changeKeyboardLayout, (...args: any[]) => {
this.queueManager.add({
method: this.changeKeyboardLayout,
Expand All @@ -143,6 +153,15 @@ export class DeviceService {
});
});

ipcMain.on(IpcEvents.device.eraseBleSettings, (...args: any[]) => {
this.queueManager.add({
method: this.eraseBleSettings,
bind: this,
params: args,
asynchronous: true
});
});

ipcMain.on(IpcEvents.device.toggleI2cDebugging, this.toggleI2cDebugging.bind(this));

ipcMain.on(IpcEvents.device.saveUserConfiguration, (...args: any[]) => {
Expand Down Expand Up @@ -235,6 +254,36 @@ export class DeviceService {
logService.misc('[DeviceService] init success');
}

public async areBleAddressesPaired(event: Electron.IpcMainEvent, args: Array<any>): Promise<void> {
this.logService.misc('[DeviceService] Check BLE Addresses are paired');

const response: AreBleAddressesPairedIpcResponse = {
success: true,
addresses: {},
};

try {
await this.stopPollUhkDevice();

const addresses: string[] = args[0];
for (const address of addresses) {
response.addresses[address] = await this.device.isPairedWith(convertBleStringToNumberArray(address));
}
}
catch (error) {
this.logService.error('[DeviceService] Check BLE Addresses pairing failed');
response.success = false;
response.error = {
message: error.message,
};
}
finally {
this.startPollUhkDevice();
}

event.sender.send(IpcEvents.device.areBleAddressesPairedReply, response);
}

/**
* Return with the actual UserConfiguration from UHK Device
* @returns {Promise<Buffer>}
Expand Down Expand Up @@ -763,6 +812,30 @@ export class DeviceService {
}
}

public async eraseBleSettings(event: Electron.IpcMainEvent): Promise<void> {
this.logService.misc('[DeviceService] erase BLE Settings');
const response: IpcResponse = {
success: true,
};
try {
await this.stopPollUhkDevice();
await this.operations.eraseBleSettings();
this.logService.misc('[DeviceService] erase BLE settings success');
}
catch(error) {
this.logService.error('[DeviceService] erase BLE settings failed', error);
response.success = false;
response.error = {
message: error.message,
};
}
finally {
this.startPollUhkDevice();
}

event.sender.send(IpcEvents.device.eraseBleSettingsReply, response);
}

public async startDonglePairing(event: Electron.IpcMainEvent): Promise<void> {
this.logService.misc('[DeviceService] start Dongle pairing');
try {
Expand Down
4 changes: 4 additions & 0 deletions packages/uhk-common/src/models/ipc-response.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ export class FirmwareUpgradeIpcResponse extends IpcResponse {
userConfigSaved?: boolean;
firmwareDowngraded?: boolean;
}

export interface AreBleAddressesPairedIpcResponse extends IpcResponse {
addresses: Record<string, boolean>;
}
4 changes: 4 additions & 0 deletions packages/uhk-common/src/util/ipcEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,13 @@ export class AutoUpdate {
}

export class Device {
public static readonly areBleAddressesPaired = 'device-are-ble-addresses-paired';
public static readonly areBleAddressesPairedReply = 'device-are-ble-addresses-paired-reply';
public static readonly changeKeyboardLayout = 'device-change-keyboard-layout';
public static readonly changeKeyboardLayoutReply = 'device-change-keyboard-layout-reply';
public static readonly dongleVersionInfoLoaded = 'device-dongle-version-info-loaded';
public static readonly eraseBleSettings = 'device-erase-ble-settings';
public static readonly eraseBleSettingsReply = 'device-erase-ble-settings-reply';
public static readonly hardwareModulesLoaded = 'device-hardware-modules-loaded';
public static readonly setPrivilegeOnLinux = 'set-privilege-on-linux';
public static readonly setPrivilegeOnLinuxReply = 'set-privilege-on-linux-reply';
Expand Down
1 change: 1 addition & 0 deletions packages/uhk-usb/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export enum UsbCommand {
UnpairAll = 0x1a,
IsPaired = 0x1b,
EnterPairingMode = 0x1c,
EraseBleSettings = 0x1d,
}

export enum EepromOperation {
Expand Down
6 changes: 6 additions & 0 deletions packages/uhk-usb/src/uhk-operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ export class UhkOperations {
private device: UhkHidDevice) {
}

public async eraseBleSettings(): Promise<void> {
this.logService.usbOps('[UhkHidDevice] USB[T]: Erase BLE settings.');
const transfer = Buffer.from([UsbCommand.EraseBleSettings]);
await this.device.write(transfer);
}

public async jumpToBootloaderModule(module: ModuleSlotToId): Promise<void> {
this.logService.usbOps(`[UhkHidDevice] USB[T]: Jump to bootloader. Module: ${ModuleSlotToId[module].toString()}`);
const transfer = Buffer.from([UsbCommand.JumpToModuleBootloader, module]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,44 @@ <h1>
>
</td>
<td>
<button *ngIf="hostConnection.hasAddress()"
[disabled]="isDonglePairing"
(confirm)="deleteHostConnection(index, hostConnection)"
type="button"
class="btn"
mwlConfirmationPopover
popoverTitle="Do you really want to delete this connection?"
placement="bottom"
confirmText="Yes"
cancelText="No"
>
<fa-icon [icon]="faTrash" />
</button>
<div class="d-inline-flex align-items-center gap-2">
<button *ngIf="hostConnection.hasAddress()"
[disabled]="eraseBleSettingsButtonState.disabled"
(confirm)="deleteHostConnection(index, hostConnection)"
type="button"
class="btn"
mwlConfirmationPopover
popoverTitle="Do you really want to delete this connection?"
placement="bottom"
confirmText="Yes"
cancelText="No"
>
<fa-icon [icon]="faTrash" />
</button>

<fa-icon *ngIf="showNotPairedTooltip(hostConnection)"
[icon]="faCircleExclamation"
ngbTooltip="This connection has been unpaired. You can re-pair this device."
/>
</div>
</td>
</tr>
</ng-container>
</tbody>
</table>

<button *ngIf="eraseBleSettingsButtonState.visible"
class="btn btn-danger mt-3"
mwlConfirmationPopover
popoverTitle="Are you sure?"
placement="bottom"
confirmText="Yes"
cancelText="No"
[disabled]="eraseBleSettingsButtonState.disabled"
(confirm)="eraseBleSettings()"
>
<fa-icon *ngIf="eraseBleSettingsButtonState.erasing"
[icon]="faSpinner"
animation="spin" />
Delete device pairings
</button>
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
import { ChangeDetectorRef } from '@angular/core';
import { Component, OnDestroy, OnInit } from '@angular/core';
import { DragulaService } from '@ert78gb/ng2-dragula';
import { faCircleNodes, faTrash } from '@fortawesome/free-solid-svg-icons';
import { faCircleExclamation, faCircleNodes, faSpinner, faTrash } from '@fortawesome/free-solid-svg-icons';
import { Store } from '@ngrx/store';
import { Subscription } from 'rxjs';
import { HostConnection } from 'uhk-common';

import { EraseBleSettingsButtonState } from '../../../models/index';
import { CheckAreHostConnectionsPairedAction, EraseBleSettingAction } from '../../../store/actions/device';
import { DeleteHostConnectionAction } from '../../../store/actions/dongle-pairing.action';
import {
RenameHostConnectionAction,
ReorderHostConnectionsAction,
SetHostConnectionSwitchoverAction,
} from '../../../store/actions/user-config';
import { AppState, getHostConnections, isDonglePairing } from '../../../store/index';
import { getHostConnectionPairState } from '../../../store/index';
import { AppState, getEraseBleSettingsButtonState, getHostConnections, isDonglePairing } from '../../../store/index';

@Component({
selector: 'host-connections',
Expand All @@ -24,19 +27,25 @@ import { AppState, getHostConnections, isDonglePairing } from '../../../store/in
})
export class HostConnectionsComponent implements OnInit, OnDestroy {
faCircleNodes = faCircleNodes;
faSpinner = faSpinner;
faTrash = faTrash;
faCircleExclamation = faCircleExclamation;

hostConnectionPairState: Record<string, boolean> = {};
eraseBleSettingsButtonState: EraseBleSettingsButtonState;
hostConnections: HostConnection[] = [] as HostConnection[];
isDonglePairing: boolean;
dragAndDropGroup = 'HOST_CONNECTION';

private hostConnectionPairStateSubscription: Subscription;
private eraseBleSettingsSubscription: Subscription;
private hostConnectionsSubscription: Subscription;
private isDonglePairingSubscription: Subscription;

constructor(private dragulaService: DragulaService,
private cdRef: ChangeDetectorRef,
private store: Store<AppState>) {

this.store.dispatch(new CheckAreHostConnectionsPairedAction());

dragulaService.createGroup(this.dragAndDropGroup, {
moves: (el, container, handle) => {
if (!handle) {
Expand All @@ -57,30 +66,37 @@ export class HostConnectionsComponent implements OnInit, OnDestroy {
}

ngOnInit(): void {
this.eraseBleSettingsSubscription = this.store.select(getEraseBleSettingsButtonState)
.subscribe(eraseBleSettingsButtonState => {
this.eraseBleSettingsButtonState = eraseBleSettingsButtonState;
this.cdRef.markForCheck();
});
this.hostConnectionPairStateSubscription = this.store.select(getHostConnectionPairState)
.subscribe(hostConnectionPairState => {
this.hostConnectionPairState = hostConnectionPairState;
});
this.hostConnectionsSubscription = this.store.select(getHostConnections)
.subscribe(hostConnections => {
this.hostConnections = hostConnections;
this.cdRef.markForCheck();
});
this.isDonglePairingSubscription = this.store.select(isDonglePairing)
.subscribe(isDonglePairing => {
this.isDonglePairing = isDonglePairing;
this.cdRef.markForCheck();
});
}

ngOnDestroy(): void {
this.dragulaService.destroy(this.dragAndDropGroup);
if(this.hostConnectionsSubscription) {
this.hostConnectionsSubscription.unsubscribe();
}
this.isDonglePairingSubscription?.unsubscribe();
this.eraseBleSettingsSubscription?.unsubscribe();
this.hostConnectionPairStateSubscription?.unsubscribe();
this.hostConnectionsSubscription?.unsubscribe();
}

deleteHostConnection(index: number, hostConnection: HostConnection): void {
this.store.dispatch(new DeleteHostConnectionAction({index, hostConnection}));
}

eraseBleSettings(): void {
this.store.dispatch(new EraseBleSettingAction());
}

renameHostConnection(index: number, newName: string): void {
this.store.dispatch(new RenameHostConnectionAction({
index,
Expand All @@ -95,4 +111,8 @@ export class HostConnectionsComponent implements OnInit, OnDestroy {
setHostConnectionSwitchover(index: number, checked: boolean): void {
this.store.dispatch(new SetHostConnectionSwitchoverAction({index, checked}));
}

showNotPairedTooltip(hostConnection: HostConnection): boolean {
return hostConnection.hasAddress() && !this.hostConnectionPairState[hostConnection.address];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface EraseBleSettingsButtonState {
disabled: boolean;
erasing: boolean;
visible: boolean;
}
1 change: 1 addition & 0 deletions packages/uhk-web/src/app/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from './delete-host-connection-payload';
export * from './device-ui-states';
export * from './dongle-pairing-state';
export * from './duplicate-macro-action-payload';
export * from './erase-ble-settings-button-state';
export * from './exchange-keys-action.model';
export * from './firmware-upgrade-state';
export * from './firmware-upgrade-steps';
Expand Down
19 changes: 19 additions & 0 deletions packages/uhk-web/src/app/services/device-renderer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Injectable, NgZone } from '@angular/core';
import { Action, Store } from '@ngrx/store';

import {
AreBleAddressesPairedIpcResponse,
ChangeKeyboardLayoutIpcResponse,
DeviceConnectionState,
DeviceVersionInformation,
Expand Down Expand Up @@ -33,8 +34,10 @@ import {
import { IpcCommonRenderer } from './ipc-common-renderer';
import {
ChangeKeyboardLayoutReplyAction,
CheckAreHostConnectionsPairedReplyAction,
ConnectionStateChangedAction,
DongleVersionInfoLoadedAction,
EraseBleSettingReplyAction,
CurrentlyUpdateSkipModuleAction,
CurrentlyUpdatingModuleAction,
HardwareModulesLoadedAction,
Expand Down Expand Up @@ -65,6 +68,10 @@ export class DeviceRendererService {
this.logService.misc('[DeviceRendererService] init success ');
}

areBleAddressesPaired(addresses: string[]): void {
this.ipcRenderer.send(IpcEvents.device.areBleAddressesPaired, addresses);
}

changeKeyboardLayout(layout: KeyboardLayout, hardwareConfiguration: HardwareConfiguration): void {
this.ipcRenderer.send(IpcEvents.device.changeKeyboardLayout, layout, hardwareConfiguration.toJsonObject());
}
Expand All @@ -77,6 +84,10 @@ export class DeviceRendererService {
});
}

eraseBleSettings(): void {
this.ipcRenderer.send(IpcEvents.device.eraseBleSettings);
}

setPrivilegeOnLinux(): void {
this.ipcRenderer.send(IpcEvents.device.setPrivilegeOnLinux);
}
Expand Down Expand Up @@ -137,6 +148,10 @@ export class DeviceRendererService {
}

private registerEvents(): void {
this.ipcRenderer.on(IpcEvents.device.areBleAddressesPairedReply, (event: string, response: AreBleAddressesPairedIpcResponse) => {
this.dispachStoreAction(new CheckAreHostConnectionsPairedReplyAction(response));
});

this.ipcRenderer.on(IpcEvents.device.changeKeyboardLayoutReply, (event: string, response: ChangeKeyboardLayoutIpcResponse) => {
this.dispachStoreAction(new ChangeKeyboardLayoutReplyAction(response));
});
Expand All @@ -153,6 +168,10 @@ export class DeviceRendererService {
this.dispachStoreAction(new DeleteHostConnectionFailedAction(message));
});

this.ipcRenderer.on(IpcEvents.device.eraseBleSettingsReply, (event: string, response: IpcResponse) => {
this.dispachStoreAction(new EraseBleSettingReplyAction(response));
});

this.ipcRenderer.on(IpcEvents.device.hardwareModulesLoaded, (event: string, response: HardwareModules) => {
this.dispachStoreAction(new HardwareModulesLoadedAction(response));
});
Expand Down
Loading
Loading