From beb7a168a40ecabea5b0d202badd5f3d66ec63dd Mon Sep 17 00:00:00 2001 From: Daniel Karski Date: Wed, 23 Oct 2024 08:18:29 +0200 Subject: [PATCH] [CP-3210][Re-flashing Mac] Simplify logic by applying filters in device retrieval (#2134) --- .../usb-devices/usb-devices-mac.helper.ts | 10 +- .../macos/macos-device-flash-service.ts | 11 +- .../macos-usb-port-device-parser.interface.ts | 2 + .../macos-usb-port-device-parser.test.ts | 211 ++++++++++++++++++ .../macos-usb-port-device-parser.ts | 25 ++- 5 files changed, 241 insertions(+), 18 deletions(-) diff --git a/libs/core/device-manager/services/usb-devices/usb-devices-mac.helper.ts b/libs/core/device-manager/services/usb-devices/usb-devices-mac.helper.ts index 035183a934..b46b5f86a7 100644 --- a/libs/core/device-manager/services/usb-devices/usb-devices-mac.helper.ts +++ b/libs/core/device-manager/services/usb-devices/usb-devices-mac.helper.ts @@ -9,13 +9,11 @@ import { ProductID, VendorID } from "Core/device/constants" export const getUsbDevicesMacOS = async (): Promise => { try { - const devices = await MacosUSBPortDeviceParser.getUSBPortDevices() - const device = devices.find((device) => { - return ( - device.vendorId?.includes(VendorID.MuditaHarmony) && - device.productId?.includes(ProductID.MuditaHarmonyMsc) - ) + const devices = await MacosUSBPortDeviceParser.getUSBPortDevices({ + vendorId: VendorID.MuditaHarmony, + productId: ProductID.MuditaHarmonyMsc, }) + const device = devices[0] if (device !== undefined) { return device diff --git a/libs/msc-flash/msc-flash-harmony/src/lib/services/device-flash/macos/macos-device-flash-service.ts b/libs/msc-flash/msc-flash-harmony/src/lib/services/device-flash/macos/macos-device-flash-service.ts index c8d6bae770..80baf3fdfb 100644 --- a/libs/msc-flash/msc-flash-harmony/src/lib/services/device-flash/macos/macos-device-flash-service.ts +++ b/libs/msc-flash/msc-flash-harmony/src/lib/services/device-flash/macos/macos-device-flash-service.ts @@ -32,14 +32,11 @@ class MacDeviceFlashService implements IDeviceFlash { async findDeviceByDeviceName(): Promise { console.log(`Searching for device...`) - const devices = await MacosUSBPortDeviceParser.getUSBPortDevices() - - const device = devices.find((device) => { - return ( - device.vendorId?.includes("3310") && - device.name?.includes("Mudita Harmony (MSC mode)") - ) + const devices = await MacosUSBPortDeviceParser.getUSBPortDevices({ + vendorId: "3310", + name: "Mudita Harmony (MSC mode)", }) + const device = devices[0] if (!device) { console.error( diff --git a/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.interface.ts b/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.interface.ts index d72951e307..f5c5ad1e83 100644 --- a/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.interface.ts +++ b/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.interface.ts @@ -21,3 +21,5 @@ export interface USBPortDevice extends USBDevice, PortInfo { path: string pnpId?: string | undefined } + +export type USBPortDeviceFilters = Partial; diff --git a/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.test.ts b/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.test.ts index 1d71c7453a..847c259a73 100644 --- a/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.test.ts +++ b/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.test.ts @@ -421,3 +421,214 @@ USB: expect(devices.length).toBe(0) }) }) + +it("should correctly filter devices by vendorId", async () => { + const output = ` +USB: + USB 3.1 Bus: + Host Controller Driver: AppleT8122USBXHCI + Mudita Harmony (MSC mode): + Product ID: 0x0103 + Vendor ID: 0x3310 + Version: 1.01 + Serial Number: 0123456789ABCDEF + Manufacturer: Mudita + Mudita Bell: + Product ID: 0x0104 + Vendor ID: 0x3311 + Version: 1.02 + Serial Number: ABCDEF1234567890 + Manufacturer: Mudita +` + ;(execPromise as jest.Mock).mockResolvedValue(output) + + const devices = await MacosUSBPortDeviceParser.getUSBPortDevices({ vendorId: '3310' }) + + expect(devices.length).toBe(1) + expect(devices[0]).toEqual({ + productId: '0103', + vendorId: '3310', + version: '1.01', + serialNumber: '0123456789ABCDEF', + manufacturer: 'Mudita', + name: 'Mudita Harmony (MSC mode)', + path: '3310/0103/0123456789ABCDEF', + }) +}) + +it("should correctly filter devices by productId", async () => { + const output = ` +USB: + USB 3.1 Bus: + Host Controller Driver: AppleT8122USBXHCI + Mudita Harmony (MSC mode): + Product ID: 0x0103 + Vendor ID: 0x3310 + Version: 1.01 + Serial Number: 0123456789ABCDEF + Manufacturer: Mudita + Mudita Bell: + Product ID: 0x0104 + Vendor ID: 0x3310 + Version: 1.02 + Serial Number: ABCDEF1234567890 + Manufacturer: Mudita +` + ;(execPromise as jest.Mock).mockResolvedValue(output) + + const devices = await MacosUSBPortDeviceParser.getUSBPortDevices({ productId: '0104' }) + + expect(devices.length).toBe(1) + expect(devices[0]).toEqual({ + productId: '0104', + vendorId: '3310', + version: '1.02', + serialNumber: 'ABCDEF1234567890', + manufacturer: 'Mudita', + name: 'Mudita Bell', + path: '3310/0104/ABCDEF1234567890', + }) +}) + +it("should correctly filter devices by name", async () => { + const output = ` +USB: + USB 3.1 Bus: + Host Controller Driver: AppleT8122USBXHCI + Mudita Harmony (MSC mode): + Product ID: 0x0103 + Vendor ID: 0x3310 + Version: 1.01 + Serial Number: 0123456789ABCDEF + Manufacturer: Mudita + Mudita Bell: + Product ID: 0x0104 + Vendor ID: 0x3310 + Version: 1.02 + Serial Number: ABCDEF1234567890 + Manufacturer: Mudita +` + ;(execPromise as jest.Mock).mockResolvedValue(output) + + const devices = await MacosUSBPortDeviceParser.getUSBPortDevices({ name: 'Mudita Bell' }) + + expect(devices.length).toBe(1) + expect(devices[0]).toEqual({ + productId: '0104', + vendorId: '3310', + version: '1.02', + serialNumber: 'ABCDEF1234567890', + manufacturer: 'Mudita', + name: 'Mudita Bell', + path: '3310/0104/ABCDEF1234567890', + }) +}) + +it("should correctly filter devices by vendorId and productId when both match", async () => { + const output = ` +USB: + USB 3.1 Bus: + Host Controller Driver: AppleT8122USBXHCI + Mudita Harmony (MSC mode): + Product ID: 0x0103 + Vendor ID: 0x3310 + Version: 1.01 + Serial Number: 0123456789ABCDEF + Manufacturer: Mudita + Mudita Bell: + Product ID: 0x0104 + Vendor ID: 0x3311 + Version: 1.02 + Serial Number: ABCDEF1234567890 + Manufacturer: Mudita +` + ;(execPromise as jest.Mock).mockResolvedValue(output) + + const devices = await MacosUSBPortDeviceParser.getUSBPortDevices({ vendorId: '3310', productId: '0103' }) + + expect(devices.length).toBe(1) + expect(devices[0]).toEqual({ + productId: '0103', + vendorId: '3310', + version: '1.01', + serialNumber: '0123456789ABCDEF', + manufacturer: 'Mudita', + name: 'Mudita Harmony (MSC mode)', + path: '3310/0103/0123456789ABCDEF', + }) +}) + +it("should return an empty array when vendorId matches but productId does not", async () => { + const output = ` +USB: + USB 3.1 Bus: + Host Controller Driver: AppleT8122USBXHCI + Mudita Harmony (MSC mode): + Product ID: 0x0103 + Vendor ID: 0x3310 + Version: 1.01 + Serial Number: 0123456789ABCDEF + Manufacturer: Mudita + Mudita Bell: + Product ID: 0x0104 + Vendor ID: 0x3311 + Version: 1.02 + Serial Number: ABCDEF1234567890 + Manufacturer: Mudita +` + ;(execPromise as jest.Mock).mockResolvedValue(output) + + const devices = await MacosUSBPortDeviceParser.getUSBPortDevices({ vendorId: '3310', productId: '0104' }) + + expect(devices.length).toBe(0) +}) + +it("should return an empty array when productId matches but vendorId does not", async () => { + const output = ` +USB: + USB 3.1 Bus: + Host Controller Driver: AppleT8122USBXHCI + Mudita Harmony (MSC mode): + Product ID: 0x0103 + Vendor ID: 0x3310 + Version: 1.01 + Serial Number: 0123456789ABCDEF + Manufacturer: Mudita + Mudita Bell: + Product ID: 0x0104 + Vendor ID: 0x3311 + Version: 1.02 + Serial Number: ABCDEF1234567890 + Manufacturer: Mudita +` + ;(execPromise as jest.Mock).mockResolvedValue(output) + + const devices = await MacosUSBPortDeviceParser.getUSBPortDevices({ vendorId: '3311', productId: '0103' }) + + expect(devices.length).toBe(0) +}) + +it("should return an empty array when neither vendorId nor productId match", async () => { + const output = ` +USB: + USB 3.1 Bus: + Host Controller Driver: AppleT8122USBXHCI + Mudita Harmony (MSC mode): + Product ID: 0x0103 + Vendor ID: 0x3310 + Version: 1.01 + Serial Number: 0123456789ABCDEF + Manufacturer: Mudita + Mudita Bell: + Product ID: 0x0104 + Vendor ID: 0x3311 + Version: 1.02 + Serial Number: ABCDEF1234567890 + Manufacturer: Mudita +` + ;(execPromise as jest.Mock).mockResolvedValue(output) + + const devices = await MacosUSBPortDeviceParser.getUSBPortDevices({ vendorId: '9999', productId: '9999' }) + + expect(devices.length).toBe(0) +}) diff --git a/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.ts b/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.ts index f3f02932cd..a2384582b7 100644 --- a/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.ts +++ b/libs/shared/utils/src/lib/macos-usb-port-device-parser/macos-usb-port-device-parser.ts @@ -3,10 +3,12 @@ * For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md */ +import isMatch from "lodash/isMatch" import { execPromise } from "../exec-command" import { USBDevice, USBPortDevice, + USBPortDeviceFilters, } from "./macos-usb-port-device-parser.interface" const fieldPatterns: Partial> = { @@ -20,16 +22,22 @@ const fieldPatterns: Partial> = { } export class MacosUSBPortDeviceParser { - static async getUSBPortDevices(): Promise { + static async getUSBPortDevices( + filters?: USBPortDeviceFilters + ): Promise { const usbDevices = await MacosUSBPortDeviceParser.getUSBDevice() - return usbDevices.map((usbDevice) => { + return usbDevices.reduce((filteredDevices, usbDevice) => { const vendorId = usbDevice.vendorId?.replace("0x", "") const productId = usbDevice.productId?.replace("0x", "") const serialNumber = usbDevice.serialNumber?.replace("0x", "") const locationId = usbDevice.locationId?.split(" ")[0] - const path = vendorId && productId && serialNumber && `${vendorId}/${productId}/${serialNumber}` + const path = + vendorId && + productId && + serialNumber && + `${vendorId}/${productId}/${serialNumber}` - return { + const mappedDevice: USBPortDevice = { ...usbDevice, productId, vendorId, @@ -37,7 +45,14 @@ export class MacosUSBPortDeviceParser { locationId, path: path ?? "unknown", } - }) + + if (filters && !isMatch(mappedDevice, filters)) { + return filteredDevices + } + + filteredDevices.push(mappedDevice) + return filteredDevices + }, []) } private static async getUSBDevice(): Promise {