Remove bluebird from main process, reduce lodash usage

Changelog-entry: Remove bluebird from main process, reduce lodash usage
Change-type: patch
This commit is contained in:
Alexis Svinartchouk 2020-07-16 14:56:32 +02:00
parent 963fc574c3
commit 512785e0a9
7 changed files with 63 additions and 83 deletions

View File

@ -18,7 +18,7 @@ import * as _ from 'lodash';
import * as resinCorvus from 'resin-corvus/browser'; import * as resinCorvus from 'resin-corvus/browser';
import * as packageJSON from '../../../../package.json'; import * as packageJSON from '../../../../package.json';
import { getConfig, hasProps } from '../../../shared/utils'; import { getConfig } from '../../../shared/utils';
import * as settings from '../models/settings'; import * as settings from '../models/settings';
import { store } from '../models/store'; import { store } from '../models/store';
@ -55,7 +55,8 @@ async function initConfig() {
await installCorvus(); await installCorvus();
let validatedConfig = null; let validatedConfig = null;
try { try {
const config = await getConfig(); const configUrl = await settings.get('configUrl');
const config = await getConfig(configUrl);
const mixpanel = _.get(config, ['analytics', 'mixpanel'], {}); const mixpanel = _.get(config, ['analytics', 'mixpanel'], {});
mixpanelSample = mixpanel.probability || DEFAULT_PROBABILITY; mixpanelSample = mixpanel.probability || DEFAULT_PROBABILITY;
if (isClientEligible(mixpanelSample)) { if (isClientEligible(mixpanelSample)) {
@ -88,7 +89,7 @@ function validateMixpanelConfig(config: {
const mixpanelConfig = { const mixpanelConfig = {
api_host: 'https://api.mixpanel.com', 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}`; mixpanelConfig.api_host = `${config.HTTP_PROTOCOL}://${config.api_host}`;
} }
return mixpanelConfig; return mixpanelConfig;

View File

@ -23,7 +23,7 @@ import { join } from 'path';
import { env } from 'process'; import { env } from 'process';
import { promisify } from 'util'; import { promisify } from 'util';
import { tmpFileDisposer } from '../../../shared/utils'; import { tmpFileDisposer } from '../../../shared/tmp';
const readFileAsync = promisify(readFile); const readFileAsync = promisify(readFile);

View File

@ -14,26 +14,24 @@
* limitations under the License. * limitations under the License.
*/ */
import { delay } from 'bluebird';
import * as electron from 'electron'; import * as electron from 'electron';
import { autoUpdater } from 'electron-updater'; import { autoUpdater } from 'electron-updater';
import { promises as fs } from 'fs'; import { promises as fs } from 'fs';
import { platform } from 'os'; import { platform } from 'os';
import * as _ from 'lodash';
import * as path from 'path'; import * as path from 'path';
import * as semver from 'semver'; import * as semver from 'semver';
import { packageType, version } from '../../package.json'; import { packageType, version } from '../../package.json';
import * as EXIT_CODES from '../shared/exit-codes'; 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 settings from './app/models/settings';
import * as analytics from './app/modules/analytics'; import { logException } from './app/modules/analytics';
import { buildWindowMenu } from './menu'; import { buildWindowMenu } from './menu';
const customProtocol = 'etcher'; const customProtocol = 'etcher';
const scheme = `${customProtocol}://`; const scheme = `${customProtocol}://`;
const updatablePackageTypes = ['appimage', 'nsis', 'dmg']; const updatablePackageTypes = ['appimage', 'nsis', 'dmg'];
const packageUpdatable = _.includes(updatablePackageTypes, packageType); const packageUpdatable = updatablePackageTypes.includes(packageType);
let packageUpdated = false; let packageUpdated = false;
async function checkForUpdates(interval: number) { async function checkForUpdates(interval: number) {
@ -51,7 +49,7 @@ async function checkForUpdates(interval: number) {
packageUpdated = true; packageUpdated = true;
} }
} catch (err) { } catch (err) {
analytics.logException(err); logException(err);
} }
} }
await delay(interval); await delay(interval);
@ -114,6 +112,14 @@ electron.app.on('open-url', async (event, data) => {
await selectImageURL(data); await selectImageURL(data);
}); });
interface AutoUpdaterConfig {
autoDownload?: boolean;
autoInstallOnAppQuit?: boolean;
allowPrerelease?: boolean;
fullChangelog?: boolean;
allowDowngrade?: boolean;
}
async function createMainWindow() { async function createMainWindow() {
const fullscreen = Boolean(await settings.get('fullscreen')); const fullscreen = Boolean(await settings.get('fullscreen'));
const defaultWidth = 800; const defaultWidth = 800;
@ -171,27 +177,24 @@ async function createMainWindow() {
page.once('did-frame-finish-load', async () => { page.once('did-frame-finish-load', async () => {
autoUpdater.on('error', (err) => { autoUpdater.on('error', (err) => {
analytics.logException(err); logException(err);
}); });
if (packageUpdatable) { if (packageUpdatable) {
try { try {
const onlineConfig = await getConfig(); const configUrl = await settings.get('configUrl');
const autoUpdaterConfig = _.get( const onlineConfig = await getConfig(configUrl);
onlineConfig, const autoUpdaterConfig: AutoUpdaterConfig = onlineConfig?.autoUpdates
['autoUpdates', 'autoUpdaterConfig'], ?.autoUpdaterConfig ?? {
{ autoDownload: false,
autoDownload: false, };
}, for (const [key, value] of Object.entries(autoUpdaterConfig)) {
); autoUpdater[key as keyof AutoUpdaterConfig] = value;
_.merge(autoUpdater, autoUpdaterConfig); }
const checkForUpdatesTimer = _.get( const checkForUpdatesTimer =
onlineConfig, onlineConfig?.autoUpdates?.checkForUpdatesTimer ?? 300000;
['autoUpdates', 'checkForUpdatesTimer'],
300000,
);
checkForUpdates(checkForUpdatesTimer); checkForUpdates(checkForUpdatesTimer);
} catch (err) { } catch (err) {
analytics.logException(err); logException(err);
} }
} }
}); });

View File

@ -14,7 +14,6 @@
* limitations under the License. * limitations under the License.
*/ */
import { delay } from 'bluebird';
import { Drive as DrivelistDrive } from 'drivelist'; import { Drive as DrivelistDrive } from 'drivelist';
import * as sdk from 'etcher-sdk'; import * as sdk from 'etcher-sdk';
import { cleanupTmpFiles } from 'etcher-sdk/build/tmp'; import { cleanupTmpFiles } from 'etcher-sdk/build/tmp';
@ -23,6 +22,7 @@ import * as ipc from 'node-ipc';
import { toJSON } from '../../shared/errors'; import { toJSON } from '../../shared/errors';
import { GENERAL_ERROR, SUCCESS } from '../../shared/exit-codes'; import { GENERAL_ERROR, SUCCESS } from '../../shared/exit-codes';
import { delay } from '../../shared/utils';
import { SourceOptions } from '../app/components/source-selector/source-selector'; import { SourceOptions } from '../app/components/source-selector/source-selector';
ipc.config.id = process.env.IPC_CLIENT_ID as string; ipc.config.id = process.env.IPC_CLIENT_ID as string;

View File

@ -25,7 +25,7 @@ import { promisify } from 'util';
import { sudo as catalinaSudo } from './catalina-sudo/sudo'; import { sudo as catalinaSudo } from './catalina-sudo/sudo';
import * as errors from './errors'; import * as errors from './errors';
import { tmpFileDisposer } from './utils'; import { tmpFileDisposer } from './tmp';
const execAsync = promisify(childProcess.exec); const execAsync = promisify(childProcess.exec);
const execFileAsync = promisify(childProcess.execFile); const execFileAsync = promisify(childProcess.execFile);

24
lib/shared/tmp.ts Normal file
View File

@ -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();
});
}

View File

@ -15,15 +15,12 @@
*/ */
import axios from 'axios'; import axios from 'axios';
import * as Bluebird from 'bluebird'; import { Dictionary } from 'lodash';
import * as _ from 'lodash';
import * as tmp from 'tmp';
import * as errors from './errors'; import * as errors from './errors';
import * as settings from '../gui/app/models/settings';
export function isValidPercentage(percentage: any): boolean { 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) { export function percentageToFloat(percentage: any) {
@ -35,63 +32,18 @@ export function percentageToFloat(percentage: any) {
return percentage / 100; return percentage / 100;
} }
/**
* @summary Check if obj has one or many specific props
*/
export function hasProps(obj: _.Dictionary<any>, props: string[]): boolean {
return _.every(props, (prop) => {
return _.has(obj, prop);
});
}
/** /**
* @summary Get etcher configs stored online * @summary Get etcher configs stored online
* @param {String} - url where config.json is stored * @param {String} - url where config.json is stored
*/ */
export async function getConfig(): Promise<_.Dictionary<any>> { export async function getConfig(configUrl?: string): Promise<Dictionary<any>> {
const configUrl = configUrl = configUrl ?? 'https://balena.io/etcher/static/config.json';
(await settings.get('configUrl')) ||
'https://balena.io/etcher/static/config.json';
const response = await axios.get(configUrl, { responseType: 'json' }); const response = await axios.get(configUrl, { responseType: 'json' });
return response.data; return response.data;
} }
/** export async function delay(duration: number): Promise<void> {
* @summary returns { path: String, cleanup: Function } await new Promise((resolve) => {
* setTimeout(resolve, duration);
* @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();
}); });
} }