Skip to content

Commit

Permalink
Handle opening and closing devices
Browse files Browse the repository at this point in the history
  • Loading branch information
Mrtenz committed Nov 13, 2024
1 parent ac721ce commit b7204de
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 6 deletions.
52 changes: 47 additions & 5 deletions packages/snaps-controllers/src/devices/DeviceController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ import type {
WriteDeviceParams,
} from '@metamask/snaps-sdk';
import { DeviceType } from '@metamask/snaps-sdk';
import { logError } from '@metamask/snaps-utils';
import { assert, createDeferredPromise, hasProperty } from '@metamask/utils';

import { CLOSE_DEVICE_TIMEOUT } from './constants';
import { HIDManager } from './implementations';
import type { SnapDevice } from './implementations/device';
import type { DeviceManager } from './implementations/device-manager';
Expand Down Expand Up @@ -98,11 +100,6 @@ export type DeviceControllerMessenger = RestrictedControllerMessenger<
DeviceControllerAllowedEvents['type']
>;

export type ConnectedDevice = {
reference: any; // TODO: Type this
metadata: Device;
};

export type DeviceControllerState = {
devices: Record<string, Device>;
pairing: {
Expand Down Expand Up @@ -136,6 +133,8 @@ export class DeviceController extends BaseController<

#devices: Record<DeviceId, SnapDevice> = {};

#timeouts: Record<DeviceId, NodeJS.Timeout> = {};

constructor({ messenger, state }: DeviceControllerArgs) {
super({
messenger,
Expand Down Expand Up @@ -240,6 +239,7 @@ export class DeviceController extends BaseController<
const device = this.#devices[id];
assert(device, 'Device not found.');

await this.#openDevice(id);
await device.write(params);

return null;
Expand All @@ -255,6 +255,7 @@ export class DeviceController extends BaseController<
const device = this.#devices[id];
assert(device, 'Device not found.');

await this.#openDevice(id);
return await device.read(params);
}

Expand Down Expand Up @@ -346,4 +347,45 @@ export class DeviceController extends BaseController<
draftState.pairing = null;
});
}

/**
* Open a device, and set a timeout to close it if it is not used.
*
* @param id - The ID of the device to open.
* @returns A promise that resolves when the device is opened.
*/
async #openDevice(id: DeviceId) {
const device = this.#devices[id];
assert(device, 'Device not found.');

await device.open();

if (this.#timeouts[id]) {
clearTimeout(this.#timeouts[id]);
}

this.#timeouts[id] = setTimeout(() => {
this.#closeDevice(id).catch((error) => {
logError('Failed to close device.', error);
});
}, CLOSE_DEVICE_TIMEOUT);
}

/**
* Close a device.
*
* @param id - The ID of the device to close.
* @returns A promise that resolves when the device is closed.
*/
async #closeDevice(id: DeviceId) {
const device = this.#devices[id];
assert(device, 'Device not found.');

if (this.#timeouts[id]) {
clearTimeout(this.#timeouts[id]);
delete this.#timeouts[id];
}

await device.close();
}
}
3 changes: 3 additions & 0 deletions packages/snaps-controllers/src/devices/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Duration, inMilliseconds } from '@metamask/utils';

export const CLOSE_DEVICE_TIMEOUT = inMilliseconds(5, Duration.Second);
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ export abstract class SnapDevice extends TypedEventEmitter<SnapDeviceEvents> {
*/
abstract write(params: WriteDeviceParams): Promise<void>;

/**
* Open the connection to the device.
*/
abstract open(): Promise<void>;

/**
* Close the connection to the device.
*/
Expand Down
15 changes: 14 additions & 1 deletion packages/snaps-controllers/src/devices/implementations/hid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class HIDSnapDevice extends SnapDevice {
*/
async read({ type, reportType = 'output', reportId = 0 }: ReadDeviceParams) {
assert(type === this.type);
assert(this.#device.opened, 'Device is not open.');

if (reportType === 'feature') {
const view = await this.#device.receiveFeatureReport(reportId);
Expand Down Expand Up @@ -102,6 +103,7 @@ export class HIDSnapDevice extends SnapDevice {
data,
}: WriteDeviceParams) {
assert(type === this.type);
assert(this.#device.opened, 'Device is not open.');

const buffer = hexToBytes(data);
if (reportType === 'feature') {
Expand All @@ -111,10 +113,21 @@ export class HIDSnapDevice extends SnapDevice {
return await this.#device.sendReport(reportId, buffer);
}

/**
* Open the connection to the device.
*/
async open() {
if (!this.#device.opened) {
await this.#device.open();
}
}

/**
* Close the connection to the device.
*/
async close() {
await this.#device.close();
if (this.#device.opened) {
await this.#device.close();
}
}
}

0 comments on commit b7204de

Please sign in to comment.