mirror of
https://github.com/crosspoint-reader/xteink-flasher.git
synced 2026-04-29 10:25:18 -07:00
Split out step runner and move volatile functions into step blocks
This commit is contained in:
+87
-100
@@ -2,26 +2,17 @@
|
||||
|
||||
import { useState } from 'react';
|
||||
import { getFirmware } from '@/remote/firmwareFetcher';
|
||||
import { StepData } from '@/types/Step';
|
||||
import { downloadData } from '@/utils/download';
|
||||
import { wrapWithWakeLock } from '@/utils/wakelock';
|
||||
import OtaPartition, { OtaPartitionDetails } from './OtaPartition';
|
||||
import useStepRunner from './useStepRunner';
|
||||
import EspController from './EspController';
|
||||
|
||||
export function useEspOperations() {
|
||||
const [stepData, setStepData] = useState<StepData[]>([]);
|
||||
const { stepData, initializeSteps, updateStepData, runStep } =
|
||||
useStepRunner();
|
||||
const [isRunning, setIsRunning] = useState(false);
|
||||
|
||||
const updateStepData = (step: string, data: Partial<StepData>) => {
|
||||
setStepData((oldStepData) =>
|
||||
oldStepData.map((oldData) => {
|
||||
if (oldData.name === step) {
|
||||
return { ...oldData, ...data };
|
||||
}
|
||||
return oldData;
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const wrapWithRunning =
|
||||
<Args extends unknown[], T>(fn: (...a: Args) => Promise<T>) =>
|
||||
async (...a: Args) => {
|
||||
@@ -29,55 +20,44 @@ export function useEspOperations() {
|
||||
return fn(...a).finally(() => setIsRunning(false));
|
||||
};
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-constraint
|
||||
const wrapWithStep = async <T extends unknown>(
|
||||
stepName: string,
|
||||
fn: () => Promise<T>,
|
||||
): Promise<T> => {
|
||||
updateStepData(stepName, { status: 'running' });
|
||||
const res = await fn().catch((e) => {
|
||||
updateStepData(stepName, {
|
||||
status: 'failed',
|
||||
error: e,
|
||||
});
|
||||
throw e;
|
||||
});
|
||||
updateStepData(stepName, { status: 'success' });
|
||||
return res;
|
||||
};
|
||||
|
||||
const flashFirmware = async (version: Parameters<typeof getFirmware>[0]) => {
|
||||
setStepData([
|
||||
{ name: 'Connect to device', status: 'pending' },
|
||||
{ name: 'Download firmware', status: 'pending' },
|
||||
{ name: 'Read otadata partition', status: 'pending' },
|
||||
{ name: 'Flash app partition', status: 'pending' },
|
||||
{ name: 'Flash otadata partition', status: 'pending' },
|
||||
{ name: 'Reset device', status: 'pending' },
|
||||
initializeSteps([
|
||||
'Connect to device',
|
||||
'Download firmware',
|
||||
'Read otadata partition',
|
||||
'Flash app partition',
|
||||
'Flash otadata partition',
|
||||
'Reset device',
|
||||
]);
|
||||
|
||||
const espController = await wrapWithStep('Connect to device', async () => {
|
||||
const espController = await runStep('Connect to device', async () => {
|
||||
const c = await EspController.fromRequestedDevice();
|
||||
await c.connect();
|
||||
return c;
|
||||
});
|
||||
|
||||
const firmwareFile = await wrapWithStep('Download firmware', () =>
|
||||
const firmwareFile = await runStep('Download firmware', () =>
|
||||
getFirmware(version),
|
||||
);
|
||||
|
||||
const otaPartition = await wrapWithStep('Read otadata partition', () =>
|
||||
espController.readOtadataPartition((_, p, t) =>
|
||||
updateStepData('Read otadata partition', {
|
||||
progress: { current: p, total: t },
|
||||
}),
|
||||
),
|
||||
const [otaPartition, backupPartitionLabel] = await runStep(
|
||||
'Read otadata partition',
|
||||
async (): Promise<
|
||||
[OtaPartition, OtaPartitionDetails['partitionLabel']]
|
||||
> => {
|
||||
const partition = await espController.readOtadataPartition((_, p, t) =>
|
||||
updateStepData('Read otadata partition', {
|
||||
progress: { current: p, total: t },
|
||||
}),
|
||||
);
|
||||
|
||||
return [partition, partition.getCurrentBackupPartitionLabel()];
|
||||
},
|
||||
);
|
||||
|
||||
const backupPartitionLabel = otaPartition.getCurrentBackupPartitionLabel();
|
||||
const flashAppPartitionStepName = `Flash app partition (${backupPartitionLabel})`;
|
||||
updateStepData('Flash app partition', { name: flashAppPartitionStepName });
|
||||
await wrapWithStep(flashAppPartitionStepName, () =>
|
||||
await runStep(flashAppPartitionStepName, () =>
|
||||
espController.writeAppPartition(
|
||||
backupPartitionLabel,
|
||||
firmwareFile,
|
||||
@@ -88,35 +68,36 @@ export function useEspOperations() {
|
||||
),
|
||||
);
|
||||
|
||||
otaPartition.setBootPartition(backupPartitionLabel);
|
||||
await wrapWithStep('Flash otadata partition', () =>
|
||||
espController.writeOtadataPartition(otaPartition, (_, p, t) =>
|
||||
await runStep('Flash otadata partition', async () => {
|
||||
otaPartition.setBootPartition(backupPartitionLabel);
|
||||
|
||||
await espController.writeOtadataPartition(otaPartition, (_, p, t) =>
|
||||
updateStepData('Flash otadata partition', {
|
||||
progress: { current: p, total: t },
|
||||
}),
|
||||
),
|
||||
);
|
||||
);
|
||||
});
|
||||
|
||||
await wrapWithStep('Reset device', () => espController.disconnect());
|
||||
await runStep('Reset device', () => espController.disconnect());
|
||||
};
|
||||
|
||||
const flashEnglishFirmware = async () => flashFirmware('3.0.8-EN');
|
||||
const flashChineseFirmware = async () => flashFirmware('3.0.7-CH');
|
||||
|
||||
const saveFullFlash = async () => {
|
||||
setStepData([
|
||||
{ name: 'Connect to device', status: 'pending' },
|
||||
{ name: 'Read flash', status: 'pending' },
|
||||
{ name: 'Disconnect from device', status: 'pending' },
|
||||
initializeSteps([
|
||||
'Connect to device',
|
||||
'Read flash',
|
||||
'Disconnect from device',
|
||||
]);
|
||||
|
||||
const espController = await wrapWithStep('Connect to device', async () => {
|
||||
const espController = await runStep('Connect to device', async () => {
|
||||
const c = await EspController.fromRequestedDevice();
|
||||
await c.connect();
|
||||
return c;
|
||||
});
|
||||
|
||||
const firmwareFile = await wrapWithStep(
|
||||
const firmwareFile = await runStep(
|
||||
'Read flash',
|
||||
wrapWithWakeLock(() =>
|
||||
espController.readFullFlash((_, p, t) =>
|
||||
@@ -125,7 +106,7 @@ export function useEspOperations() {
|
||||
),
|
||||
);
|
||||
|
||||
await wrapWithStep('Disconnect from device', () =>
|
||||
await runStep('Disconnect from device', () =>
|
||||
espController.disconnect({ skipReset: true }),
|
||||
);
|
||||
|
||||
@@ -133,14 +114,14 @@ export function useEspOperations() {
|
||||
};
|
||||
|
||||
const writeFullFlash = async (getFile: () => File | undefined) => {
|
||||
setStepData([
|
||||
{ name: 'Read file', status: 'pending' },
|
||||
{ name: 'Connect to device', status: 'pending' },
|
||||
{ name: 'Write flash', status: 'pending' },
|
||||
{ name: 'Reset device', status: 'pending' },
|
||||
initializeSteps([
|
||||
'Read file',
|
||||
'Connect to device',
|
||||
'Write flash',
|
||||
'Reset device',
|
||||
]);
|
||||
|
||||
const fileData = await wrapWithStep('Read file', async () => {
|
||||
const fileData = await runStep('Read file', async () => {
|
||||
const file = getFile();
|
||||
if (!file) {
|
||||
throw new Error('File not found');
|
||||
@@ -148,35 +129,35 @@ export function useEspOperations() {
|
||||
return new Uint8Array(await file.arrayBuffer());
|
||||
});
|
||||
|
||||
const espController = await wrapWithStep('Connect to device', async () => {
|
||||
const espController = await runStep('Connect to device', async () => {
|
||||
const c = await EspController.fromRequestedDevice();
|
||||
await c.connect();
|
||||
return c;
|
||||
});
|
||||
|
||||
await wrapWithStep('Write flash', () =>
|
||||
await runStep('Write flash', () =>
|
||||
espController.writeFullFlash(fileData, (_, p, t) =>
|
||||
updateStepData('Write flash', { progress: { current: p, total: t } }),
|
||||
),
|
||||
);
|
||||
|
||||
await wrapWithStep('Reset device', () => espController.disconnect());
|
||||
await runStep('Reset device', () => espController.disconnect());
|
||||
};
|
||||
|
||||
const readDebugOtadata = async () => {
|
||||
setStepData([
|
||||
{ name: 'Connect to device', status: 'pending' },
|
||||
{ name: 'Read otadata partition', status: 'pending' },
|
||||
{ name: 'Disconnect from device', status: 'pending' },
|
||||
initializeSteps([
|
||||
'Connect to device',
|
||||
'Read otadata partition',
|
||||
'Disconnect from device',
|
||||
]);
|
||||
|
||||
const espController = await wrapWithStep('Connect to device', async () => {
|
||||
const espController = await runStep('Connect to device', async () => {
|
||||
const c = await EspController.fromRequestedDevice();
|
||||
await c.connect();
|
||||
return c;
|
||||
});
|
||||
|
||||
const otaPartition = await wrapWithStep('Read otadata partition', () =>
|
||||
const otaPartition = await runStep('Read otadata partition', () =>
|
||||
espController.readOtadataPartition((_, p, t) =>
|
||||
updateStepData('Read otadata partition', {
|
||||
progress: { current: p, total: t },
|
||||
@@ -184,7 +165,7 @@ export function useEspOperations() {
|
||||
),
|
||||
);
|
||||
|
||||
await wrapWithStep('Disconnect from device', () =>
|
||||
await runStep('Disconnect from device', () =>
|
||||
espController.disconnect({ skipReset: true }),
|
||||
);
|
||||
|
||||
@@ -192,30 +173,36 @@ export function useEspOperations() {
|
||||
};
|
||||
|
||||
const swapBootPartition = async () => {
|
||||
setStepData([
|
||||
{ name: 'Connect to device', status: 'pending' },
|
||||
{ name: 'Read otadata partition', status: 'pending' },
|
||||
{ name: 'Flash otadata partition', status: 'pending' },
|
||||
{ name: 'Reset device', status: 'pending' },
|
||||
initializeSteps([
|
||||
'Connect to device',
|
||||
'Read otadata partition',
|
||||
'Flash otadata partition',
|
||||
'Reset device',
|
||||
]);
|
||||
|
||||
const espController = await wrapWithStep('Connect to device', async () => {
|
||||
const espController = await runStep('Connect to device', async () => {
|
||||
const c = await EspController.fromRequestedDevice();
|
||||
await c.connect();
|
||||
return c;
|
||||
});
|
||||
|
||||
const otaPartition = await wrapWithStep('Read otadata partition', () =>
|
||||
espController.readOtadataPartition((_, p, t) =>
|
||||
updateStepData('Read otadata partition', {
|
||||
progress: { current: p, total: t },
|
||||
}),
|
||||
),
|
||||
const [otaPartition, backupPartitionLabel] = await runStep(
|
||||
'Read otadata partition',
|
||||
async (): Promise<
|
||||
[OtaPartition, OtaPartitionDetails['partitionLabel']]
|
||||
> => {
|
||||
const partition = await espController.readOtadataPartition((_, p, t) =>
|
||||
updateStepData('Read otadata partition', {
|
||||
progress: { current: p, total: t },
|
||||
}),
|
||||
);
|
||||
|
||||
return [partition, partition.getCurrentBackupPartitionLabel()];
|
||||
},
|
||||
);
|
||||
|
||||
const backupPartitionLabel = otaPartition.getCurrentBackupPartitionLabel();
|
||||
otaPartition.setBootPartition(backupPartitionLabel);
|
||||
await wrapWithStep('Flash otadata partition', () =>
|
||||
await runStep('Flash otadata partition', () =>
|
||||
espController.writeOtadataPartition(otaPartition, (_, p, t) =>
|
||||
updateStepData('Flash otadata partition', {
|
||||
progress: { current: p, total: t },
|
||||
@@ -223,20 +210,20 @@ export function useEspOperations() {
|
||||
),
|
||||
);
|
||||
|
||||
await wrapWithStep('Reset device', () => espController.disconnect());
|
||||
await runStep('Reset device', () => espController.disconnect());
|
||||
|
||||
return otaPartition;
|
||||
};
|
||||
|
||||
const fakeWriteFullFlash = async () => {
|
||||
setStepData([
|
||||
{ name: 'Read file', status: 'pending' },
|
||||
{ name: 'Connect to device', status: 'pending' },
|
||||
{ name: 'Write flash', status: 'pending' },
|
||||
{ name: 'Reset device', status: 'pending' },
|
||||
initializeSteps([
|
||||
'Read file',
|
||||
'Connect to device',
|
||||
'Write flash',
|
||||
'Reset device',
|
||||
]);
|
||||
|
||||
await wrapWithStep(
|
||||
await runStep(
|
||||
'Read file',
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
@@ -244,7 +231,7 @@ export function useEspOperations() {
|
||||
}),
|
||||
);
|
||||
|
||||
await wrapWithStep(
|
||||
await runStep(
|
||||
'Connect to device',
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
@@ -252,7 +239,7 @@ export function useEspOperations() {
|
||||
}),
|
||||
);
|
||||
|
||||
await wrapWithStep(
|
||||
await runStep(
|
||||
'Write flash',
|
||||
() =>
|
||||
new Promise((resolve, reject) => {
|
||||
@@ -278,7 +265,7 @@ export function useEspOperations() {
|
||||
}),
|
||||
);
|
||||
|
||||
await wrapWithStep(
|
||||
await runStep(
|
||||
'Reset device',
|
||||
() =>
|
||||
new Promise((resolve) => {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
'use client';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { StepData } from '@/types/Step';
|
||||
|
||||
export default function useStepRunner() {
|
||||
const [stepData, setStepData] = useState<StepData[]>([]);
|
||||
|
||||
const initializeSteps = (stepNames: string[]) => {
|
||||
setStepData(stepNames.map((step) => ({ name: step, status: 'pending' })));
|
||||
};
|
||||
|
||||
const updateStepData = (step: string, data: Partial<StepData>) => {
|
||||
setStepData((oldStepData) =>
|
||||
oldStepData.map((oldData) => {
|
||||
if (oldData.name === step) {
|
||||
return { ...oldData, ...data };
|
||||
}
|
||||
return oldData;
|
||||
}),
|
||||
);
|
||||
};
|
||||
|
||||
const runStep = async <T>(stepName: string, fn: () => Promise<T>) => {
|
||||
updateStepData(stepName, { status: 'running' });
|
||||
|
||||
try {
|
||||
const result = await fn();
|
||||
updateStepData(stepName, { status: 'success' });
|
||||
return result;
|
||||
} catch (error) {
|
||||
let parsedError;
|
||||
if (error instanceof Error) {
|
||||
parsedError = error;
|
||||
} else if (typeof error === 'string') {
|
||||
parsedError = new Error(error);
|
||||
} else {
|
||||
parsedError = new Error(`${error}`);
|
||||
}
|
||||
updateStepData(stepName, { status: 'failed', error: parsedError });
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
stepData,
|
||||
initializeSteps,
|
||||
updateStepData,
|
||||
runStep,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user