Typescriptify main.js
This commit is contained in:
parent
e033fd2cf3
commit
9a1430a460
22 changed files with 721 additions and 524 deletions
|
@ -5,19 +5,21 @@
|
|||
/* eslint-disable more/no-then */
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import { join } from 'path';
|
||||
import { readdirSync, readFile, unlinkSync, writeFileSync } from 'fs';
|
||||
import { BrowserWindow, app, ipcMain as ipc } from 'electron';
|
||||
import pinoms from 'pino-multi-stream';
|
||||
import pino from 'pino';
|
||||
import * as mkdirp from 'mkdirp';
|
||||
import * as _ from 'lodash';
|
||||
import { compact, filter, flatten, map, pick, sortBy } from 'lodash';
|
||||
import readFirstLine from 'firstline';
|
||||
import { read as readLastLines } from 'read-last-lines';
|
||||
import rimraf from 'rimraf';
|
||||
import { createStream } from 'rotating-file-stream';
|
||||
|
||||
import { setLogAtLevel } from './log';
|
||||
import type { LoggerType } from '../types/Logging';
|
||||
|
||||
import * as log from './log';
|
||||
import { Environment, getEnvironment } from '../environment';
|
||||
|
||||
import {
|
||||
|
@ -39,7 +41,7 @@ declare global {
|
|||
}
|
||||
}
|
||||
|
||||
let globalLogger: undefined | pinoms.Logger;
|
||||
let globalLogger: undefined | pino.Logger;
|
||||
let shouldRestart = false;
|
||||
|
||||
const isRunningFromConsole =
|
||||
|
@ -49,13 +51,13 @@ const isRunningFromConsole =
|
|||
|
||||
export async function initialize(
|
||||
getMainWindow: () => undefined | BrowserWindow
|
||||
): Promise<pinoms.Logger> {
|
||||
): Promise<LoggerType> {
|
||||
if (globalLogger) {
|
||||
throw new Error('Already called initialize!');
|
||||
}
|
||||
|
||||
const basePath = app.getPath('userData');
|
||||
const logPath = path.join(basePath, 'logs');
|
||||
const logPath = join(basePath, 'logs');
|
||||
mkdirp.sync(logPath);
|
||||
|
||||
try {
|
||||
|
@ -73,7 +75,7 @@ export async function initialize(
|
|||
}, 500);
|
||||
}
|
||||
|
||||
const logFile = path.join(logPath, 'main.log');
|
||||
const logFile = join(logPath, 'main.log');
|
||||
const stream = createStream(logFile, {
|
||||
interval: '1d',
|
||||
rotate: 3,
|
||||
|
@ -160,7 +162,7 @@ export async function initialize(
|
|||
|
||||
globalLogger = logger;
|
||||
|
||||
return logger;
|
||||
return log;
|
||||
}
|
||||
|
||||
async function deleteAllLogs(logPath: string): Promise<void> {
|
||||
|
@ -189,7 +191,7 @@ async function cleanupLogs(logPath: string) {
|
|||
|
||||
try {
|
||||
const remaining = await eliminateOutOfDateFiles(logPath, earliestDate);
|
||||
const files = _.filter(remaining, file => !file.start && file.end);
|
||||
const files = filter(remaining, file => !file.start && file.end);
|
||||
|
||||
if (!files.length) {
|
||||
return;
|
||||
|
@ -234,11 +236,11 @@ export function eliminateOutOfDateFiles(
|
|||
end: boolean;
|
||||
}>
|
||||
> {
|
||||
const files = fs.readdirSync(logPath);
|
||||
const paths = files.map(file => path.join(logPath, file));
|
||||
const files = readdirSync(logPath);
|
||||
const paths = files.map(file => join(logPath, file));
|
||||
|
||||
return Promise.all(
|
||||
_.map(paths, target =>
|
||||
map(paths, target =>
|
||||
Promise.all([readFirstLine(target), readLastLines(target, 2)]).then(
|
||||
results => {
|
||||
const start = results[0];
|
||||
|
@ -253,7 +255,7 @@ export function eliminateOutOfDateFiles(
|
|||
};
|
||||
|
||||
if (!file.start && !file.end) {
|
||||
fs.unlinkSync(file.path);
|
||||
unlinkSync(file.path);
|
||||
}
|
||||
|
||||
return file;
|
||||
|
@ -269,12 +271,12 @@ export async function eliminateOldEntries(
|
|||
date: Readonly<Date>
|
||||
): Promise<void> {
|
||||
await Promise.all(
|
||||
_.map(files, file =>
|
||||
map(files, file =>
|
||||
fetchLog(file.path).then(lines => {
|
||||
const recent = _.filter(lines, line => new Date(line.time) >= date);
|
||||
const text = _.map(recent, line => JSON.stringify(line)).join('\n');
|
||||
const recent = filter(lines, line => new Date(line.time) >= date);
|
||||
const text = map(recent, line => JSON.stringify(line)).join('\n');
|
||||
|
||||
return fs.writeFileSync(file.path, `${text}\n`);
|
||||
return writeFileSync(file.path, `${text}\n`);
|
||||
})
|
||||
)
|
||||
);
|
||||
|
@ -283,16 +285,16 @@ export async function eliminateOldEntries(
|
|||
// Exported for testing only.
|
||||
export function fetchLog(logFile: string): Promise<Array<LogEntryType>> {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(logFile, { encoding: 'utf8' }, (err, text) => {
|
||||
readFile(logFile, { encoding: 'utf8' }, (err, text) => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
const lines = _.compact(text.split('\n'));
|
||||
const data = _.compact(
|
||||
const lines = compact(text.split('\n'));
|
||||
const data = compact(
|
||||
lines.map(line => {
|
||||
try {
|
||||
const result = _.pick(JSON.parse(line), ['level', 'time', 'msg']);
|
||||
const result = pick(JSON.parse(line), ['level', 'time', 'msg']);
|
||||
return isLogEntry(result) ? result : null;
|
||||
} catch (e) {
|
||||
return null;
|
||||
|
@ -307,8 +309,8 @@ export function fetchLog(logFile: string): Promise<Array<LogEntryType>> {
|
|||
|
||||
// Exported for testing only.
|
||||
export function fetchLogs(logPath: string): Promise<Array<LogEntryType>> {
|
||||
const files = fs.readdirSync(logPath);
|
||||
const paths = files.map(file => path.join(logPath, file));
|
||||
const files = readdirSync(logPath);
|
||||
const paths = files.map(file => join(logPath, file));
|
||||
|
||||
// creating a manual log entry for the final log result
|
||||
const fileListEntry: LogEntryType = {
|
||||
|
@ -318,11 +320,11 @@ export function fetchLogs(logPath: string): Promise<Array<LogEntryType>> {
|
|||
};
|
||||
|
||||
return Promise.all(paths.map(fetchLog)).then(results => {
|
||||
const data = _.flatten(results);
|
||||
const data = flatten(results);
|
||||
|
||||
data.push(fileListEntry);
|
||||
|
||||
return _.sortBy(data, logEntry => logEntry.time);
|
||||
return sortBy(data, logEntry => logEntry.time);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -351,12 +353,12 @@ function isProbablyObjectHasBeenDestroyedError(err: unknown): boolean {
|
|||
|
||||
// This blows up using mocha --watch, so we ensure it is run just once
|
||||
if (!console._log) {
|
||||
setLogAtLevel(logAtLevel);
|
||||
log.setLogAtLevel(logAtLevel);
|
||||
|
||||
console._log = console.log;
|
||||
console.log = _.partial(logAtLevel, LogLevel.Info);
|
||||
console.log = log.info;
|
||||
console._error = console.error;
|
||||
console.error = _.partial(logAtLevel, LogLevel.Error);
|
||||
console.error = log.error;
|
||||
console._warn = console.warn;
|
||||
console.warn = _.partial(logAtLevel, LogLevel.Warn);
|
||||
console.warn = log.warn;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
export class SettingsChannel {
|
||||
private mainWindow?: BrowserWindow;
|
||||
|
||||
public setMainWindow(mainWindow: BrowserWindow): void {
|
||||
public setMainWindow(mainWindow: BrowserWindow | undefined): void {
|
||||
this.mainWindow = mainWindow;
|
||||
}
|
||||
|
||||
|
|
|
@ -170,6 +170,7 @@ describe('sgnlHref', () => {
|
|||
assert.deepEqual(parseSgnlHref(href, explodingLogger), {
|
||||
command: null,
|
||||
args: new Map<never, never>(),
|
||||
hash: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -329,6 +330,7 @@ describe('sgnlHref', () => {
|
|||
assert.deepEqual(parseSignalHttpsLink(href, explodingLogger), {
|
||||
command: null,
|
||||
args: new Map<never, never>(),
|
||||
hash: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -354,9 +354,17 @@ export function setUpdateListener(performUpdateCallback: () => void): void {
|
|||
ipcMain.once('start-update', performUpdateCallback);
|
||||
}
|
||||
|
||||
export function getAutoDownloadUpdateSetting(
|
||||
mainWindow: BrowserWindow
|
||||
export async function getAutoDownloadUpdateSetting(
|
||||
mainWindow: BrowserWindow | undefined,
|
||||
logger: LoggerType
|
||||
): Promise<boolean> {
|
||||
if (!mainWindow) {
|
||||
logger.warn(
|
||||
'getAutoDownloadUpdateSetting: No main window, returning false'
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcMain.once(
|
||||
'settings:get-success:autoDownloadUpdate',
|
||||
|
|
|
@ -14,7 +14,7 @@ let initialized = false;
|
|||
let updater: UpdaterInterface | undefined;
|
||||
|
||||
export async function start(
|
||||
getMainWindow: () => BrowserWindow,
|
||||
getMainWindow: () => BrowserWindow | undefined,
|
||||
logger?: LoggerType
|
||||
): Promise<void> {
|
||||
const { platform } = process;
|
||||
|
|
|
@ -30,7 +30,7 @@ import { DialogType } from '../types/Dialogs';
|
|||
const INTERVAL = 30 * durations.MINUTE;
|
||||
|
||||
export async function start(
|
||||
getMainWindow: () => BrowserWindow,
|
||||
getMainWindow: () => BrowserWindow | undefined,
|
||||
logger: LoggerType
|
||||
): Promise<UpdaterInterface> {
|
||||
logger.info('macos/start: starting checks...');
|
||||
|
@ -61,7 +61,7 @@ let updateFilePath: string;
|
|||
let loggerForQuitHandler: LoggerType;
|
||||
|
||||
async function checkForUpdatesMaybeInstall(
|
||||
getMainWindow: () => BrowserWindow,
|
||||
getMainWindow: () => BrowserWindow | undefined,
|
||||
logger: LoggerType,
|
||||
force = false
|
||||
) {
|
||||
|
@ -75,12 +75,13 @@ async function checkForUpdatesMaybeInstall(
|
|||
|
||||
if (fileName !== newFileName || !version || gt(newVersion, version)) {
|
||||
const autoDownloadUpdates = await getAutoDownloadUpdateSetting(
|
||||
getMainWindow()
|
||||
getMainWindow(),
|
||||
logger
|
||||
);
|
||||
if (!autoDownloadUpdates) {
|
||||
setUpdateListener(async () => {
|
||||
logger.info(
|
||||
'performUpdate: have not downloaded update, going to download'
|
||||
'checkForUpdatesMaybeInstall: have not downloaded update, going to download'
|
||||
);
|
||||
await downloadAndInstall(
|
||||
newFileName,
|
||||
|
@ -90,14 +91,22 @@ async function checkForUpdatesMaybeInstall(
|
|||
true
|
||||
);
|
||||
});
|
||||
getMainWindow().webContents.send(
|
||||
'show-update-dialog',
|
||||
DialogType.DownloadReady,
|
||||
{
|
||||
downloadSize: result.size,
|
||||
version: result.version,
|
||||
}
|
||||
);
|
||||
const mainWindow = getMainWindow();
|
||||
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send(
|
||||
'show-update-dialog',
|
||||
DialogType.DownloadReady,
|
||||
{
|
||||
downloadSize: result.size,
|
||||
version: result.version,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
'checkForUpdatesMaybeInstall: no mainWindow, cannot show update dialog'
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
await downloadAndInstall(newFileName, newVersion, getMainWindow, logger);
|
||||
|
@ -107,7 +116,7 @@ async function checkForUpdatesMaybeInstall(
|
|||
async function downloadAndInstall(
|
||||
newFileName: string,
|
||||
newVersion: string,
|
||||
getMainWindow: () => BrowserWindow,
|
||||
getMainWindow: () => BrowserWindow | undefined,
|
||||
logger: LoggerType,
|
||||
updateOnProgress?: boolean
|
||||
) {
|
||||
|
@ -151,20 +160,25 @@ async function downloadAndInstall(
|
|||
} catch (error) {
|
||||
const readOnly = 'Cannot update while running on a read-only volume';
|
||||
const message: string = error.message || '';
|
||||
if (message.includes(readOnly)) {
|
||||
const mainWindow = getMainWindow();
|
||||
if (mainWindow && message.includes(readOnly)) {
|
||||
logger.info('downloadAndInstall: showing read-only dialog...');
|
||||
getMainWindow().webContents.send(
|
||||
mainWindow.webContents.send(
|
||||
'show-update-dialog',
|
||||
DialogType.MacOS_Read_Only
|
||||
);
|
||||
} else {
|
||||
} else if (mainWindow) {
|
||||
logger.info(
|
||||
'downloadAndInstall: showing general update failure dialog...'
|
||||
);
|
||||
getMainWindow().webContents.send(
|
||||
mainWindow.webContents.send(
|
||||
'show-update-dialog',
|
||||
DialogType.Cannot_Update
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
'downloadAndInstall: no mainWindow, cannot show update dialog'
|
||||
);
|
||||
}
|
||||
|
||||
throw error;
|
||||
|
@ -179,9 +193,17 @@ async function downloadAndInstall(
|
|||
markShouldQuit();
|
||||
autoUpdater.quitAndInstall();
|
||||
});
|
||||
getMainWindow().webContents.send('show-update-dialog', DialogType.Update, {
|
||||
version,
|
||||
});
|
||||
const mainWindow = getMainWindow();
|
||||
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send('show-update-dialog', DialogType.Update, {
|
||||
version,
|
||||
});
|
||||
} else {
|
||||
logger.warn(
|
||||
'checkForUpdatesMaybeInstall: no mainWindow, cannot show update dialog'
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`downloadAndInstall: ${getPrintableError(error)}`);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ let installing: boolean;
|
|||
let loggerForQuitHandler: LoggerType;
|
||||
|
||||
export async function start(
|
||||
getMainWindow: () => BrowserWindow,
|
||||
getMainWindow: () => BrowserWindow | undefined,
|
||||
logger: LoggerType
|
||||
): Promise<UpdaterInterface> {
|
||||
logger.info('windows/start: starting checks...');
|
||||
|
@ -64,7 +64,7 @@ export async function start(
|
|||
}
|
||||
|
||||
async function checkForUpdatesMaybeInstall(
|
||||
getMainWindow: () => BrowserWindow,
|
||||
getMainWindow: () => BrowserWindow | undefined,
|
||||
logger: LoggerType,
|
||||
force = false
|
||||
) {
|
||||
|
@ -78,12 +78,13 @@ async function checkForUpdatesMaybeInstall(
|
|||
|
||||
if (fileName !== newFileName || !version || gt(newVersion, version)) {
|
||||
const autoDownloadUpdates = await getAutoDownloadUpdateSetting(
|
||||
getMainWindow()
|
||||
getMainWindow(),
|
||||
logger
|
||||
);
|
||||
if (!autoDownloadUpdates) {
|
||||
setUpdateListener(async () => {
|
||||
logger.info(
|
||||
'performUpdate: have not downloaded update, going to download'
|
||||
'checkForUpdatesMaybeInstall: have not downloaded update, going to download'
|
||||
);
|
||||
await downloadAndInstall(
|
||||
newFileName,
|
||||
|
@ -93,14 +94,21 @@ async function checkForUpdatesMaybeInstall(
|
|||
true
|
||||
);
|
||||
});
|
||||
getMainWindow().webContents.send(
|
||||
'show-update-dialog',
|
||||
DialogType.DownloadReady,
|
||||
{
|
||||
downloadSize: result.size,
|
||||
version: result.version,
|
||||
}
|
||||
);
|
||||
const mainWindow = getMainWindow();
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send(
|
||||
'show-update-dialog',
|
||||
DialogType.DownloadReady,
|
||||
{
|
||||
downloadSize: result.size,
|
||||
version: result.version,
|
||||
}
|
||||
);
|
||||
} else {
|
||||
logger.warn(
|
||||
'checkForUpdatesMaybeInstall: No mainWindow, not showing update dialog'
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
await downloadAndInstall(newFileName, newVersion, getMainWindow, logger);
|
||||
|
@ -110,7 +118,7 @@ async function checkForUpdatesMaybeInstall(
|
|||
async function downloadAndInstall(
|
||||
newFileName: string,
|
||||
newVersion: string,
|
||||
getMainWindow: () => BrowserWindow,
|
||||
getMainWindow: () => BrowserWindow | undefined,
|
||||
logger: LoggerType,
|
||||
updateOnProgress?: boolean
|
||||
) {
|
||||
|
@ -151,11 +159,18 @@ async function downloadAndInstall(
|
|||
await verifyAndInstall(updateFilePath, newVersion, logger);
|
||||
installing = true;
|
||||
} catch (error) {
|
||||
logger.info('createUpdater: showing general update failure dialog...');
|
||||
getMainWindow().webContents.send(
|
||||
'show-update-dialog',
|
||||
DialogType.Cannot_Update
|
||||
);
|
||||
const mainWindow = getMainWindow();
|
||||
if (mainWindow) {
|
||||
logger.info(
|
||||
'createUpdater: showing general update failure dialog...'
|
||||
);
|
||||
mainWindow.webContents.send(
|
||||
'show-update-dialog',
|
||||
DialogType.Cannot_Update
|
||||
);
|
||||
} else {
|
||||
logger.warn('createUpdater: no mainWindow, just failing over...');
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
@ -163,9 +178,17 @@ async function downloadAndInstall(
|
|||
markShouldQuit();
|
||||
app.quit();
|
||||
});
|
||||
getMainWindow().webContents.send('show-update-dialog', DialogType.Update, {
|
||||
version,
|
||||
});
|
||||
|
||||
const mainWindow = getMainWindow();
|
||||
if (mainWindow) {
|
||||
mainWindow.webContents.send('show-update-dialog', DialogType.Update, {
|
||||
version,
|
||||
});
|
||||
} else {
|
||||
logger.warn(
|
||||
'downloadAndInstall: no mainWindow, cannot show update dialog'
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error(`downloadAndInstall: ${getPrintableError(error)}`);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
import { LocaleMessagesType } from '../types/I18N';
|
||||
import { LocalizerType } from '../types/Util';
|
||||
import * as log from '../logging/log';
|
||||
|
||||
export function setupI18n(
|
||||
locale: string,
|
||||
|
@ -16,9 +17,6 @@ export function setupI18n(
|
|||
}
|
||||
|
||||
const getMessage: LocalizerType = (key, substitutions) => {
|
||||
// eslint-disable-next-line no-console
|
||||
const log = window?.SignalWindow?.log || console;
|
||||
|
||||
const entry = messages[key];
|
||||
if (!entry) {
|
||||
log.error(
|
||||
|
|
|
@ -51,7 +51,7 @@ export function isSignalHttpsLink(
|
|||
}
|
||||
|
||||
type ParsedSgnlHref =
|
||||
| { command: null; args: Map<never, never> }
|
||||
| { command: null; args: Map<never, never>; hash: undefined }
|
||||
| { command: string; args: Map<string, string>; hash: string | undefined };
|
||||
export function parseSgnlHref(
|
||||
href: string,
|
||||
|
@ -59,7 +59,7 @@ export function parseSgnlHref(
|
|||
): ParsedSgnlHref {
|
||||
const url = parseUrl(href, logger);
|
||||
if (!url || !isSgnlHref(url, logger)) {
|
||||
return { command: null, args: new Map<never, never>() };
|
||||
return { command: null, args: new Map<never, never>(), hash: undefined };
|
||||
}
|
||||
|
||||
const args = new Map<string, string>();
|
||||
|
@ -99,7 +99,7 @@ export function parseSignalHttpsLink(
|
|||
): ParsedSgnlHref {
|
||||
const url = parseUrl(href, logger);
|
||||
if (!url || !isSignalHttpsLink(url, logger)) {
|
||||
return { command: null, args: new Map<never, never>() };
|
||||
return { command: null, args: new Map<never, never>(), hash: undefined };
|
||||
}
|
||||
|
||||
if (url.host === 'signal.art') {
|
||||
|
@ -114,7 +114,7 @@ export function parseSignalHttpsLink(
|
|||
});
|
||||
|
||||
if (!args.get('pack_id') || !args.get('pack_key')) {
|
||||
return { command: null, args: new Map<never, never>() };
|
||||
return { command: null, args: new Map<never, never>(), hash: undefined };
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -132,7 +132,7 @@ export function parseSignalHttpsLink(
|
|||
};
|
||||
}
|
||||
|
||||
return { command: null, args: new Map<never, never>() };
|
||||
return { command: null, args: new Map<never, never>(), hash: undefined };
|
||||
}
|
||||
|
||||
export function parseE164FromSignalDotMeHash(hash: string): undefined | string {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue