Browse Source

Fix app install and prepare for firmware update

master
Valentin D. Pinkman 7 years ago
parent
commit
e56d479905
No known key found for this signature in database GPG Key ID: E7D110669FFB8D3E
  1. 96
      src/components/ManagerPage/FirmwareUpdate.js
  2. 26
      src/internals/manager/getFirmwareInfo.js
  3. 1
      src/internals/manager/getLatestFirmwareForDevice.js
  4. 40
      src/internals/manager/helpers.js
  5. 3
      src/internals/manager/index.js
  6. 24
      src/internals/manager/installFinalFirmware.js
  7. 17
      src/internals/manager/installFirmware.js
  8. 1
      src/internals/manager/installMcu.js
  9. 24
      src/internals/manager/installOsuFirmware.js

96
src/components/ManagerPage/FirmwareUpdate.js

@ -1,6 +1,7 @@
// @flow
import React, { PureComponent } from 'react'
import isEqual from 'lodash/isEqual'
import type { Device, T } from 'types/common'
@ -16,6 +17,13 @@ type FirmwareInfos = {
notes: string,
}
type DeviceInfos = {
final: boolean,
mcu: boolean,
targetId: number,
version: string,
}
type Props = {
t: T,
device: Device,
@ -23,15 +31,27 @@ type Props = {
type State = {
latestFirmware: ?FirmwareInfos,
deviceInfos: ?DeviceInfos,
installing: boolean,
}
class FirmwareUpdate extends PureComponent<Props, State> {
state = {
latestFirmware: null,
deviceInfos: null,
installing: false,
}
componentDidMount() {
this.fetchLatestFirmware()
this.fetchLatestFirmware(true)
}
componentDidUpdate(prevProps: Props, prevState: State) {
if (!isEqual(prevState.deviceInfos, this.state.deviceInfos)) {
this.fetchDeviceInfos()
} else if (this.state.installing) {
this.installFirmware()
}
}
componentWillUnmount() {
@ -40,7 +60,7 @@ class FirmwareUpdate extends PureComponent<Props, State> {
_unmounted = false
fetchLatestFirmware = async () => {
fetchLatestFirmware = async (checkDeviceInfos: boolean = false) => {
const { device } = this.props
const latestFirmware =
CACHED_LATEST_FIRMWARE ||
@ -51,25 +71,65 @@ class FirmwareUpdate extends PureComponent<Props, State> {
successResponse: 'manager.getLatestFirmwareForDeviceSuccess',
errorResponse: 'manager.getLatestFirmwareForDeviceError',
}))
if (checkDeviceInfos) {
await this.fetchDeviceInfos()
}
// CACHED_LATEST_FIRMWARE = latestFirmware
console.log(latestFirmware)
if (!this._unmounted) {
this.setState({ latestFirmware })
}
}
handleInstallFirmware = async () => {
fetchDeviceInfos = async () => {
const { device } = this.props
const deviceInfos = await runJob({
channel: 'manager',
job: 'getFirmwareInfo', // TODO: RENAME THIS PROCESS DIFFERENTLY (EG: getInstallStep)
data: { devicePath: device.path },
successResponse: 'device.getFirmwareInfoSuccess',
errorResponse: 'device.getFirmwareInfoError',
})
if (!this._unmounted) {
this.setState(state => ({ ...state, deviceInfos }))
}
}
handleIntallOsuFirmware = async () => {
try {
const { latestFirmware } = this.state
const {
device: { path: devicePath },
} = this.props
await runJob({
channel: 'manager',
job: 'installOsuFirmware',
successResponse: 'device.osuFirmwareInstallSuccess',
errorResponse: 'device.osuFirmwareInstallError',
data: {
devicePath,
firmware: latestFirmware,
},
})
} catch (err) {
console.log(err)
}
}
handleIntallFinalFirmware = async () => {
try {
const { latestFirmware } = this.state
console.log(latestFirmware)
this.setState(state => ({ ...state, installing: true }))
const {
device: { path: devicePath },
} = this.props
await runJob({
channel: 'manager',
job: 'installFirmware',
successResponse: 'device.firmwareInstalled',
errorResponse: 'device.firmwareInstallError',
job: 'installFinalFirmware',
successResponse: 'device.finalFirmwareInstallSuccess',
errorResponse: 'device.finalFirmwareInstallError',
data: {
devicePath,
firmware: latestFirmware,
@ -80,6 +140,22 @@ class FirmwareUpdate extends PureComponent<Props, State> {
}
}
handleIntallMcu = async () => {}
installFirmware = async () => {
const { deviceInfos } = this.state
if (deviceInfos) {
const { mcu, final } = deviceInfos
if (mcu) {
this.handleIntallMcu()
} else if (final) {
this.handleIntallFinalFirmware()
} else {
this.handleIntallOsuFirmware()
}
}
}
render() {
const { t, ...props } = this.props
const { latestFirmware } = this.state
@ -96,8 +172,8 @@ class FirmwareUpdate extends PureComponent<Props, State> {
<Card flow={2} {...props}>
<Box horizontal align="center" flow={2}>
<Box ff="Museo Sans">{`Latest firmware: ${latestFirmware.name}`}</Box>
<Button outline onClick={this.fetchLatestFirmware}>
{'Fetch'}
<Button outline onClick={this.handleInstallFirmware}>
{'Install'}
</Button>
</Box>
<Box

26
src/internals/manager/getFirmwareInfo.js

@ -0,0 +1,26 @@
// @flow
import type Transport from '@ledgerhq/hw-transport'
import type { IPCSend } from 'types/electron'
import { createTransportHandler, getFirmwareInfo } from './helpers'
const handler = async (transport: Transport<*>) =>
new Promise(async resolve => {
try {
const { targetId, version } = await getFirmwareInfo(transport)
const finalReady = version.endsWith('-osu')
const mcuReady = targetId === 0x01000001
resolve({ targetId, version, final: finalReady, mcu: mcuReady })
} catch (err) {
throw err
}
})
export default async (send: IPCSend, data: any) =>
createTransportHandler(send, {
action: handler,
successResponse: 'device.getFirmwareInfoSuccess',
errorResponse: 'device.getFirmwareInfoError',
})(data)

1
src/internals/manager/getLatestFirmwareForDevice.js

@ -13,7 +13,6 @@ export default async (send: IPCSend, data: any) => {
try {
const transport = await CommNodeHid.open(data.devicePath)
const infos = await getFirmwareInfo(transport)
// Get device infos from targetId
const { data: deviceVersion } = await axios.get(
`${API_BASE_URL}/device_versions_target_id/${infos.targetId}`,

40
src/internals/manager/helpers.js

@ -21,13 +21,15 @@ type Message = {
data: any,
}
type LedgerAppParams = {
type LedgerScriptParams = {
firmware?: string,
firmwareKey?: string,
delete?: string,
deleteKey?: string,
}
type FirmwareUpdateType = 'osu' | 'final'
/**
* Generate handler which create transport with given
* `devicePath` then call action with it
@ -68,7 +70,7 @@ export function createTransportHandler(
*/
export async function installApp(
transport: Transport<*>,
{ appParams }: { appParams: LedgerAppParams },
{ appParams }: { appParams: LedgerScriptParams },
): Promise<void> {
return createSocketDialog(transport, '/install', appParams)
}
@ -78,7 +80,7 @@ export async function installApp(
*/
export async function uninstallApp(
transport: Transport<*>,
{ appParams }: { appParams: LedgerAppParams },
{ appParams }: { appParams: LedgerScriptParams },
): Promise<void> {
return createSocketDialog(transport, '/install', {
...appParams,
@ -105,7 +107,11 @@ function socketSend(ws: WebsocketType, msg: Message) {
/**
* Exchange data on transport
*/
async function exchange(ws: WebsocketType, transport: Transport<*>, msg: Message): Promise<void> {
export async function exchange(
ws: WebsocketType,
transport: Transport<*>,
msg: Message,
): Promise<void> {
const { data, nonce } = msg
const r: Buffer = await transport.exchange(Buffer.from(data, 'hex'))
const status = r.slice(r.length - 2)
@ -121,7 +127,7 @@ async function exchange(ws: WebsocketType, transport: Transport<*>, msg: Message
/**
* Bulk update on transport
*/
async function bulk(ws: WebsocketType, transport: Transport<*>, msg: Message) {
export async function bulk(ws: WebsocketType, transport: Transport<*>, msg: Message) {
const { data, nonce } = msg
// Execute all apdus and collect last status
@ -146,11 +152,15 @@ async function bulk(ws: WebsocketType, transport: Transport<*>, msg: Message) {
* Open socket connection with firmware api, and init a dialog
* with the device
*/
function createSocketDialog(transport: Transport<*>, endpoint: string, appParams: LedgerAppParams) {
export async function createSocketDialog(
transport: Transport<*>,
endpoint: string,
params: LedgerScriptParams,
) {
return new Promise(async (resolve, reject) => {
try {
let lastData
const url = `${BASE_SOCKET_URL}${endpoint}?${qs.stringify(appParams)}`
const url = `${BASE_SOCKET_URL}${endpoint}?${qs.stringify(params)}`
log('WS CONNECTING', url)
const ws: WebsocketType = new Websocket(url)
@ -211,7 +221,7 @@ export async function getFirmwareInfo(transport: Transport<*>) {
/**
* Debug helper
*/
function log(namespace: string, str: string = '', color?: string) {
export function log(namespace: string, str: string = '', color?: string) {
namespace = namespace.padEnd(15)
// $FlowFixMe
const coloredNamespace = color ? chalk[color](namespace) : namespace
@ -223,7 +233,7 @@ function log(namespace: string, str: string = '', color?: string) {
/**
* Log a socket send/receive
*/
function logWS(type: string, msg: Message) {
export function logWS(type: string, msg: Message) {
const arrow = type === 'SEND' ? '↑' : '↓'
const namespace = `${arrow} WS ${type}`
const color = type === 'SEND' ? 'blue' : 'red'
@ -243,3 +253,15 @@ function logWS(type: string, msg: Message) {
log(namespace, JSON.stringify(msg), color)
}
}
/**
* Helpers to build OSU and Final firmware params
*/
export const buildParamsFromFirmware = (type: FirmwareUpdateType): Function => (
data: any,
): LedgerScriptParams => ({
firmware: data[`${type}_firmware`],
firmwareKey: data[`${type}_firmware_key`],
perso: data[`${type}_perso`],
targetId: data[`${type}_target_id`],
})

3
src/internals/manager/index.js

@ -21,3 +21,6 @@ export { default as installApp } from './installApp'
export { default as listApps } from './listApps'
export { default as uninstallApp } from './uninstallApp'
export { default as getLatestFirmwareForDevice } from './getLatestFirmwareForDevice'
export { default as installOsuFirmware } from './installOsuFirmware'
export { default as installFinalFirmware } from './installFinalFirmware'
export { default as getFirmwareInfo } from './getFirmwareInfo'

24
src/internals/manager/installFinalFirmware.js

@ -0,0 +1,24 @@
// @flow
import CommNodeHid from '@ledgerhq/hw-transport-node-hid'
import type { IPCSend } from 'types/electron'
import { createSocketDialog, buildParamsFromFirmware } from './helpers'
type DataType = {
devicePath: string,
firmware: Object,
}
const buildFinalParams = buildParamsFromFirmware('final')
export default async (send: IPCSend, data: DataType) => {
try {
const transport = await CommNodeHid.open(data.devicePath)
const finalData = buildFinalParams(data.firmware)
await createSocketDialog(transport, '/install', finalData)
send('device.finalFirmwareInstallSuccess', { success: true })
} catch (err) {
send('device.finalFirmwareInstallError', { success: false })
}
}

17
src/internals/manager/installFirmware.js

@ -1,17 +0,0 @@
// @flow
import type { IPCSend } from 'types/electron'
export default async (send: IPCSend, data: any) => {
/**
* 1 CREATE TRANSPORT
* 2 GETFIRMWARE INFOS
* 3 SEND
*/
console.log(data)
}
// createTransportHandler(send, {
// action: installFirmware,
// successResponse: 'manager.appInstalled',
// errorResponse: 'manager.appInstallError',
// })(data)

1
src/internals/manager/installMcu.js

@ -0,0 +1 @@
// flow

24
src/internals/manager/installOsuFirmware.js

@ -0,0 +1,24 @@
// @flow
import CommNodeHid from '@ledgerhq/hw-transport-node-hid'
import type { IPCSend } from 'types/electron'
import { createSocketDialog, buildParamsFromFirmware } from './helpers'
type DataType = {
devicePath: string,
firmware: Object,
}
const buildOsuParams = buildParamsFromFirmware('osu')
export default async (send: IPCSend, data: DataType) => {
try {
const transport = await CommNodeHid.open(data.devicePath)
const osuData = buildOsuParams(data.firmware)
await createSocketDialog(transport, '/install', osuData)
send('device.osuFirmwareInstallSuccess', { success: true })
} catch (err) {
send('device.osuFirmwareInstallError', { success: false })
}
}
Loading…
Cancel
Save