Refactor code to comply with ESLint rules
Major refactoring using ESLint with rules from AirBnb and Vue. Enable most of the ESLint rules and do necessary linting in the code. Also add more information for rules that are disabled to describe what they are and why they are disabled. Allow logging (`console.log`) in test files, and in development mode (e.g. when working with `npm run serve`), but disable it when environment is production (as pre-configured by Vue). Also add flag (`--mode production`) in `lint:eslint` command so production linting is executed earlier in lifecycle. Disable rules that requires a separate work. Such as ESLint rules that are broken in TypeScript: no-useless-constructor (eslint/eslint#14118) and no-shadow (eslint/eslint#13014).
This commit is contained in:
@@ -1,74 +1,74 @@
|
||||
import { app, dialog } from 'electron';
|
||||
import { autoUpdater, UpdateInfo } from 'electron-updater';
|
||||
import { ProgressInfo } from 'electron-builder';
|
||||
import { UpdateProgressBar } from './UpdateProgressBar';
|
||||
import log from 'electron-log';
|
||||
import { UpdateProgressBar } from './UpdateProgressBar';
|
||||
|
||||
export async function handleAutoUpdate() {
|
||||
if (await askDownloadAndInstall() === DownloadDialogResult.NotNow) {
|
||||
return;
|
||||
}
|
||||
startHandlingUpdateProgress();
|
||||
await autoUpdater.downloadUpdate();
|
||||
if (await askDownloadAndInstall() === DownloadDialogResult.NotNow) {
|
||||
return;
|
||||
}
|
||||
startHandlingUpdateProgress();
|
||||
await autoUpdater.downloadUpdate();
|
||||
}
|
||||
|
||||
function startHandlingUpdateProgress() {
|
||||
const progressBar = new UpdateProgressBar();
|
||||
progressBar.showIndeterminateState();
|
||||
autoUpdater.on('error', (e) => {
|
||||
progressBar.showError(e);
|
||||
});
|
||||
autoUpdater.on('download-progress', (progress: ProgressInfo) => {
|
||||
/*
|
||||
On macOS, download-progress event is not called.
|
||||
So the indeterminate progress will continue until download is finished.
|
||||
*/
|
||||
log.debug('@download-progress@\n', progress);
|
||||
progressBar.showProgress(progress);
|
||||
});
|
||||
autoUpdater.on('update-downloaded', async (info: UpdateInfo) => {
|
||||
log.info('@update-downloaded@\n', info);
|
||||
progressBar.close();
|
||||
await handleUpdateDownloaded();
|
||||
});
|
||||
const progressBar = new UpdateProgressBar();
|
||||
progressBar.showIndeterminateState();
|
||||
autoUpdater.on('error', (e) => {
|
||||
progressBar.showError(e);
|
||||
});
|
||||
autoUpdater.on('download-progress', (progress: ProgressInfo) => {
|
||||
/*
|
||||
On macOS, download-progress event is not called.
|
||||
So the indeterminate progress will continue until download is finished.
|
||||
*/
|
||||
log.debug('@download-progress@\n', progress);
|
||||
progressBar.showProgress(progress);
|
||||
});
|
||||
autoUpdater.on('update-downloaded', async (info: UpdateInfo) => {
|
||||
log.info('@update-downloaded@\n', info);
|
||||
progressBar.close();
|
||||
await handleUpdateDownloaded();
|
||||
});
|
||||
}
|
||||
|
||||
async function handleUpdateDownloaded() {
|
||||
if (await askRestartAndInstall() === InstallDialogResult.NotNow) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => autoUpdater.quitAndInstall(), 1);
|
||||
if (await askRestartAndInstall() === InstallDialogResult.NotNow) {
|
||||
return;
|
||||
}
|
||||
setTimeout(() => autoUpdater.quitAndInstall(), 1);
|
||||
}
|
||||
|
||||
enum DownloadDialogResult {
|
||||
Install = 0,
|
||||
NotNow = 1,
|
||||
Install = 0,
|
||||
NotNow = 1,
|
||||
}
|
||||
async function askDownloadAndInstall(): Promise<DownloadDialogResult> {
|
||||
const updateDialogResult = await dialog.showMessageBox({
|
||||
type: 'question',
|
||||
buttons: ['Install', 'Not now' ],
|
||||
title: 'Confirm Update',
|
||||
message: 'Update available.\n\nWould you like to download and install new version?',
|
||||
detail: 'Application will automatically restart to apply update after download',
|
||||
defaultId: DownloadDialogResult.Install,
|
||||
cancelId: DownloadDialogResult.NotNow,
|
||||
});
|
||||
return updateDialogResult.response;
|
||||
const updateDialogResult = await dialog.showMessageBox({
|
||||
type: 'question',
|
||||
buttons: ['Install', 'Not now'],
|
||||
title: 'Confirm Update',
|
||||
message: 'Update available.\n\nWould you like to download and install new version?',
|
||||
detail: 'Application will automatically restart to apply update after download',
|
||||
defaultId: DownloadDialogResult.Install,
|
||||
cancelId: DownloadDialogResult.NotNow,
|
||||
});
|
||||
return updateDialogResult.response;
|
||||
}
|
||||
|
||||
enum InstallDialogResult {
|
||||
InstallAndRestart = 0,
|
||||
NotNow = 1,
|
||||
InstallAndRestart = 0,
|
||||
NotNow = 1,
|
||||
}
|
||||
async function askRestartAndInstall(): Promise<InstallDialogResult> {
|
||||
const installDialogResult = await dialog.showMessageBox({
|
||||
type: 'question',
|
||||
buttons: ['Install and restart', 'Later'],
|
||||
message: 'A new version of ' + app.name + ' has been downloaded',
|
||||
detail: 'It will be installed the next time you restart the application',
|
||||
defaultId: InstallDialogResult.InstallAndRestart,
|
||||
cancelId: InstallDialogResult.NotNow,
|
||||
});
|
||||
return installDialogResult.response;
|
||||
const installDialogResult = await dialog.showMessageBox({
|
||||
type: 'question',
|
||||
buttons: ['Install and restart', 'Later'],
|
||||
message: `A new version of ${app.name} has been downloaded.`,
|
||||
detail: 'It will be installed the next time you restart the application.',
|
||||
defaultId: InstallDialogResult.InstallAndRestart,
|
||||
cancelId: InstallDialogResult.NotNow,
|
||||
});
|
||||
return installDialogResult.response;
|
||||
}
|
||||
|
||||
@@ -1,130 +1,137 @@
|
||||
import { app, dialog, shell } from 'electron';
|
||||
import { ProjectInformation } from '@/domain/ProjectInformation';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { UpdateInfo } from 'electron-updater';
|
||||
import { UpdateProgressBar } from './UpdateProgressBar';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { app, dialog, shell } from 'electron';
|
||||
import { UpdateInfo } from 'electron-updater';
|
||||
import log from 'electron-log';
|
||||
import fetch from 'cross-fetch';
|
||||
import { ProjectInformation } from '@/domain/ProjectInformation';
|
||||
import { OperatingSystem } from '@/domain/OperatingSystem';
|
||||
import { UpdateProgressBar } from './UpdateProgressBar';
|
||||
|
||||
export function requiresManualUpdate(): boolean {
|
||||
return process.platform === 'darwin';
|
||||
return process.platform === 'darwin';
|
||||
}
|
||||
|
||||
export async function handleManualUpdate(info: UpdateInfo) {
|
||||
const result = await askForVisitingWebsiteForManualUpdate();
|
||||
if (result === ManualDownloadDialogResult.NoAction) {
|
||||
return;
|
||||
}
|
||||
const project = new ProjectInformation(
|
||||
process.env.VUE_APP_NAME,
|
||||
info.version,
|
||||
process.env.VUE_APP_REPOSITORY_URL,
|
||||
process.env.VUE_APP_HOMEPAGE_URL,
|
||||
);
|
||||
if (result === ManualDownloadDialogResult.VisitReleasesPage) {
|
||||
await shell.openExternal(project.releaseUrl);
|
||||
} else if (result === ManualDownloadDialogResult.UpdateNow) {
|
||||
await download(info, project);
|
||||
}
|
||||
const result = await askForVisitingWebsiteForManualUpdate();
|
||||
if (result === ManualDownloadDialogResult.NoAction) {
|
||||
return;
|
||||
}
|
||||
const project = new ProjectInformation(
|
||||
process.env.VUE_APP_NAME,
|
||||
info.version,
|
||||
process.env.VUE_APP_REPOSITORY_URL,
|
||||
process.env.VUE_APP_HOMEPAGE_URL,
|
||||
);
|
||||
if (result === ManualDownloadDialogResult.VisitReleasesPage) {
|
||||
await shell.openExternal(project.releaseUrl);
|
||||
} else if (result === ManualDownloadDialogResult.UpdateNow) {
|
||||
await download(info, project);
|
||||
}
|
||||
}
|
||||
|
||||
enum ManualDownloadDialogResult {
|
||||
NoAction = 0,
|
||||
UpdateNow = 1,
|
||||
VisitReleasesPage = 2,
|
||||
NoAction = 0,
|
||||
UpdateNow = 1,
|
||||
VisitReleasesPage = 2,
|
||||
}
|
||||
async function askForVisitingWebsiteForManualUpdate(): Promise<ManualDownloadDialogResult> {
|
||||
const visitPageResult = await dialog.showMessageBox({
|
||||
type: 'info',
|
||||
buttons: [
|
||||
'Not now', // First button is shown at bottom after some space in macOS and has default cancel behavior
|
||||
'Download and manually update',
|
||||
'Visit releases page',
|
||||
],
|
||||
message: 'Update available\n\nWould you like to update manually?',
|
||||
detail:
|
||||
'There are new updates available.'
|
||||
+ ' privacy.sexy does not support fully auto-update for macOS due to code signing costs.'
|
||||
+ ' Please manually update your version, because newer versions fix issues and improve privacy and security.',
|
||||
defaultId: ManualDownloadDialogResult.UpdateNow,
|
||||
cancelId: ManualDownloadDialogResult.NoAction,
|
||||
});
|
||||
return visitPageResult.response;
|
||||
const visitPageResult = await dialog.showMessageBox({
|
||||
type: 'info',
|
||||
buttons: [
|
||||
'Not now', // First button is shown at bottom after some space in macOS and has default cancel behavior
|
||||
'Download and manually update',
|
||||
'Visit releases page',
|
||||
],
|
||||
message: 'Update available\n\nWould you like to update manually?',
|
||||
detail:
|
||||
'There are new updates available.'
|
||||
+ ' privacy.sexy does not support fully auto-update for macOS due to code signing costs.'
|
||||
+ ' Please manually update your version, because newer versions fix issues and improve privacy and security.',
|
||||
defaultId: ManualDownloadDialogResult.UpdateNow,
|
||||
cancelId: ManualDownloadDialogResult.NoAction,
|
||||
});
|
||||
return visitPageResult.response;
|
||||
}
|
||||
|
||||
async function download(info: UpdateInfo, project: ProjectInformation) {
|
||||
log.info('Downloading update manually');
|
||||
const progressBar = new UpdateProgressBar();
|
||||
progressBar.showIndeterminateState();
|
||||
try {
|
||||
const filePath = `${path.dirname(app.getPath('temp'))}/privacy.sexy/${info.version}-installer.dmg`;
|
||||
const parentFolder = path.dirname(filePath);
|
||||
if (fs.existsSync(filePath)) {
|
||||
log.info('Update is already downloaded');
|
||||
await fs.promises.unlink(filePath);
|
||||
log.info(`Deleted ${filePath}`);
|
||||
} else {
|
||||
await fs.promises.mkdir(parentFolder, { recursive: true });
|
||||
}
|
||||
const dmgFileUrl = project.getDownloadUrl(OperatingSystem.macOS);
|
||||
await downloadFileWithProgress(dmgFileUrl, filePath,
|
||||
(percentage) => { progressBar.showPercentage(percentage); });
|
||||
await shell.openPath(filePath);
|
||||
progressBar.close();
|
||||
app.quit();
|
||||
} catch (e) {
|
||||
progressBar.showError(e);
|
||||
log.info('Downloading update manually');
|
||||
const progressBar = new UpdateProgressBar();
|
||||
progressBar.showIndeterminateState();
|
||||
try {
|
||||
const filePath = `${path.dirname(app.getPath('temp'))}/privacy.sexy/${info.version}-installer.dmg`;
|
||||
const parentFolder = path.dirname(filePath);
|
||||
if (fs.existsSync(filePath)) {
|
||||
log.info('Update is already downloaded');
|
||||
await fs.promises.unlink(filePath);
|
||||
log.info(`Deleted ${filePath}`);
|
||||
} else {
|
||||
await fs.promises.mkdir(parentFolder, { recursive: true });
|
||||
}
|
||||
const dmgFileUrl = project.getDownloadUrl(OperatingSystem.macOS);
|
||||
await downloadFileWithProgress(
|
||||
dmgFileUrl,
|
||||
filePath,
|
||||
(percentage) => { progressBar.showPercentage(percentage); },
|
||||
);
|
||||
await shell.openPath(filePath);
|
||||
progressBar.close();
|
||||
app.quit();
|
||||
} catch (e) {
|
||||
progressBar.showError(e);
|
||||
}
|
||||
}
|
||||
|
||||
type ProgressCallback = (progress: number) => void;
|
||||
|
||||
async function downloadFileWithProgress(
|
||||
url: string, filePath: string, progressHandler: ProgressCallback) {
|
||||
// We don't download through autoUpdater as it cannot download DMG but requires distributing ZIP
|
||||
log.info(`Fetching ${url}`);
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw Error(`Unable to download, server returned ${response.status} ${response.statusText}`);
|
||||
}
|
||||
const contentLength = +response.headers.get('content-length');
|
||||
const writer = fs.createWriteStream(filePath);
|
||||
log.info(`Writing to ${filePath}, content length: ${contentLength}`);
|
||||
if (!contentLength) {
|
||||
log.error('Unknown content-length', Array.from(response.headers.entries()));
|
||||
progressHandler = () => { /* do nothing */ };
|
||||
}
|
||||
const reader = getReader(response);
|
||||
if (!reader) {
|
||||
throw new Error('No response body');
|
||||
}
|
||||
await streamWithProgress(contentLength, reader, writer, progressHandler);
|
||||
url: string,
|
||||
filePath: string,
|
||||
progressHandler: ProgressCallback,
|
||||
) {
|
||||
// We don't download through autoUpdater as it cannot download DMG but requires distributing ZIP
|
||||
log.info(`Fetching ${url}`);
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw Error(`Unable to download, server returned ${response.status} ${response.statusText}`);
|
||||
}
|
||||
const contentLength = +response.headers.get('content-length');
|
||||
const writer = fs.createWriteStream(filePath);
|
||||
log.info(`Writing to ${filePath}, content length: ${contentLength}`);
|
||||
if (!contentLength) {
|
||||
log.error('Unknown content-length', Array.from(response.headers.entries()));
|
||||
progressHandler = () => { /* do nothing */ };
|
||||
}
|
||||
const reader = getReader(response);
|
||||
if (!reader) {
|
||||
throw new Error('No response body');
|
||||
}
|
||||
await streamWithProgress(contentLength, reader, writer, progressHandler);
|
||||
}
|
||||
|
||||
async function streamWithProgress(
|
||||
totalLength: number,
|
||||
readStream: NodeJS.ReadableStream,
|
||||
writeStream: fs.WriteStream,
|
||||
progressHandler: ProgressCallback): Promise<void> {
|
||||
let receivedLength = 0;
|
||||
for await (const chunk of readStream) {
|
||||
if (!chunk) {
|
||||
throw Error('Empty chunk received during download');
|
||||
}
|
||||
writeStream.write(Buffer.from(chunk));
|
||||
receivedLength += chunk.length;
|
||||
const percentage = Math.floor((receivedLength / totalLength) * 100);
|
||||
progressHandler(percentage);
|
||||
log.debug(`Received ${receivedLength} of ${totalLength}`);
|
||||
totalLength: number,
|
||||
readStream: NodeJS.ReadableStream,
|
||||
writeStream: fs.WriteStream,
|
||||
progressHandler: ProgressCallback,
|
||||
): Promise<void> {
|
||||
let receivedLength = 0;
|
||||
for await (const chunk of readStream) {
|
||||
if (!chunk) {
|
||||
throw Error('Empty chunk received during download');
|
||||
}
|
||||
log.info(`Downloaded successfully`);
|
||||
writeStream.write(Buffer.from(chunk));
|
||||
receivedLength += chunk.length;
|
||||
const percentage = Math.floor((receivedLength / totalLength) * 100);
|
||||
progressHandler(percentage);
|
||||
log.debug(`Received ${receivedLength} of ${totalLength}`);
|
||||
}
|
||||
log.info('Downloaded successfully');
|
||||
}
|
||||
|
||||
function getReader(response: Response): NodeJS.ReadableStream {
|
||||
// On browser, we could use browser API response.body.getReader()
|
||||
// But here, we use cross-fetch that gets node-fetch on a node application
|
||||
// This API is node-fetch specific, see https://github.com/node-fetch/node-fetch#streams
|
||||
return response.body as unknown as NodeJS.ReadableStream;
|
||||
// On browser, we could use browser API response.body.getReader()
|
||||
// But here, we use cross-fetch that gets node-fetch on a node application
|
||||
// This API is node-fetch specific, see https://github.com/node-fetch/node-fetch#streams
|
||||
return response.body as unknown as NodeJS.ReadableStream;
|
||||
}
|
||||
|
||||
@@ -1,90 +1,95 @@
|
||||
import ProgressBar from 'electron-progressbar';
|
||||
import { ProgressInfo } from 'electron-builder';
|
||||
import { app } from 'electron';
|
||||
import { app, BrowserWindow } from 'electron';
|
||||
import log from 'electron-log';
|
||||
|
||||
export class UpdateProgressBar {
|
||||
private progressBar: ProgressBar;
|
||||
private showingProgress = false;
|
||||
public showIndeterminateState() {
|
||||
this.progressBar?.close();
|
||||
this.progressBar = progressBarFactory.createWithIndeterminateState();
|
||||
private progressBar: ProgressBar;
|
||||
|
||||
private get innerProgressBarWindow(): BrowserWindow {
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
return this.progressBar._window;
|
||||
}
|
||||
|
||||
private showingProgress = false;
|
||||
|
||||
public showIndeterminateState() {
|
||||
this.progressBar?.close();
|
||||
this.progressBar = progressBarFactory.createWithIndeterminateState();
|
||||
}
|
||||
|
||||
public showProgress(progress: ProgressInfo) {
|
||||
const percentage = getUpdatePercent(progress);
|
||||
this.showPercentage(percentage);
|
||||
}
|
||||
|
||||
public showPercentage(percentage: number) {
|
||||
if (!this.showingProgress) { // First time showing progress
|
||||
this.progressBar?.close();
|
||||
this.showingProgress = true;
|
||||
this.progressBar = progressBarFactory.createWithPercentile(percentage);
|
||||
} else {
|
||||
this.progressBar.value = percentage;
|
||||
}
|
||||
public showProgress(progress: ProgressInfo) {
|
||||
const percentage = getUpdatePercent(progress);
|
||||
this.showPercentage(percentage);
|
||||
}
|
||||
|
||||
public showError(e: Error) {
|
||||
const reportUpdateError = () => {
|
||||
this.progressBar.detail = 'An error occurred while fetching updates.'
|
||||
+ `\n${e && e.message ? e.message : e}`;
|
||||
this.innerProgressBarWindow.setClosable(true);
|
||||
};
|
||||
if (this.progressBar.innerProgressBarWindow) {
|
||||
reportUpdateError();
|
||||
} else {
|
||||
this.progressBar.on('ready', () => reportUpdateError());
|
||||
}
|
||||
public showPercentage(percentage: number) {
|
||||
if (!this.showingProgress) { // First time showing progress
|
||||
this.progressBar?.close();
|
||||
this.showingProgress = true;
|
||||
this.progressBar = progressBarFactory.createWithPercentile(percentage);
|
||||
} else {
|
||||
updateProgressBar(percentage, this.progressBar);
|
||||
}
|
||||
}
|
||||
public showError(e: Error) {
|
||||
const reportUpdateError = () => {
|
||||
this.progressBar.detail =
|
||||
'An error occurred while fetching updates.\n'
|
||||
+ (e && e.message ? e.message : e);
|
||||
this.progressBar._window.setClosable(true);
|
||||
};
|
||||
if (this.progressBar._window) {
|
||||
reportUpdateError();
|
||||
} else {
|
||||
this.progressBar.on('ready', () => reportUpdateError());
|
||||
}
|
||||
}
|
||||
public close() {
|
||||
if (!this.progressBar.isCompleted()) {
|
||||
this.progressBar.close();
|
||||
}
|
||||
}
|
||||
|
||||
public close() {
|
||||
if (!this.progressBar.isCompleted()) {
|
||||
this.progressBar.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getUpdatePercent(progress: ProgressInfo) {
|
||||
let percent = progress.percent;
|
||||
if (percent) {
|
||||
percent = Math.round(percent * 100) / 100;
|
||||
}
|
||||
return percent;
|
||||
let { percent } = progress;
|
||||
if (percent) {
|
||||
percent = Math.round(percent * 100) / 100;
|
||||
}
|
||||
return percent;
|
||||
}
|
||||
|
||||
const progressBarFactory = {
|
||||
createWithIndeterminateState: () => {
|
||||
return new ProgressBar({
|
||||
title: `${app.name} Update`,
|
||||
text: `Downloading ${app.name} update...`,
|
||||
});
|
||||
},
|
||||
createWithPercentile: (initialPercentage: number) => {
|
||||
const progressBar = new ProgressBar({
|
||||
indeterminate: false,
|
||||
title: `${app.name} Update`,
|
||||
text: `Downloading ${app.name} update...`,
|
||||
detail: `${initialPercentage}% ...`,
|
||||
initialValue: initialPercentage,
|
||||
});
|
||||
progressBar
|
||||
.on('completed', () => {
|
||||
progressBar.detail = 'Download completed.';
|
||||
})
|
||||
.on('aborted', (value: number) => {
|
||||
log.info(`progress aborted... ${value}`);
|
||||
})
|
||||
.on('progress', (value: number) => {
|
||||
progressBar.detail = `${value}% ...`;
|
||||
})
|
||||
.on('ready', () => {
|
||||
// initialValue doesn't set the UI, so this is needed to render it correctly
|
||||
progressBar.value = initialPercentage;
|
||||
});
|
||||
return progressBar;
|
||||
},
|
||||
createWithIndeterminateState: () => {
|
||||
return new ProgressBar({
|
||||
title: `${app.name} Update`,
|
||||
text: `Downloading ${app.name} update...`,
|
||||
});
|
||||
},
|
||||
createWithPercentile: (initialPercentage: number) => {
|
||||
const progressBar = new ProgressBar({
|
||||
indeterminate: false,
|
||||
title: `${app.name} Update`,
|
||||
text: `Downloading ${app.name} update...`,
|
||||
detail: `${initialPercentage}% ...`,
|
||||
initialValue: initialPercentage,
|
||||
});
|
||||
progressBar
|
||||
.on('completed', () => {
|
||||
progressBar.detail = 'Download completed.';
|
||||
})
|
||||
.on('aborted', (value: number) => {
|
||||
log.info(`progress aborted... ${value}`);
|
||||
})
|
||||
.on('progress', (value: number) => {
|
||||
progressBar.detail = `${value}% ...`;
|
||||
})
|
||||
.on('ready', () => {
|
||||
// initialValue doesn't set the UI, so this is needed to render it correctly
|
||||
progressBar.value = initialPercentage;
|
||||
});
|
||||
return progressBar;
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
function updateProgressBar(percentage: number, progressBar: ProgressBar) {
|
||||
progressBar.value = percentage;
|
||||
}
|
||||
|
||||
@@ -4,37 +4,43 @@ import { handleManualUpdate, requiresManualUpdate } from './ManualUpdater';
|
||||
import { handleAutoUpdate } from './AutoUpdater';
|
||||
|
||||
interface IUpdater {
|
||||
checkForUpdates(): Promise<void>;
|
||||
checkForUpdates(): Promise<void>;
|
||||
}
|
||||
|
||||
export function setupAutoUpdater(): IUpdater {
|
||||
autoUpdater.logger = log;
|
||||
autoUpdater.autoDownload = false; // Checking and downloading are handled separately based on platform/user choice
|
||||
autoUpdater.on('error', (error: Error) => {
|
||||
log.error('@error@\n', error);
|
||||
});
|
||||
let isAlreadyHandled = false;
|
||||
autoUpdater.on('update-available', async (info: UpdateInfo) => {
|
||||
log.info('@update-available@\n', info);
|
||||
if (isAlreadyHandled) {
|
||||
log.info('Available updates is already handled');
|
||||
return;
|
||||
}
|
||||
isAlreadyHandled = true;
|
||||
await handleAvailableUpdate(info);
|
||||
});
|
||||
return {
|
||||
checkForUpdates: async () => {
|
||||
// autoUpdater.emit('update-available'); // For testing
|
||||
await autoUpdater.checkForUpdates();
|
||||
},
|
||||
};
|
||||
autoUpdater.logger = log;
|
||||
|
||||
// Disable autodownloads because "checking" and "downloading" are handled separately based on the
|
||||
// current platform and user's choice.
|
||||
autoUpdater.autoDownload = false;
|
||||
|
||||
autoUpdater.on('error', (error: Error) => {
|
||||
log.error('@error@\n', error);
|
||||
});
|
||||
|
||||
let isAlreadyHandled = false;
|
||||
autoUpdater.on('update-available', async (info: UpdateInfo) => {
|
||||
log.info('@update-available@\n', info);
|
||||
if (isAlreadyHandled) {
|
||||
log.info('Available updates is already handled');
|
||||
return;
|
||||
}
|
||||
isAlreadyHandled = true;
|
||||
await handleAvailableUpdate(info);
|
||||
});
|
||||
|
||||
return {
|
||||
checkForUpdates: async () => {
|
||||
// autoUpdater.emit('update-available'); // For testing
|
||||
await autoUpdater.checkForUpdates();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async function handleAvailableUpdate(info: UpdateInfo) {
|
||||
if (requiresManualUpdate()) {
|
||||
await handleManualUpdate(info);
|
||||
return;
|
||||
}
|
||||
await handleAutoUpdate();
|
||||
if (requiresManualUpdate()) {
|
||||
await handleManualUpdate(info);
|
||||
return;
|
||||
}
|
||||
await handleAutoUpdate();
|
||||
}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
// This is main process of Electron, started as first thing when app starts.
|
||||
// This script is running through entire life of the application.
|
||||
// It doesn't have any windows which you can see on screen, opens the main window from here.
|
||||
|
||||
import { app, protocol, BrowserWindow, shell, screen } from 'electron';
|
||||
import path from 'path';
|
||||
import {
|
||||
app, protocol, BrowserWindow, shell, screen,
|
||||
} from 'electron';
|
||||
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib';
|
||||
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer';
|
||||
import path from 'path';
|
||||
import log from 'electron-log';
|
||||
import { setupAutoUpdater } from './Update/Updater';
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== 'production';
|
||||
|
||||
// Path of static assets, magic variable populated by electron
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
declare const __static: string; // https://github.com/electron-userland/electron-webpack/issues/172
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
@@ -25,7 +28,7 @@ protocol.registerSchemesAsPrivileged([
|
||||
|
||||
log.transports.file.level = 'silly';
|
||||
if (!process.env.IS_TEST) {
|
||||
Object.assign(console, log.functions); // override console.log, console.warn etc.
|
||||
Object.assign(console, log.functions); // override console.log, console.warn etc.
|
||||
}
|
||||
|
||||
function createWindow() {
|
||||
@@ -39,7 +42,7 @@ function createWindow() {
|
||||
// Use pluginOptions.nodeIntegration, leave this alone
|
||||
// See https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration
|
||||
nodeIntegration: (process.env
|
||||
.ELECTRON_NODE_INTEGRATION as unknown) as boolean,
|
||||
.ELECTRON_NODE_INTEGRATION as unknown) as boolean,
|
||||
},
|
||||
// https://nklayman.github.io/vue-cli-plugin-electron-builder/guide/recipes.html#set-tray-icon
|
||||
icon: path.join(__static, 'icon.png'),
|
||||
@@ -68,7 +71,8 @@ app.on('window-all-closed', () => {
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
// On macOS we application quit is stopped if user does not Cmd + Q
|
||||
// But we still want to be able to use app.quit() and quit the application on menu bar, after updates etc.
|
||||
// But we still want to be able to use app.quit() and quit the application
|
||||
// on menu bar, after updates etc.
|
||||
app.on('before-quit', () => {
|
||||
macOsQuit = true;
|
||||
});
|
||||
@@ -91,6 +95,7 @@ app.on('ready', async () => {
|
||||
try {
|
||||
await installExtension(VUEJS_DEVTOOLS);
|
||||
} catch (e) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('Vue Devtools failed to install:', e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user