@yume-chan/adb-daemon-webusb
Version:
Adb daemon transport connection for `@yume-chan/adb` using WebUSB API.
113 lines (99 loc) • 3.55 kB
text/typescript
import {
AdbDaemonWebUsbDevice,
mergeDefaultAdbInterfaceFilter,
} from "./device.js";
import { AdbDaemonWebUsbDeviceObserver } from "./observer.js";
import { isErrorName, matchFilters } from "./utils.js";
export namespace AdbDaemonWebUsbDeviceManager {
export interface RequestDeviceOptions {
filters?: USBDeviceFilter[] | undefined;
exclusionFilters?: USBDeviceFilter[] | undefined;
}
}
export class AdbDaemonWebUsbDeviceManager {
/**
* Gets the instance of {@link AdbDaemonWebUsbDeviceManager} using browser WebUSB implementation.
*
* May be `undefined` if current runtime does not support WebUSB.
*/
static readonly BROWSER = /* #__PURE__ */ (() =>
typeof globalThis.navigator !== "undefined" && globalThis.navigator.usb
? new AdbDaemonWebUsbDeviceManager(globalThis.navigator.usb)
: undefined)();
readonly #usbManager: USB;
/**
* Create a new instance of {@link AdbDaemonWebUsbDeviceManager} using the specified WebUSB implementation.
* @param usbManager A WebUSB compatible interface.
*/
constructor(usbManager: USB) {
this.#usbManager = usbManager;
}
/**
* Call `USB#requestDevice()` to prompt the user to select a device.
*/
async requestDevice(
options: AdbDaemonWebUsbDeviceManager.RequestDeviceOptions = {},
): Promise<AdbDaemonWebUsbDevice | undefined> {
const filters = mergeDefaultAdbInterfaceFilter(options.filters);
try {
const device = await this.#usbManager.requestDevice({
filters,
exclusionFilters: options.exclusionFilters,
});
const interface_ = matchFilters(
device,
filters,
options.exclusionFilters,
);
if (!interface_) {
// `#usbManager` doesn't support `exclusionFilters`,
// selected device is invalid
return undefined;
}
return new AdbDaemonWebUsbDevice(
device,
interface_,
this.#usbManager,
);
} catch (e) {
// No device selected
if (isErrorName(e, "NotFoundError")) {
return undefined;
}
throw e;
}
}
/**
* Get all connected and requested devices that match the specified filters.
*/
async getDevices(
options: AdbDaemonWebUsbDeviceManager.RequestDeviceOptions = {},
): Promise<AdbDaemonWebUsbDevice[]> {
const filters = mergeDefaultAdbInterfaceFilter(options.filters);
const devices = await this.#usbManager.getDevices();
// filter map
const result: AdbDaemonWebUsbDevice[] = [];
for (const device of devices) {
const interface_ = matchFilters(
device,
filters,
options.exclusionFilters,
);
if (interface_) {
result.push(
new AdbDaemonWebUsbDevice(
device,
interface_,
this.#usbManager,
),
);
}
}
return result;
}
trackDevices(
options: AdbDaemonWebUsbDeviceManager.RequestDeviceOptions = {},
): Promise<AdbDaemonWebUsbDeviceObserver> {
return AdbDaemonWebUsbDeviceObserver.create(this.#usbManager, options);
}
}