diff --git a/Makefile b/Makefile index 595c5316..15091162 100644 --- a/Makefile +++ b/Makefile @@ -124,7 +124,7 @@ TARGETS = \ help \ info \ lint \ - lint-js \ + lint-ts \ lint-sass \ lint-cpp \ lint-spell \ @@ -149,7 +149,7 @@ sass: node-sass lib/gui/app/scss/main.scss > lib/gui/css/main.css lint-ts: - resin-lint --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts + resin-lint --fix --typescript typings lib tests scripts/clean-shrinkwrap.ts webpack.config.ts lint-sass: sass-lint lib/gui/scss diff --git a/lib/gui/app/models/leds.ts b/lib/gui/app/models/leds.ts index 5e6ffb7e..85363138 100644 --- a/lib/gui/app/models/leds.ts +++ b/lib/gui/app/models/leds.ts @@ -14,131 +14,17 @@ * limitations under the License. */ -import { delay } from 'bluebird'; -import { promises as fs } from 'fs'; +import { + AnimationFunction, + blinkWhite, + breatheGreen, + Color, + RGBLed, +} from 'sys-class-rgb-led'; import * as settings from './settings'; import { observe } from './store'; -class Led { - private handle: fs.FileHandle; - private lastValue?: number; - - constructor(private path: string) {} - - private async open() { - if (this.handle === undefined) { - this.handle = await fs.open(this.path, 'w'); - } - } - - public async setIntensity(intensity: number) { - if (intensity < 0 || intensity > 1) { - throw new Error('Led intensity must be between 0 and 1'); - } - const value = Math.round(intensity * 255); - if (value !== this.lastValue) { - await this.open(); - await this.handle.write(value.toString(), 0); - // On a regular file we would also need to truncate to the written value length but it looks like it's not the case on sysfs files - this.lastValue = value; - } - } -} - -export type Color = [number, number, number]; -export type AnimationFunction = (t: number) => Color; - -function delay1(duration: number): Promise { - // delay that accepts Infinity - if (duration === Infinity) { - return new Promise(() => { - // Never resolve - }); - } else { - return delay(duration); - } -} - -function cancellableDelay( - duration: number, -): { promise: Promise; cancel: () => void } { - let maybeCancel: () => void; - const cancel = () => { - if (maybeCancel !== undefined) { - maybeCancel(); - } - }; - const cancelPromise: Promise = new Promise(resolve => { - maybeCancel = resolve; - }); - const promise = Promise.race([delay1(duration), cancelPromise]); - return { promise, cancel }; -} - -export class RGBLed { - private leds: [Led, Led, Led]; - private animation: AnimationFunction; - private period: number; // in ms - private wakeUp = () => { - // noop until this.loop() is called - }; - - constructor(paths: [string, string, string]) { - this.leds = paths.map(path => new Led(path)) as [Led, Led, Led]; - this.setStaticColor([0, 0, 0]); - this.loop(); - } - - private setFrequency(frequency: number) { - if (frequency < 0) { - throw new Error('frequency must be greater or equal to 0'); - } - this.period = 1000 / frequency; - this.wakeUp(); - } - - private async loop() { - while (true) { - const start = new Date().getTime(); - await this.setColor(this.animation(start)); - const end = new Date().getTime(); - const duration = end - start; - const { promise, cancel } = cancellableDelay(this.period - duration); - this.wakeUp = cancel; - await promise; - } - } - - public setAnimation(animation: AnimationFunction, frequency = 10) { - this.animation = animation; - this.setFrequency(frequency); - } - - public setStaticColor(color: Color) { - this.setAnimation(() => color, 0); - } - - private async setColor(color: Color) { - await Promise.all([ - this.leds[0].setIntensity(color[0]), - this.leds[1].setIntensity(color[1]), - this.leds[2].setIntensity(color[2]), - ]); - } -} - -// Animations: -function breatheGreen(t: number): Color { - const intensity = (1 + Math.sin(t / 1000)) / 2; - return [0, intensity, 0]; -} - -function blinkWhite(t: number): Color { - const intensity = Math.floor(t / 1000) % 2; - return [intensity, intensity, intensity]; -} - const leds: Map = new Map(); function setLeds( @@ -184,16 +70,16 @@ export function init() { // ledsMapping is something like: // { // 'platform-xhci-hcd.0.auto-usb-0:1.1.1:1.0-scsi-0:0:0:0': [ - // '/sys/class/leds/led1_r', - // '/sys/class/leds/led1_g', - // '/sys/class/leds/led1_b', + // 'led1_r', + // 'led1_g', + // 'led1_b', // ], // ... // } const ledsMapping: _.Dictionary<[string, string, string]> = settings.get('ledsMapping') || {}; - for (const [drivePath, ledsPaths] of Object.entries(ledsMapping)) { - leds.set('/dev/disk/by-path/' + drivePath, new RGBLed(ledsPaths)); + for (const [drivePath, ledsNames] of Object.entries(ledsMapping)) { + leds.set('/dev/disk/by-path/' + drivePath, new RGBLed(ledsNames)); } observe(state => { const availableDrives = state diff --git a/lib/gui/app/modules/image-writer.ts b/lib/gui/app/modules/image-writer.ts index 98282407..81d79661 100644 --- a/lib/gui/app/modules/image-writer.ts +++ b/lib/gui/app/modules/image-writer.ts @@ -227,12 +227,15 @@ export function performWrite( !flashResults.cancelled && !_.get(flashResults, ['results', 'bytesWritten']) ) { - throw errors.createUserError({ - title: 'The writer process ended unexpectedly', - description: - 'Please try again, and contact the Etcher team if the problem persists', - code: 'ECHILDDIED', - }); + reject( + errors.createUserError({ + title: 'The writer process ended unexpectedly', + description: + 'Please try again, and contact the Etcher team if the problem persists', + code: 'ECHILDDIED', + }), + ); + return; } resolve(flashResults); }); diff --git a/lib/gui/app/pages/main/Flash.tsx b/lib/gui/app/pages/main/Flash.tsx index a797319e..07a1c10d 100644 --- a/lib/gui/app/pages/main/Flash.tsx +++ b/lib/gui/app/pages/main/Flash.tsx @@ -71,7 +71,7 @@ const getErrorMessageFromCode = (errorCode: string) => { return ''; }; -const flashImageToDrive = async (goToSuccess: () => void) => { +async function flashImageToDrive(goToSuccess: () => void): Promise { const devices = selection.getSelectedDevices(); const image: any = selection.getImage(); const drives = _.filter(availableDrives.getDrives(), (drive: any) => { @@ -129,7 +129,7 @@ const flashImageToDrive = async (goToSuccess: () => void) => { } return ''; -}; +} /** * @summary Get progress button label diff --git a/lib/start.ts b/lib/start.ts index 38f62f40..d377d5c4 100644 --- a/lib/start.ts +++ b/lib/start.ts @@ -21,7 +21,9 @@ // if passing `ELECTRON_RUN_AS_NODE`, you have to pass the path to the asar // or the entry point file (this file) manually as an argument. -if (process.env.ELECTRON_RUN_AS_NODE) { +import { env } from 'process'; + +if (env.ELECTRON_RUN_AS_NODE) { import('./gui/modules/child-writer'); } else { import('./gui/etcher'); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 678716b6..4d7cec69 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -12694,6 +12694,11 @@ "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" }, + "sys-class-rgb-led": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sys-class-rgb-led/-/sys-class-rgb-led-2.1.0.tgz", + "integrity": "sha512-ckjrMCWWwg1J4d+B3xlTPLhgK6U/2qpW1TYzCLBSULKoLk2tFchis7nDEOmcbiLfpR/8GQK1Q2CrDNleF0USHA==" + }, "tapable": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", @@ -14457,4 +14462,4 @@ } } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 70333b7c..ebe8af10 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,6 @@ }, "scripts": { "test": "make lint test sanity-checks", - "prettier": "prettier --config ./node_modules/resin-lint/config/.prettierrc --write \"lib/**/*.ts\" \"lib/**/*.tsx\" \"tests/**/*.ts\" \"webpack.config.ts\" \"scripts/clean-shrinkwrap.ts\"", "start": "./node_modules/.bin/electron .", "postshrinkwrap": "ts-node ./scripts/clean-shrinkwrap.ts", "configure": "node-gyp configure", @@ -39,7 +38,6 @@ }, "lint-staged": { "./**/*.{ts,tsx}": [ - "npm run prettier", "make lint-ts", "git add" ] @@ -84,6 +82,7 @@ "styled-components": "^4.2.0", "styled-system": "^4.1.0", "sudo-prompt": "^9.0.0", + "sys-class-rgb-led": "^2.1.0", "tmp": "^0.1.0", "uuid": "^3.0.1" },