From 7054df94582b564953d176ee3f69c483abbf409c Mon Sep 17 00:00:00 2001 From: Ryan Cloherty Date: Fri, 1 Jan 2021 21:58:22 -0500 Subject: [PATCH 1/2] Prevent a complete crash when DemoRecordingHelper fails --- src/Main.ts | 4 ++-- src/services/DemoRecordingHelper.ts | 3 ++- src/utils/DemoNamingHelper.ts | 2 +- src/utils/SubscriberManager.ts | 4 ++-- src/utils/TimeoutPromise.ts | 7 +++++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Main.ts b/src/Main.ts index 6682d13..ed8c1b5 100644 --- a/src/Main.ts +++ b/src/Main.ts @@ -36,8 +36,8 @@ const waitForUserInputThenExit = () => { subscriberManager.subscribe(new ShowHelpMessageWhenAsked()); subscriberManager.subscribe(new DemoRecordingHelper()); subscriberManager.subscribe(new DemoPlaybackHelper()); - await subscriberManager.init() - subscriberManager.begin().then(); + await subscriberManager.init(); + await subscriberManager.begin(); })().catch(reason => { log.fatal(reason); log.fatal('Exited due to a fatal error. Please see above for details.'); diff --git a/src/services/DemoRecordingHelper.ts b/src/services/DemoRecordingHelper.ts index 1d28935..21035f8 100644 --- a/src/services/DemoRecordingHelper.ts +++ b/src/services/DemoRecordingHelper.ts @@ -54,7 +54,8 @@ export class DemoRecordingHelper implements ListenerService { await this.handleStartRecord(); } catch (e) { //It's okay to throw errors in this method because it's an expectation that SubscriberManager knows what to do. - throw e; + // throw e; + DemoRecordingHelper.log.error(e); } // The only other possible condition is DemoRecordingHelper.demoRecordingEndRegExp.test(consoleLine) being true. } else { diff --git a/src/utils/DemoNamingHelper.ts b/src/utils/DemoNamingHelper.ts index 06ea141..52622d5 100644 --- a/src/utils/DemoNamingHelper.ts +++ b/src/utils/DemoNamingHelper.ts @@ -47,7 +47,7 @@ export class DemoNamingHelper { } public static getMapName = async (excludePrefix: boolean): Promise => { - const mapLine = await SubscriberManagerFactory.getSubscriberManager().searchForValue('status', DemoNamingHelper.mapFromStatusRegExp, false); + const mapLine = await SubscriberManagerFactory.getSubscriberManager().searchForValue('status', DemoNamingHelper.mapFromStatusRegExp, false, 'to get the current map the player is on'); const mapName = DemoNamingHelper.mapFromStatusRegExp.exec(mapLine); if (excludePrefix) { //Attempt to remove the first underscore in the map name and everything before it diff --git a/src/utils/SubscriberManager.ts b/src/utils/SubscriberManager.ts index 6b06a4d..793e816 100644 --- a/src/utils/SubscriberManager.ts +++ b/src/utils/SubscriberManager.ts @@ -209,12 +209,12 @@ export class SubscriberManager { return new TimeoutPromise().timeoutPromise(deferred.promise, `Request for Cvar '${cvarName}'`, false); } - public searchForValue = (command: string | string[], regex: RegExp, isUserDecision: boolean) => { + public searchForValue = (command: string | string[], regex: RegExp, isUserDecision: boolean, additionalDetailsAboutRequest?: string) => { const deferred: pDefer.DeferredPromise = pDefer(); this.specialOutputGrabbers.push([regex, deferred]); this.sendMessage(command); this.valueListenersLog.debug(`Added a value grabber grabbing output from '${command}' to the grabber list.`); - return new TimeoutPromise().timeoutPromise(deferred.promise, `Request for response to command '${command}'`, isUserDecision); + return new TimeoutPromise().timeoutPromise(deferred.promise, `Request for response to command '${command}'`, isUserDecision, additionalDetailsAboutRequest); } public subscribe = (listener: ListenerService) => { diff --git a/src/utils/TimeoutPromise.ts b/src/utils/TimeoutPromise.ts index d574847..7f64c4e 100644 --- a/src/utils/TimeoutPromise.ts +++ b/src/utils/TimeoutPromise.ts @@ -10,9 +10,12 @@ export class TimeoutPromise { * @param promise a promise to add a timeout to * @param descriptiveTaskName some name that will make sense to someone when they're trying to figure out the specific promise that failed and what it was doing * @param isUserDecision whether or not this promise is for a user's decision, in which case the promise should wait console_user_input_wait_time seconds (per config.ini) + * @param additionalDetailsAboutRequest provides additional context for why this request was made. For example, 'to get the name of the current map' * @returns a promise that will be rejected after config.internals.console_output_promise_wait_time milliseconds but won't be rejected if the provided promise resolves or is rejected before then */ - public timeoutPromise = (promise: Promise, descriptiveTaskName: string, isUserDecision: boolean): Promise => { + public timeoutPromise = (promise: Promise, descriptiveTaskName: string, isUserDecision: boolean, additionalDetailsAboutRequest?: string): Promise => { + // Create the error here to not mess up the stacktrace + let err = Error(`${descriptiveTaskName} timed out in ${this.consolePromiseTimeoutMs}ms.${additionalDetailsAboutRequest ? ` The purpose of this request was ${additionalDetailsAboutRequest}.` : ''}`); // Create a promise that rejects in milliseconds let timeout = new Promise((resolve, reject) => { let id = setTimeout(() => { @@ -20,7 +23,7 @@ export class TimeoutPromise { if (isUserDecision) { reject(new UserDecisionTimeoutException(descriptiveTaskName, this.consoleUserInputPromiseTimeoutMs)); } else { - reject(Error(`${descriptiveTaskName} timed out in ${this.consolePromiseTimeoutMs}ms.`)); + reject(err); } }, isUserDecision ? this.consoleUserInputPromiseTimeoutMs : this.consolePromiseTimeoutMs); }) From 91ab7c436a72c19642f12c462d5d7181a156c2bc Mon Sep 17 00:00:00 2001 From: Ryan Cloherty Date: Fri, 1 Jan 2021 22:04:53 -0500 Subject: [PATCH 2/2] Add a message to convey what just happened to the user (who will be using the console at that moment) --- src/services/DemoRecordingHelper.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/services/DemoRecordingHelper.ts b/src/services/DemoRecordingHelper.ts index 21035f8..8212125 100644 --- a/src/services/DemoRecordingHelper.ts +++ b/src/services/DemoRecordingHelper.ts @@ -56,6 +56,7 @@ export class DemoRecordingHelper implements ListenerService { //It's okay to throw errors in this method because it's an expectation that SubscriberManager knows what to do. // throw e; DemoRecordingHelper.log.error(e); + SubscriberManagerFactory.getSubscriberManager().sendMessage('echo Failed to start recording. Check the log file for details.'); } // The only other possible condition is DemoRecordingHelper.demoRecordingEndRegExp.test(consoleLine) being true. } else {