import async = require("async"); import { ISkeletosCommand } from "./ISkeletosCommand"; /** * An action is the place where you would place any business logic that needs to be done on the server. It is a * nice way to handle callback hell, where you would define all your data and flow up front in the action and have it * all wire up the callbacks automatically. * * An action is composed of multiple commands. The action can execute these commands in parallel, sequentially or * in some defined order. Under the covers, the action uses async.auto(..) to determine the pipeline of commands * that need to be executed. See getCommands(..). */ export declare abstract class AbstractAction { /** * The name of the action (same as name of class in development). * * @type {string} * @private */ protected _actionName: string; /** * Whether execution has been scheduled to be aborted. */ protected _executionAborted: boolean; /** * If this callback is specified, this it is used instead of the action's callback specified in the execute(..) * method. This allows another action to take over this action's execute callback. It is useful in situations when * another action wants to use this action as a command in it's own context. */ protected _onDoneOverride: async.ErrorCallback; protected _startTime: number; private _actionTimeOut; private _actionTimeOutID; private _startTimeOutCallback; /** * Creates a new action. * * If you have attributes/variables that you want to initialize, do it in the AbstractAction#doBeforeExecute(). * That function is a good chance to initialize variables instead of initializing variables in the constructor. * The problem with initializing variables in the constructor is that if this action is encapsulated within another * action, then you may not currently have all the data to initialize variables with. */ constructor(); /** * Use this to execute the action. * * !IMPORTANT! As a subclass, you should never override this function. Override AbstractAction#getCommands(..) * instead. */ execute(): void; /** * Allows actions to specific a timeout threshold after which the action will throw an error exception * * Part of the action chaining API, which allows actions to pass properties while calling other actions in a clean * and efficient way. */ setActionTimeout(actionTimeOut: number): AbstractAction; /** * Returns an Array of Functions or an action map used to feed into async.series or async.auto respectively. * * For example, you can either return this: * * * return [ * this.callFunctionSynchronously(this.command1), * this.callFunctionSynchronously(this.command2), * this.callFunctionAsynchronously(this.command3), * this.callAnotherAction(new AnotherAction()) * ]; * * * And command1 will be executed first, followed by command2, followed by command3, followed by AnotherAction. * * * Alternatively, you can run things in parallel using the following format: * * * { * Command1: this.callFunctionSynchronously(this.command1), * * Command2: ["Command1", this.callFunctionSynchronously(this.command2)], // depends on Command 1 * * Command3: ["Command1", this.callFunctionSynchronously(this.command3)], // depends on Command 1 also * * Command4: ["Command1", "Command2", this.callFunctionAsynchronously(this.command4)], // depends on command1 and * command2 * * Command5: this.callAnotherAction(new AnotherAction()) // does not depend on anything, executes another command * } * * * See: * http://caolan.github.io/async/docs.html#.auto */ protected abstract getCommands(): ISkeletosCommand[] | object; /** * This method gets called right before the action is executed. It is a good chance to initialize variables instead * of initializing variables in the constructor. The problem with initializing variables in the constructor is that * if this action is encapsulated within another action, then you may not currently have all the data to initialize * variables with. */ protected abstract doBeforeExecute(): void; /** * This method gets called right after the action is executed. It is a good chance to cleanup anything you * initialized. */ protected abstract doAfterExecute(err?: Error): void; /** * Shows an error notification. By default, outputs to console. * * @param err */ protected displayErrorNotification(err: Error): void; /** * Subclasses may want to override this to log a problem and/or display a translatable error message */ protected getTimeoutError(): Error; /** * Abort the action if it has not already been executed. Has no effect when called after the action is executed or * when it is currently executing commands. */ protected abortIfNotExecuted(): void; /** * When specifying the command map in getCommands(..), use this function to wrap another action within this action. * * @param action */ protected callAnotherAction(action: AbstractAction): ISkeletosCommand; /** * When specifying the command map in getCommands(..), use this function to call a function synchronously. * * That is, as soon as the supplied function exits, it will be taken as the end of that command and control will * be passed back to the async.auto(..) controller. * * @param fn * @param thisArg * @param params * @returns {function(async.ErrorCallback): any} */ protected callFunctionSynchronously(fn: Function, thisArg?: any, ...params: any[]): (prevResultsOrCallback: async.ErrorCallback | any, callback?: async.ErrorCallback) => any; /** * When specifying the command map in getCommands(..), use this function to call an function asynchronously. * * That is, the supplied function will be given a callback to call when it is done. This gives a chance for the * function to do some asynchronous processing. * * @param fn * @param thisArg * @returns {function((async.ErrorCallback|any), async.ErrorCallback=): any} */ protected callFunctionAsynchronously(fn: (callback: async.ErrorCallback) => any, thisArg?: any): ISkeletosCommand; /** * Wraps commands returned by this.getCommands() for any additional processing by framework classes. * * For example, you can use this to wrap each command with a progress meter. * * This method only exists to help you write reusable code in your application. Do *not* use this instead of * doBeforeExecute and doAfterExecute for business logic. * * @returns {ISkeletosCommand[] | object} */ protected wrapCommands(): ISkeletosCommand[] | object; private _wrapCommandsWithTimeout; private _startTimeout; private _turnOffTimeout; private doFinish; }