Typescript - Refactor code base

This commit is contained in:
Kiran Niranjan 2019-01-16 23:30:59 +05:30
parent 3177e54b6e
commit 9c138ddf25
25 changed files with 125 additions and 115 deletions

View File

@ -6,8 +6,8 @@
"buildNumber": "0",
"description": "Symphony desktop app (Foundation ODP)",
"author": "Symphony",
"main": "lib/src/browser/main.js",
"types": "lib/src/browser/main.d.ts",
"main": "lib/src/app/main.js",
"types": "lib/src/app/main.d.ts",
"scripts": {
"compile": "npm run lint && gulp build",
"lint": "tslint --project tsconfig.json",

View File

@ -5,7 +5,7 @@ import { i18n, LocaleType } from '../common/i18n';
import { logger } from '../common/logger';
import { autoLaunchInstance as autoLaunch } from './auto-launch-controller';
import { config, IConfig } from './config-handler';
import { exportCrashDumps, exportLogs } from './reports';
import { exportCrashDumps, exportLogs } from './reports-handler';
import { updateAlwaysOnTop } from './window-actions';
import { windowHandler } from './window-handler';

View File

@ -46,7 +46,7 @@ const library = new Library((cryptoLibPath), {
getVersion: [types.CString, []],
});
export interface ICryptoLib {
interface ICryptoLib {
AESGCMEncrypt: (name: string, base64IV: string, base64AAD: string, base64Key: string, base64In: string) => string | null;
AESGCMDecrypt: (base64IV: string, base64AAD: string, base64Key: string, base64In: string) => string | null;
}

View File

@ -9,7 +9,7 @@ import { setChromeFlags } from './chrome-flags';
import { config } from './config-handler';
import './dialog-handler';
import './main-api-handler';
import { SpellChecker } from './spell-checker-handler';
import { SpellChecker } from './spell-check-handler';
import { ICustomBrowserWindow, windowHandler } from './window-handler';
const allowMultiInstance: string | boolean = getCommandLineArgs(process.argv, '--multiInstance', true) || isDevEnv;

View File

@ -1,11 +1,64 @@
import * as archiver from 'archiver';
import { app, BrowserWindow, dialog, shell } from 'electron';
import * as fs from 'fs';
import * as electron from 'electron';
import * as fs from 'fs';
import * as path from 'path';
import { isMac } from '../common/env';
import { i18n } from '../common/i18n';
import { generateArchiveForDirectory } from '../common/utils';
/**
* Archives files in the source directory
* that matches the given file extension
*
* @param source {String} source path
* @param destination {String} destination path
* @param fileExtensions {Array} array of file ext
* @return {Promise<void>}
*/
const generateArchiveForDirectory = (source: string, destination: string, fileExtensions: string[]): Promise<void> => {
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(destination);
const archive = archiver('zip', { zlib: { level: 9 } });
output.on('close', () => {
return resolve();
});
archive.on('error', (err) => {
return reject(err);
});
archive.pipe(output);
const files = fs.readdirSync(source);
files
.filter((file) => fileExtensions.indexOf(path.extname(file)) !== -1)
.forEach((file) => {
switch (path.extname(file)) {
case '.log':
archive.file(source + '/' + file, { name: 'logs/' + file });
break;
case '.dmp':
case '.txt': // on Windows .txt files will be created as part of crash dump
archive.file(source + '/' + file, { name: 'crashes/' + file });
break;
default:
break;
}
});
archive.finalize();
});
};
/**
* Compress and export logs stored under system log directory
*
* MacOS - /Library/Logs/Symphony/
* Windows - AppData\Roaming\Symphony\logs
*/
export const exportLogs = (): void => {
const FILE_EXTENSIONS = [ '.log' ];
const MAC_LOGS_PATH = '/Library/Logs/Symphony/';
@ -42,6 +95,9 @@ export const exportLogs = (): void => {
});
};
/**
* Compress and export crash dump stored under system crashes directory
*/
export const exportCrashDumps = (): void => {
const FILE_EXTENSIONS = isMac ? [ '.dmp' ] : [ '.dmp', '.txt' ];
const crashesDirectory = (electron.crashReporter as any).getCrashesDirectory();

View File

@ -2,7 +2,7 @@ import { BrowserWindow } from 'electron';
import { apiName, IBoundsChange, KeyCodes } from '../common/api-interface';
import { isWindowsOS } from '../common/env';
import { throttle } from '../common/throttle';
import { throttle } from '../common/utils';
import { config } from './config-handler';
import { ICustomBrowserWindow, windowHandler } from './window-handler';
import { showPopupMenu } from './window-utils';

View File

@ -10,9 +10,9 @@ import { isMac, isWindowsOS } from '../common/env';
import { i18n } from '../common/i18n';
import { getCommandLineArgs, getGuid } from '../common/utils';
import { AppMenu } from './app-menu';
import { handleChildWindow } from './child-window-handler';
import { config, IConfig } from './config-handler';
import { showNetworkConnectivityError } from './dialog-handler';
import { handleChildWindow } from './pop-out-window-handler';
import { monitorWindowActions } from './window-actions';
import { createComponentWindow, getBounds, handleDownloadManager, injectStyles } from './window-utils';

View File

@ -1,30 +0,0 @@
/**
* Formats a string with dynamic values
* @param str {String} String to be formatted
* @param data {Object} - Data to be added
*
* @example
* StringFormat(this will log {time}`, { time: '1234' })
*
* result:
* this will log 1234
*
* @return {*}
*/
export const formatString = (str: string, data?: object): string => {
if (!str || !data) return str;
for (const key in data) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
return str.replace(/({([^}]+)})/g, (i) => {
const replacedKey = i.replace(/{/, '').replace(/}/, '');
if (!data[key] || !data[key][replacedKey]) {
return i;
}
return data[key][replacedKey];
});
}
}
return str;
};

View File

@ -1,4 +1,4 @@
import { formatString } from './format-string';
import { formatString } from './utils';
const localeCodeRegex = /^([a-z]{2})-([A-Z]{2})$/;

View File

@ -1,7 +1,7 @@
import * as fs from 'fs';
import * as path from 'path';
import { formatString } from './format-string';
import { formatString } from './utils';
const localeCodeRegex = /^([a-z]{2})-([A-Z]{2})$/;

View File

@ -1,22 +0,0 @@
/**
* Limits your function to be called at most every milliseconds
*
* @param func
* @param wait
* @example const throttled = throttle(anyFunc, 500);
*/
export const throttle = (func: (...args) => void, wait: number): (...args) => void => {
if (wait <= 0) {
throw Error('throttle: invalid throttleTime arg, must be a number: ' + wait);
}
let isCalled: boolean = false;
return (...args) => {
if (!isCalled) {
func(...args);
isCalled = true;
setTimeout(() => isCalled = false, wait);
}
};
};

View File

@ -1,7 +1,3 @@
import * as archiver from 'archiver';
import * as fs from 'fs';
import * as path from 'path';
// regex match the semver (semantic version) this checks for the pattern X.Y.Z
// ex-valid v1.2.0, 1.2.0, 2.3.4-r51
const semver = /^v?(?:\d+)(\.(?:[x*]|\d+)(\.(?:[x*]|\d+)(?:-[\da-z-]+(?:\.[\da-z-]+)*)?(?:\+[\da-z-]+(?:\.[\da-z-]+)*)?)?)?$/i;
@ -52,7 +48,7 @@ const validate = (version: string): number => {
* @param v2
* @returns {number}
*/
const compareVersions = (v1: string, v2: string): number => {
export const compareVersions = (v1: string, v2: string): number => {
if (validate(v1) === -1 || validate(v2) === -1) {
return -1;
}
@ -96,7 +92,7 @@ const compareVersions = (v1: string, v2: string): number => {
* try finding arg that starts with argName.
* @return {String} If found, returns the arg, otherwise null.
*/
const getCommandLineArgs = (argv: string[], argName: string, exactMatch: boolean): string | null => {
export const getCommandLineArgs = (argv: string[], argName: string, exactMatch: boolean): string | null => {
if (!Array.isArray(argv)) {
throw new Error(`get-command-line-args: TypeError invalid func arg, must be an array: ${argv}`);
}
@ -120,7 +116,7 @@ const getCommandLineArgs = (argv: string[], argName: string, exactMatch: boolean
*
* @return {String} guid value in string
*/
const getGuid = (): string => {
export const getGuid = (): string => {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,
(c) => {
const r = Math.random() * 16 | 0; // tslint:disable-line:no-bitwise
@ -135,7 +131,7 @@ const getGuid = (): string => {
* @param object Object to be filtered
* @param fields Fields to be picked
*/
const pick = (object: object, fields: string[]) => {
export const pick = (object: object, fields: string[]) => {
const obj = {};
for (const field of fields) {
if (object[field]) {
@ -146,49 +142,55 @@ const pick = (object: object, fields: string[]) => {
};
/**
* Archives files in the source directory
* that matches the given file extension
* Limits your function to be called at most every milliseconds
*
* @param source {String} source path
* @param destination {String} destination path
* @param fileExtensions {Array} array of file ext
* @return {Promise<void>}
* @param func
* @param wait
* @example const throttled = throttle(anyFunc, 500);
*/
const generateArchiveForDirectory = (source: string, destination: string, fileExtensions: string[]): Promise<void> => {
export const throttle = (func: (...args) => void, wait: number): (...args) => void => {
if (wait <= 0) {
throw Error('throttle: invalid throttleTime arg, must be a number: ' + wait);
}
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(destination);
const archive = archiver('zip', { zlib: { level: 9 } });
let isCalled: boolean = false;
output.on('close', () => {
return resolve();
});
archive.on('error', (err) => {
return reject(err);
});
archive.pipe(output);
const files = fs.readdirSync(source);
files
.filter((file) => fileExtensions.indexOf(path.extname(file)) !== -1)
.forEach((file) => {
switch (path.extname(file)) {
case '.log':
archive.file(source + '/' + file, { name: 'logs/' + file });
break;
case '.dmp':
case '.txt': // on Windows .txt files will be created as part of crash dump
archive.file(source + '/' + file, { name: 'crashes/' + file });
break;
default:
break;
}
});
archive.finalize();
});
return (...args) => {
if (!isCalled) {
func(...args);
isCalled = true;
setTimeout(() => isCalled = false, wait);
}
};
};
export { compareVersions, getCommandLineArgs, getGuid, pick, generateArchiveForDirectory };
/**
* Formats a string with dynamic values
* @param str {String} String to be formatted
* @param data {Object} - Data to be added
*
* @example
* StringFormat(this will log {time}`, { time: '1234' })
*
* result:
* this will log 1234
*
* @return {*}
*/
export const formatString = (str: string, data?: object): string => {
if (!str || !data) return str;
for (const key in data) {
if (Object.prototype.hasOwnProperty.call(data, key)) {
return str.replace(/({([^}]+)})/g, (i) => {
const replacedKey = i.replace(/{/, '').replace(/}/, '');
if (!data[key] || !data[key][replacedKey]) {
return i;
}
return data[key][replacedKey];
});
}
}
return str;
};

View File

@ -1,6 +1,5 @@
import { ipcRenderer, remote } from 'electron';
import { ICryptoLib } from '../browser/crypto-library-handler';
import {
apiCmds,
apiName,
@ -10,13 +9,18 @@ import {
IScreenSnippet, KeyCodes,
} from '../common/api-interface';
import { i18n, LocaleType } from '../common/i18n-preload';
import { throttle } from '../common/throttle';
import { throttle } from '../common/utils';
import { getSource } from './desktop-capturer';
let isAltKey: boolean = false;
let isMenuOpen: boolean = false;
let nextId = 0;
interface ICryptoLib {
AESGCMEncrypt: (name: string, base64IV: string, base64AAD: string, base64Key: string, base64In: string) => string | null;
AESGCMDecrypt: (base64IV: string, base64AAD: string, base64Key: string, base64In: string) => string | null;
}
interface ILocalObject {
ipcRenderer;
activityDetectionCallback?: (arg: IActivityDetection) => void;
@ -46,7 +50,7 @@ const throttledSetLocale = throttle((locale) => {
let cryptoLib: ICryptoLib | null;
try {
cryptoLib = remote.require('../browser/crypto-library-handler.js').cryptoLibrary;
cryptoLib = remote.require('../app/crypto-handler.js').cryptoLibrary;
} catch (e) {
cryptoLib = null;
// tslint:disable-next-line