Skip to content

Commit

Permalink
[CP-3185] Integrate the flashing mechanism with the application on Wi…
Browse files Browse the repository at this point in the history
…ndows (#2126)
  • Loading branch information
dkarski authored Oct 16, 2024
1 parent 1fdedd4 commit c90eaef
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 24 deletions.
13 changes: 12 additions & 1 deletion libs/core/core/hooks/use-msc-device-detached-effect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
abortMscFlashing,
FlashingProcessState,
selectIsFlashingInActivePhases,
selectIsFlashingInState,
setMscFlashingInitialState,
} from "msc-flash-harmony"
import { Dispatch } from "Core/__deprecated__/renderer/store"

Expand All @@ -35,6 +37,10 @@ export const useMscDeviceDetachedEffect = () => {
const useHandleDevicesDetached = () => {
const dispatch = useDispatch<Dispatch>()
const flashingInActivePhases = useSelector(selectIsFlashingInActivePhases)
const flashingInWaitingForBackButtonState = useSelector(
selectIsFlashingInState(FlashingProcessState.WaitingForBackButton)
)

return useCallback(
(deviceDetachedEvents: DeviceBaseProperties[]) => {
const mscEvents = deviceDetachedEvents.filter(
Expand All @@ -45,11 +51,16 @@ const useHandleDevicesDetached = () => {
return
}

if (flashingInWaitingForBackButtonState) {
dispatch(setMscFlashingInitialState())
return
}

const reason = flashingInActivePhases
? FlashingProcessState.Failed
: undefined
dispatch(abortMscFlashing({ reason }))
},
[dispatch, flashingInActivePhases]
[dispatch, flashingInActivePhases, flashingInWaitingForBackButtonState]
)
}
1 change: 1 addition & 0 deletions libs/generic-view/store/src/lib/action-names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ export enum ActionName {
MscFlashingSetProcessState = "msc-flashing/set-process-state",
MscFlashingSetAbort = "msc-flashing/set-abort",
MscFlashingAbort = "msc-flashing/abort",
MscFlashingSetInitialState = "msc-flashing/set-initial-state",

GetEntitiesConfig = "entities/get-entities-config",
SetEntitiesConfig = "entities/set-entities-config",
Expand Down
4 changes: 4 additions & 0 deletions libs/msc-flash/msc-flash-harmony/src/lib/actions/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@ import { ActionName } from "generic-view/store"
export const setMscFlashingAbort = createAction<AbortController | undefined>(
ActionName.MscFlashingSetAbort
)

export const setMscFlashingInitialState = createAction(
ActionName.MscFlashingSetInitialState
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

import { createReducer } from "@reduxjs/toolkit"
import { FlashingState } from "./flashing.interface"
import { getMscFlashingFilesDetails, setFlashingProcessState } from "../actions"
import {
getMscFlashingFilesDetails,
setFlashingProcessState,
setMscFlashingInitialState,
} from "../actions"
import { FlashingProcessState } from "../constants"
import { setMscFlashingAbort } from "../actions/actions"

Expand All @@ -28,5 +32,8 @@ export const flashingReducer = createReducer<FlashingState>(
.addCase(setMscFlashingAbort, (state, action) => {
state.abortController = action.payload
})
.addCase(setMscFlashingInitialState, () => {
return { ...initialState }
})
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from "./select-flashing-state"
export * from "./select-flashing-abort-controller"
export * from "./select-flashing-process-state"
export * from "./select-is-flashing-in-active-phases"
export * from "./select-is-flashing-in-state"
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* Copyright (c) Mudita sp. z o.o. All rights reserved.
* For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md
*/

import { createSelector } from "@reduxjs/toolkit"
import { FlashingProcessState } from "../constants"
import { selectFlashingProcessState } from "./select-flashing-process-state"

export const selectIsFlashingInState = (targetState: FlashingProcessState) =>
createSelector(
selectFlashingProcessState,
(flashingProcessState) => flashingProcessState === targetState
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,20 @@
import IDeviceFlash from "./device-flash.interface"
import LinuxDeviceFlashService from "./linux/linux-device-flash.service"
import MacDeviceFlashService from "./macos/macos-device-flash-service"
import WindowsDeviceFlashService from "./windows/windows-device-flash.service"

class DeviceFlashFactory {
static createDeviceFlashService(temporaryDirectoryPath: string): IDeviceFlash {
static createDeviceFlashService(
temporaryDirectoryPath: string
): IDeviceFlash {
const platform = process.platform

if (platform === "linux") {
return new LinuxDeviceFlashService()
} else if (platform === "darwin") {
return new MacDeviceFlashService(temporaryDirectoryPath)
} else if (platform === "win32") {
return new WindowsDeviceFlashService()
} else {
throw new Error(`Unsupported platform: ${platform}`)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* Copyright (c) Mudita sp. z o.o. All rights reserved.
* For licensing, see https://github.com/mudita/mudita-center/blob/master/LICENSE.md
*/

import {
execCommandWithSudo,
execPromise,
splitPathToDirNameAndBaseName,
} from "shared/utils"
import IDeviceFlash from "../device-flash.interface"

interface DiskInformation {
DiskNumber: number
FriendlyName: string
Size: string
OperationalStatus: string
}

class WindowsDeviceFlashService implements IDeviceFlash {
async findDeviceByDeviceName(deviceName: string): Promise<string> {
console.log(
`Searching for the device with the friendly name: ${deviceName}`
)

const getDiskResult = await execPromise(
`powershell.exe -Command "Get-Disk | Where-Object { $_.FriendlyName -eq '${deviceName}' }| ConvertTo-Json"`
)

if (!getDiskResult) {
throw new Error(`Disk not found for friendly name: ${deviceName}`)
}

const diskInformation: DiskInformation = JSON.parse(getDiskResult)

console.log(
`Disk information retrieved successfully: Disk Number - ${diskInformation.DiskNumber}, Size - ${diskInformation.Size} bytes, Status - ${diskInformation.OperationalStatus}`
)

return String(diskInformation.DiskNumber)
}

async execute(
device: string,
imagePath: string,
scriptPath: string
): Promise<void> {
await this.flashDevice(device, imagePath, scriptPath)
console.log("Flash process completed successfully")
}

private async flashDevice(
device: string,
imagePath: string,
scriptPath: string
): Promise<void> {
const [path, scriptBasename] = splitPathToDirNameAndBaseName(scriptPath)
const [, imageBasename] = splitPathToDirNameAndBaseName(imagePath)
const command = `cd ${path} && powershell.exe -ExecutionPolicy Bypass -File ${scriptBasename} -file ${imageBasename} -diskid ${device} -force`

try {
await execCommandWithSudo(command)
} catch (error) {
throw new Error(
`An error occurred during flashing: ${JSON.stringify(error)}`
)
}
}
}

export default WindowsDeviceFlashService
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,23 @@

import path from "path"
import { Dispatch, ReduxRootState } from "Core/__deprecated__/renderer/store"
import logger from "Core/__deprecated__/main/utils/logger"
import getAppSettingsMain from "Core/__deprecated__/main/functions/get-app-settings"
import { RELEASE_SPACE } from "Core/update/constants/release-space.constant"
import { FlashingProcessState, SupportedPlatform, Product } from "../constants"
import { setFlashingProcessState } from "../actions/set-flashing-process-state.action"
import { getMscFlashingFilesDetails } from "../actions/get-msc-flashing-files-details.action"
import { MscFlashDetails } from "../dto"
import { downloadFlashingFileRequest } from "../requests"
import { setMscFlashingAbort } from "../actions/actions"
import { selectIsFlashingInActivePhases } from "../selectors"
import { unpackFlashingImageService } from "./unpack-flashing-image"
import DeviceFlashFactory from "./device-flash/device-flash.factory"
import getAppSettingsMain from "Core/__deprecated__/main/functions/get-app-settings"

const IMAGE_FILE_NAME = "BellHybrid.img"
import { RELEASE_SPACE } from "Core/update/constants/release-space.constant"
import MacDeviceFlashService from "./device-flash/macos/macos-device-flash-service"
import IDeviceFlash from "./device-flash/device-flash.interface"
import { removeDownloadedMscFiles } from "./remove-downloaded-msc-files.service"
import { setMscFlashingAbort } from "../actions/actions"
import { selectIsFlashingInActivePhases } from "../selectors"
import logger from "Core/__deprecated__/main/utils/logger"

const IMAGE_FILE_NAME = "BellHybrid.img"

export const flashMscDeviceService =
() => async (dispatch: Dispatch, getState: () => ReduxRootState) => {
Expand Down Expand Up @@ -148,34 +149,62 @@ const startFlashingProcess = async (

const deviceFlash =
DeviceFlashFactory.createDeviceFlashService(osDownloadLocation)
const deviceName = getDeviceName()
const device = await deviceFlash.findDeviceByDeviceName(deviceName)

const device = await deviceFlash.findDeviceByDeviceName("HARMONY")

const flashingScriptName = flashingFiles
? flashingFiles.scripts[0].name
: ""

const imageFilePath = path.join(osDownloadLocation, IMAGE_FILE_NAME)
const scriptFilePath = path.join(osDownloadLocation, flashingScriptName)
const { imageFilePath, scriptFilePath } = buildFlashingFilePaths(
flashingFiles,
osDownloadLocation
)

await deviceFlash.execute(device, imageFilePath, scriptFilePath)

if (signal.aborted) {
return
}

if (deviceFlash instanceof MacDeviceFlashService) {
dispatch(setFlashingProcessState(FlashingProcessState.TerminalOpened))

await deviceFlash.waitForFlashCompletion({ signal })
}
await handlePostExecutingTasks(deviceFlash, dispatch, signal)

if (signal.aborted) {
return
}
dispatch(setFlashingProcessState(FlashingProcessState.Restarting))

await removeDownloadedMscFiles()
} catch (error) {
throw new Error(`Flash process failed with error: ${JSON.stringify(error)}`)
}
}

const getDeviceName = () => {
return process.platform === "win32" ? "MUDITA HARMONY MSC" : "HARMONY"
}

const buildFlashingFilePaths = (
flashingFiles: MscFlashDetails | undefined,
osDownloadLocation: string
) => {
const flashingFilesScripts =
process.platform === "win32"
? flashingFiles?.scripts[1]
: flashingFiles?.scripts[0]
const flashingScriptName = flashingFilesScripts?.name ?? ""
const imageFilePath = path.join(osDownloadLocation, IMAGE_FILE_NAME)
const scriptFilePath = path.join(osDownloadLocation, flashingScriptName)

return { imageFilePath, scriptFilePath }
}

const handlePostExecutingTasks = async (
deviceFlash: IDeviceFlash,
dispatch: Dispatch,
signal: AbortSignal
) => {
if (deviceFlash instanceof MacDeviceFlashService) {
dispatch(setFlashingProcessState(FlashingProcessState.TerminalOpened))
await deviceFlash.waitForFlashCompletion({ signal })
} else if (process.platform === "win32") {
dispatch(setFlashingProcessState(FlashingProcessState.WaitingForBackButton))
} else {
dispatch(setFlashingProcessState(FlashingProcessState.Restarting))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export const unpackFlashingImageService = async (
const imageFilePath = path.join(osDownloadLocation, fileName)
command = `tar -xf "${imageFilePath}" -C "${osDownloadLocation}"`
}
if (process.platform === "win32") {
const imageFilePath = path.join(osDownloadLocation, fileName)
command = `tar -xzvf "${imageFilePath}" -C "${osDownloadLocation}"`
}

try {
await execPromise(command)
Expand Down

0 comments on commit c90eaef

Please sign in to comment.