/// // Sandwiches a call to an asynchronous function between two other // (synchronous) functions. Intended for tracking the number of calls // inflight to a freedom provider, which may fail to resolve if the // provider's communication channel is destroyed while the call is // pending (this can happen even on a normal call to the provider's // close method). // Throws synchronously if the before function raises an error; the // returned promise rejects if the after function raises an error. export function wrap( wrapper:Wrapper, f:() => Promise) : Promise { try { wrapper.before(); } catch (e) { wrapper.after(); throw e; } return f().then((result:T) => { wrapper.after(); return result; }, (e:Error) => { wrapper.after(); throw e; }); } export class Wrapper { private counter_ = 0; private fulfillDestroyed_ :() => void; private rejectDestroyed_ :(e:Error) => void; private onceDestroyed_ = new Promise((F, R) => { this.fulfillDestroyed_ = F; this.rejectDestroyed_ = R; }); constructor(private destructor_ :() => void) {} public discard = () : void => { this.after(); } public onceDestroyed = () : Promise => { return this.onceDestroyed_; } public before = () : void => { this.counter_++; } public after = () : void => { this.counter_--; if (this.counter_ < 0) { try { this.destructor_(); this.fulfillDestroyed_(); } catch (e) { this.rejectDestroyed_(e); } } } }