From bb4ce5505a967e4452675ea89b64a4eb46fe7b86 Mon Sep 17 00:00:00 2001 From: MathieuG-P <40181755+Zagrios@users.noreply.github.com> Date: Sun, 21 Jan 2024 15:22:09 +0100 Subject: [PATCH] [chore] add @Log decorator + add logs for LivShortcuts --- .eslintrc.js | 1 + src/main/decorators/log.decorator.ts | 67 ++++++++++++++++++++++++++ src/main/services/liv/liv.service.ts | 8 ++- src/shared/helpers/error.helpers.ts | 23 +++++++-- src/shared/helpers/function.helpers.ts | 3 ++ src/shared/helpers/promise.helpers.ts | 9 ++++ tsconfig.json | 3 +- 7 files changed, 108 insertions(+), 6 deletions(-) create mode 100644 src/main/decorators/log.decorator.ts create mode 100644 src/shared/helpers/function.helpers.ts diff --git a/.eslintrc.js b/.eslintrc.js index ac327b68..00660f47 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -47,6 +47,7 @@ module.exports = { "import/no-cycle": "off", "prefer-promise-reject-errors": "off", "react/jsx-no-target-blank": "off" + "@typescript-eslint/ban-types": "off" }, parserOptions: { ecmaVersion: 2020, diff --git a/src/main/decorators/log.decorator.ts b/src/main/decorators/log.decorator.ts new file mode 100644 index 00000000..9c87f932 --- /dev/null +++ b/src/main/decorators/log.decorator.ts @@ -0,0 +1,67 @@ +import log from "electron-log"; +import { isPromise } from "../../shared/helpers/promise.helpers"; +import { tryit } from "../../shared/helpers/error.helpers"; + +type LogOptions = { + logInput?: boolean; + logOutput?: boolean; + logArgs?: boolean; +}; + +const stringifyArgs = (args: unknown[]) => { + return args?.map(a => JSON.stringify(a)).join(', '); +}; + +const logInfo = (message: string, propertyKey: string, args: unknown[], logArgs: boolean, result: unknown) => { + log.info(`[${message}] ${propertyKey}(${logArgs ? stringifyArgs(args) : ''})`, result); +}; + +const logError = (propertyKey: string, args: unknown[], logArgs: boolean, error: unknown) => { + log.error(`[ERROR] ${propertyKey}(${logArgs ? stringifyArgs(args) : ''})`, error); + throw error; +}; + +export function Log(options?: LogOptions){ + + const logInput = options?.logInput ?? false; + const logOutput = options?.logOutput ?? true; + const logArgs = options?.logArgs ?? true; + + return (target: unknown, propertyKey: string, descriptor: PropertyDescriptor) => { + const originalMethod = descriptor.value; + + descriptor.value = function(...args: unknown[]) { + + if (logInput) { + logInfo('INPUT', propertyKey, args, logArgs, null); + } + + const outcome = tryit(() => originalMethod.apply(this, args)); + + if (isPromise(outcome)) { + return outcome.then(({ result, error }) => { + + if (error) { + logError(propertyKey, args, logArgs, error); + } + if (logOutput) { + logInfo('OUTPUT', propertyKey, args, logArgs, result); + } + return result; + }); + } + + const { result, error } = outcome; + + if (error) { + logError(propertyKey, args, logArgs, error); + } + + if (logOutput) { + logInfo('OUTPUT', propertyKey, args, logArgs, result); + } + + return result; + }; + }; +} diff --git a/src/main/services/liv/liv.service.ts b/src/main/services/liv/liv.service.ts index ce9c649d..38b488e1 100644 --- a/src/main/services/liv/liv.service.ts +++ b/src/main/services/liv/liv.service.ts @@ -1,6 +1,7 @@ import { execOnOs } from "../../helpers/env.helpers"; import { list, createKey, putValue, deleteKey, RegSzValue } from "regedit-rs"; import path from "path"; +import { Log } from "../../decorators/log.decorator"; export class LivService { @@ -20,6 +21,7 @@ export class LivService { } + @Log() public async isLivInstalled(): Promise { return execOnOs({ win32: async () => { @@ -29,6 +31,7 @@ export class LivService { }, true); } + @Log() public async createLivShortcut(entry: LivEntry): Promise { return execOnOs({ win32: async () => { @@ -46,6 +49,7 @@ export class LivService { }); } + @Log() public async deleteLivShortcuts(ids: string[]): Promise { return execOnOs({ win32: async () => { @@ -55,11 +59,13 @@ export class LivService { }) } + @Log() public getLivShortcuts(): Promise { + return execOnOs({ win32: async () => { const regRes = await list(this.livExternalAppsRegeditKey).then(res => res[this.livExternalAppsRegeditKey]); - + if(!regRes.exists){ return []; } diff --git a/src/shared/helpers/error.helpers.ts b/src/shared/helpers/error.helpers.ts index ce67ffa0..33f71fce 100644 --- a/src/shared/helpers/error.helpers.ts +++ b/src/shared/helpers/error.helpers.ts @@ -1,7 +1,22 @@ -export function tryit(func: () => Return): {error: Error, result: Return} { +import { isPromise } from "./promise.helpers"; + +type TryitReturn = Return extends Promise ? Promise<{ error: Error | null, result: Awaited | null }> : { error: Error | null, result: Return | null }; + +export function tryit(func: () => Return): TryitReturn { try { - return { error: null, result: func() }; + const result = func(); + + if(isPromise(result)){ + return result + .then((value) => ({ error: null, result: value })) + .catch((err) => ({ error: err instanceof Error ? err : new Error(`${err}`), result: null })) as Return extends Promise + ? Promise<{error: Error, result: undefined} | {error: undefined, result: Awaited}> + : {error: Error, result: undefined} | {error: undefined, result: Return}; + } + + return { error: undefined, result } as TryitReturn; + } catch (err) { - return { error: err instanceof Error ? err : new Error(`${err}`), result: null } + return { error: err, result: undefined } as TryitReturn; } -} \ No newline at end of file +} diff --git a/src/shared/helpers/function.helpers.ts b/src/shared/helpers/function.helpers.ts new file mode 100644 index 00000000..6f17657d --- /dev/null +++ b/src/shared/helpers/function.helpers.ts @@ -0,0 +1,3 @@ +export function isFunction(value: any): value is Function { + return !!(value && value.constructor && value.call && value.apply) +} diff --git a/src/shared/helpers/promise.helpers.ts b/src/shared/helpers/promise.helpers.ts index d9ed9995..3bcbd069 100644 --- a/src/shared/helpers/promise.helpers.ts +++ b/src/shared/helpers/promise.helpers.ts @@ -1,3 +1,5 @@ +import { isFunction } from "./function.helpers"; + export type AllSettledHelperOptions = { keepStructure?: boolean; removeFalsy?: boolean; @@ -19,3 +21,10 @@ export async function allSettled(promises: Promise[], options?: AllSettled return acc; }, []); } + +export function isPromise(value: any): value is Promise { + if(!value) { return false; } + if(!value.then) { return false; } + if(!isFunction(value.then)) { return false; } + return true; +} diff --git a/tsconfig.json b/tsconfig.json index 13c86d2f..3f432026 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,7 +20,8 @@ "resolveJsonModule": true, "allowJs": true, "outDir": "release/app/dist", - "strictNullChecks": false + "strictNullChecks": false, + "experimentalDecorators": true }, "exclude": ["test", "release/build", "release/app/dist", ".erb/dll"] }