From b0e11bd386608df0ad59c880d4c19e48a66b1456 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Thu, 2 Nov 2023 19:01:22 -0400 Subject: [PATCH] Adds better progress & logging to webview msgs --- src/plus/webviews/graph/graphWebview.ts | 5 +-- src/plus/webviews/timeline/timelineWebview.ts | 10 ++--- src/system/decorators/log.ts | 4 ++ src/system/logger.scope.ts | 6 ++- src/system/logger.ts | 10 ++++- src/webviews/webviewController.ts | 54 +++++++++++++++++++++++---- 6 files changed, 68 insertions(+), 21 deletions(-) diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index ffd6e62..d253563 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -580,9 +580,7 @@ export class GraphWebviewProvider implements WebviewProvider - this.host.notify(DidChangeNotificationType, { - state: await this.getState(context), - }); - - if (!this.host.isView()) return task(); - return window.withProgress({ location: { viewId: this.host.id } }, task); + return this.host.notify(DidChangeNotificationType, { + state: await this.getState(context), + }); } } diff --git a/src/system/decorators/log.ts b/src/system/decorators/log.ts index 7ea2823..48c6924 100644 --- a/src/system/decorators/log.ts +++ b/src/system/decorators/log.ts @@ -91,6 +91,7 @@ export function log any>(options?: LogOptions, deb const logFn = debug ? Logger.debug.bind(Logger) : Logger.log.bind(Logger); const warnFn = Logger.warn.bind(Logger); + const errorFn = Logger.error.bind(Logger); return (target: any, key: string, descriptor: PropertyDescriptor & Record) => { let fn: Function | undefined; @@ -263,6 +264,9 @@ export function log any>(options?: LogOptions, deb } else if (exitFn === true) { exit = `returned ${Logger.toLoggable(r)}`; } + } else if (scope?.exitFailed) { + exit = scope.exitFailed; + exitLogFn = errorFn; } else { exit = 'completed'; } diff --git a/src/system/logger.scope.ts b/src/system/logger.scope.ts index 17f2e44..95d746a 100644 --- a/src/system/logger.scope.ts +++ b/src/system/logger.scope.ts @@ -7,6 +7,7 @@ export interface LogScope { readonly scopeId?: number; readonly prefix: string; exitDetails?: string; + exitFailed?: string; } export function clearLogScope(scopeId: number) { @@ -40,8 +41,11 @@ export function setLogScope(scopeId: number, scope: LogScope) { scopes.set(scopeId, scope); } -export function setLogScopeExit(scope: LogScope | undefined, details: string): void { +export function setLogScopeExit(scope: LogScope | undefined, details: string | undefined, failed?: string): void { if (scope == null) return; scope.exitDetails = details; + if (failed != null) { + scope.exitFailed = failed; + } } diff --git a/src/system/logger.ts b/src/system/logger.ts index 82297ef..40338b3 100644 --- a/src/system/logger.ts +++ b/src/system/logger.ts @@ -112,12 +112,18 @@ export const Logger = new (class Logger { } if (this.isDebugging) { - console.error(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params, ex); + if (ex != null) { + console.error(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params, ex); + } else { + console.error(this.timestamp, `[${this.provider!.name}]`, message ?? emptyStr, ...params); + } } if (this.output == null || this.level < OrderedLevel.Error) return; this.output.appendLine( - `${this.timestamp} ${message ?? emptyStr}${this.toLoggableParams(false, params)}\n${String(ex)}`, + `${this.timestamp} ${message ?? emptyStr}${this.toLoggableParams(false, params)}${ + ex != null ? `\n${String(ex)}` : '' + }`, ); } diff --git a/src/webviews/webviewController.ts b/src/webviews/webviewController.ts index 6813858..d21d6ad 100644 --- a/src/webviews/webviewController.ts +++ b/src/webviews/webviewController.ts @@ -3,10 +3,13 @@ import { Disposable, EventEmitter, Uri, ViewColumn, window, workspace } from 'vs import { getNonce } from '@env/crypto'; import type { Commands, CustomEditorTypes, WebviewTypes, WebviewViewTypes } from '../constants'; import type { Container } from '../container'; +import { pauseOnCancelOrTimeout } from '../system/cancellation'; import { executeCommand, executeCoreCommand } from '../system/command'; import { setContext } from '../system/context'; import { debug, logName } from '../system/decorators/log'; import { serialize } from '../system/decorators/serialize'; +import { Logger } from '../system/logger'; +import { getLogScope, setLogScopeExit } from '../system/logger.scope'; import { isPromise } from '../system/promise'; import type { WebviewContext } from '../system/webview'; import type { @@ -537,6 +540,7 @@ export class WebviewController< params: params, completionId: completionId, }; + const success = await this.postMessage(msg); if (success) { this._pendingIpcNotifications.clear(); @@ -548,18 +552,52 @@ export class WebviewController< @serialize() @debug['postMessage']>({ - args: { - 0: m => `{"id":${m.id},"method":${m.method}${m.completionId ? `,"completionId":${m.completionId}` : ''}}`, - }, + args: false, + enter: m => `(${m.id}|${m.method}${m.completionId ? `+${m.completionId}` : ''})`, }) private async postMessage(message: IpcMessage): Promise { if (!this._ready) return Promise.resolve(false); - // It looks like there is a bug where `postMessage` can sometimes just hang infinitely. Not sure why, but ensure we don't hang - const success = await Promise.race([ - this.webview.postMessage(message), - new Promise(resolve => setTimeout(resolve, 5000, false)), + const scope = getLogScope(); + let timeout: ReturnType | undefined; + + // It looks like there is a bug where `postMessage` can sometimes just hang infinitely. Not sure why, but ensure we don't hang forever + const promise = Promise.race([ + this.webview.postMessage(message).then( + s => { + clearTimeout(timeout); + return s; + }, + ex => { + clearTimeout(timeout); + Logger.error(scope, ex); + debugger; + return false; + }, + ), + new Promise(resolve => { + timeout = setTimeout(() => { + debugger; + setLogScopeExit(scope, undefined, 'TIMEDOUT'); + resolve(false); + }, 5000); + }), ]); + + let success; + + if (this.isView()) { + // If we are in a view, show progress if we are waiting too long + const result = await pauseOnCancelOrTimeout(promise, undefined, 100); + if (result.paused) { + success = await window.withProgress({ location: { viewId: this.id } }, () => result.value); + } else { + success = result.value; + } + } else { + success = await promise; + } + return success; } @@ -593,7 +631,7 @@ export class WebviewController< } sendPendingIpcNotifications() { - if (this._pendingIpcNotifications.size === 0) return; + if (!this._ready || this._pendingIpcNotifications.size === 0) return; const ipcs = new Map(this._pendingIpcNotifications); this._pendingIpcNotifications.clear();