From 512785e0a96c5c24792a034fbb2b56c2c67926ab Mon Sep 17 00:00:00 2001 From: Alexis Svinartchouk Date: Thu, 16 Jul 2020 14:56:32 +0200 Subject: [PATCH] Remove bluebird from main process, reduce lodash usage Changelog-entry: Remove bluebird from main process, reduce lodash usage Change-type: patch --- lib/gui/app/modules/analytics.ts | 7 +-- lib/gui/app/os/windows-network-drives.ts | 2 +- lib/gui/etcher.ts | 47 +++++++++--------- lib/gui/modules/child-writer.ts | 2 +- lib/shared/permissions.ts | 2 +- lib/shared/tmp.ts | 24 +++++++++ lib/shared/utils.ts | 62 +++--------------------- 7 files changed, 63 insertions(+), 83 deletions(-) create mode 100644 lib/shared/tmp.ts diff --git a/lib/gui/app/modules/analytics.ts b/lib/gui/app/modules/analytics.ts index f62f10ac..d63969a5 100644 --- a/lib/gui/app/modules/analytics.ts +++ b/lib/gui/app/modules/analytics.ts @@ -18,7 +18,7 @@ import * as _ from 'lodash'; import * as resinCorvus from 'resin-corvus/browser'; import * as packageJSON from '../../../../package.json'; -import { getConfig, hasProps } from '../../../shared/utils'; +import { getConfig } from '../../../shared/utils'; import * as settings from '../models/settings'; import { store } from '../models/store'; @@ -55,7 +55,8 @@ async function initConfig() { await installCorvus(); let validatedConfig = null; try { - const config = await getConfig(); + const configUrl = await settings.get('configUrl'); + const config = await getConfig(configUrl); const mixpanel = _.get(config, ['analytics', 'mixpanel'], {}); mixpanelSample = mixpanel.probability || DEFAULT_PROBABILITY; if (isClientEligible(mixpanelSample)) { @@ -88,7 +89,7 @@ function validateMixpanelConfig(config: { const mixpanelConfig = { api_host: 'https://api.mixpanel.com', }; - if (hasProps(config, ['HTTP_PROTOCOL', 'api_host'])) { + if (config.HTTP_PROTOCOL !== undefined && config.api_host !== undefined) { mixpanelConfig.api_host = `${config.HTTP_PROTOCOL}://${config.api_host}`; } return mixpanelConfig; diff --git a/lib/gui/app/os/windows-network-drives.ts b/lib/gui/app/os/windows-network-drives.ts index 1acba6a7..860e26e9 100755 --- a/lib/gui/app/os/windows-network-drives.ts +++ b/lib/gui/app/os/windows-network-drives.ts @@ -23,7 +23,7 @@ import { join } from 'path'; import { env } from 'process'; import { promisify } from 'util'; -import { tmpFileDisposer } from '../../../shared/utils'; +import { tmpFileDisposer } from '../../../shared/tmp'; const readFileAsync = promisify(readFile); diff --git a/lib/gui/etcher.ts b/lib/gui/etcher.ts index afb7842a..044e9f13 100644 --- a/lib/gui/etcher.ts +++ b/lib/gui/etcher.ts @@ -14,26 +14,24 @@ * limitations under the License. */ -import { delay } from 'bluebird'; import * as electron from 'electron'; import { autoUpdater } from 'electron-updater'; import { promises as fs } from 'fs'; import { platform } from 'os'; -import * as _ from 'lodash'; import * as path from 'path'; import * as semver from 'semver'; import { packageType, version } from '../../package.json'; import * as EXIT_CODES from '../shared/exit-codes'; -import { getConfig } from '../shared/utils'; +import { delay, getConfig } from '../shared/utils'; import * as settings from './app/models/settings'; -import * as analytics from './app/modules/analytics'; +import { logException } from './app/modules/analytics'; import { buildWindowMenu } from './menu'; const customProtocol = 'etcher'; const scheme = `${customProtocol}://`; const updatablePackageTypes = ['appimage', 'nsis', 'dmg']; -const packageUpdatable = _.includes(updatablePackageTypes, packageType); +const packageUpdatable = updatablePackageTypes.includes(packageType); let packageUpdated = false; async function checkForUpdates(interval: number) { @@ -51,7 +49,7 @@ async function checkForUpdates(interval: number) { packageUpdated = true; } } catch (err) { - analytics.logException(err); + logException(err); } } await delay(interval); @@ -114,6 +112,14 @@ electron.app.on('open-url', async (event, data) => { await selectImageURL(data); }); +interface AutoUpdaterConfig { + autoDownload?: boolean; + autoInstallOnAppQuit?: boolean; + allowPrerelease?: boolean; + fullChangelog?: boolean; + allowDowngrade?: boolean; +} + async function createMainWindow() { const fullscreen = Boolean(await settings.get('fullscreen')); const defaultWidth = 800; @@ -171,27 +177,24 @@ async function createMainWindow() { page.once('did-frame-finish-load', async () => { autoUpdater.on('error', (err) => { - analytics.logException(err); + logException(err); }); if (packageUpdatable) { try { - const onlineConfig = await getConfig(); - const autoUpdaterConfig = _.get( - onlineConfig, - ['autoUpdates', 'autoUpdaterConfig'], - { - autoDownload: false, - }, - ); - _.merge(autoUpdater, autoUpdaterConfig); - const checkForUpdatesTimer = _.get( - onlineConfig, - ['autoUpdates', 'checkForUpdatesTimer'], - 300000, - ); + const configUrl = await settings.get('configUrl'); + const onlineConfig = await getConfig(configUrl); + const autoUpdaterConfig: AutoUpdaterConfig = onlineConfig?.autoUpdates + ?.autoUpdaterConfig ?? { + autoDownload: false, + }; + for (const [key, value] of Object.entries(autoUpdaterConfig)) { + autoUpdater[key as keyof AutoUpdaterConfig] = value; + } + const checkForUpdatesTimer = + onlineConfig?.autoUpdates?.checkForUpdatesTimer ?? 300000; checkForUpdates(checkForUpdatesTimer); } catch (err) { - analytics.logException(err); + logException(err); } } }); diff --git a/lib/gui/modules/child-writer.ts b/lib/gui/modules/child-writer.ts index e7e3e78e..deeccfb2 100644 --- a/lib/gui/modules/child-writer.ts +++ b/lib/gui/modules/child-writer.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { delay } from 'bluebird'; import { Drive as DrivelistDrive } from 'drivelist'; import * as sdk from 'etcher-sdk'; import { cleanupTmpFiles } from 'etcher-sdk/build/tmp'; @@ -23,6 +22,7 @@ import * as ipc from 'node-ipc'; import { toJSON } from '../../shared/errors'; import { GENERAL_ERROR, SUCCESS } from '../../shared/exit-codes'; +import { delay } from '../../shared/utils'; import { SourceOptions } from '../app/components/source-selector/source-selector'; ipc.config.id = process.env.IPC_CLIENT_ID as string; diff --git a/lib/shared/permissions.ts b/lib/shared/permissions.ts index 51580a35..b152c9d2 100755 --- a/lib/shared/permissions.ts +++ b/lib/shared/permissions.ts @@ -25,7 +25,7 @@ import { promisify } from 'util'; import { sudo as catalinaSudo } from './catalina-sudo/sudo'; import * as errors from './errors'; -import { tmpFileDisposer } from './utils'; +import { tmpFileDisposer } from './tmp'; const execAsync = promisify(childProcess.exec); const execFileAsync = promisify(childProcess.execFile); diff --git a/lib/shared/tmp.ts b/lib/shared/tmp.ts new file mode 100644 index 00000000..9187f4d9 --- /dev/null +++ b/lib/shared/tmp.ts @@ -0,0 +1,24 @@ +import * as Bluebird from 'bluebird'; +import * as tmp from 'tmp'; + +function tmpFileAsync( + options: tmp.FileOptions, +): Promise<{ path: string; cleanup: () => void }> { + return new Promise((resolve, reject) => { + tmp.file(options, (error, path, _fd, cleanup) => { + if (error) { + reject(error); + } else { + resolve({ path, cleanup }); + } + }); + }); +} + +export function tmpFileDisposer( + options: tmp.FileOptions, +): Bluebird.Disposer<{ path: string; cleanup: () => void }> { + return Bluebird.resolve(tmpFileAsync(options)).disposer(({ cleanup }) => { + cleanup(); + }); +} diff --git a/lib/shared/utils.ts b/lib/shared/utils.ts index 70abdabe..36c4c021 100755 --- a/lib/shared/utils.ts +++ b/lib/shared/utils.ts @@ -15,15 +15,12 @@ */ import axios from 'axios'; -import * as Bluebird from 'bluebird'; -import * as _ from 'lodash'; -import * as tmp from 'tmp'; +import { Dictionary } from 'lodash'; import * as errors from './errors'; -import * as settings from '../gui/app/models/settings'; export function isValidPercentage(percentage: any): boolean { - return _.every([_.isNumber(percentage), percentage >= 0, percentage <= 100]); + return typeof percentage === 'number' && percentage >= 0 && percentage <= 100; } export function percentageToFloat(percentage: any) { @@ -35,63 +32,18 @@ export function percentageToFloat(percentage: any) { return percentage / 100; } -/** - * @summary Check if obj has one or many specific props - */ -export function hasProps(obj: _.Dictionary, props: string[]): boolean { - return _.every(props, (prop) => { - return _.has(obj, prop); - }); -} - /** * @summary Get etcher configs stored online * @param {String} - url where config.json is stored */ -export async function getConfig(): Promise<_.Dictionary> { - const configUrl = - (await settings.get('configUrl')) || - 'https://balena.io/etcher/static/config.json'; +export async function getConfig(configUrl?: string): Promise> { + configUrl = configUrl ?? 'https://balena.io/etcher/static/config.json'; const response = await axios.get(configUrl, { responseType: 'json' }); return response.data; } -/** - * @summary returns { path: String, cleanup: Function } - * - * @example - * const {path, cleanup } = await tmpFileAsync() - * console.log(path) - * cleanup() - */ -function tmpFileAsync( - options: tmp.FileOptions, -): Promise<{ path: string; cleanup: () => void }> { - return new Promise((resolve, reject) => { - tmp.file(options, (error, path, _fd, cleanup) => { - if (error) { - reject(error); - } else { - resolve({ path, cleanup }); - } - }); - }); -} - -/** - * @summary Disposer for tmpFileAsync, calls cleanup() - * - * @returns {Disposer<{ path: String, cleanup: Function }>} - * - * @example - * await Bluebird.using(tmpFileDisposer(), ({ path }) => { - * console.log(path); - * }) - */ -export function tmpFileDisposer( - options: tmp.FileOptions, -): Bluebird.Disposer<{ path: string; cleanup: () => void }> { - return Bluebird.resolve(tmpFileAsync(options)).disposer(({ cleanup }) => { - cleanup(); +export async function delay(duration: number): Promise { + await new Promise((resolve) => { + setTimeout(resolve, duration); }); }