All files / src/command command.ts

96% Statements 24/25
90% Branches 9/10
100% Functions 7/7
96% Lines 24/25

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123  1x   1x                   1x       1x       1x       1x       1x                                   1x             20x 20x 20x 20x                   21x 21x     21x 20x 20x 20x                                 640x 17x   623x               79x               74x               91x        
// tslint:disable-next-line:no-var-requires
const debug = require("debug").debug("Command");
 
import Client, {
    CommandAlreadyExecutedError,
} from "../client";
 
/**
 * The potential states that a command can have.
 * When a command is created, the state is "initial"
 * When the execution has started, the status is "running"
 * When the execution has finsihed, the status can be "succes" or "failed"
 */
export enum CommandStatus {
    /**
     * When a command is created, the state is "initial"
     */
    initial = "initial",
    /**
     * When the execution has started, the status is "running"
     */
    running = "running",
    /**
     * After successful  execution of the command, the status is "success"
     */
    success = "success",
    /**
     * After unsuccessfull execution of the command, the status is "failed"
     */
    failed = "failed",
}
 
/**
 * when the command has finished, the client can get the result of the command execution
 */
export interface CommandResultMetaData {
    errors: string[],
    messages: string[],
    timeElapsed: number,
}
 
/**
 * The command class represents a potential long running activity.
 * This activity has been wrapped into an object to ease the tracking of the processing state.
 * Create a command with  receiver information, execute the command and check the status and progress.
 * Check the result when finsished.
 */
export default abstract class Command {
    protected client: Client;
    protected status: CommandStatus;
    protected percentCompleted: number;
    protected resultMetaData: CommandResultMetaData;
 
    constructor(client: Client) {
        this.client = client;
        this.status = CommandStatus.initial;
        this.percentCompleted = 0;
        this.resultMetaData = { messages: [], errors: [], timeElapsed: 0 };
    }
 
    /**
     * final execute the command
     * @async
     * @final
     * @returns {Promise<void>}
     */
    public async execute(): Promise<void> {
        debug("execute Command = " + this.constructor.name, this.status);
        Iif (this.isFinished()) {
            throw new CommandAlreadyExecutedError("Error: Command has already been executed. Command = " + this.constructor.name);
        }
        if (this.status === CommandStatus.initial) {
            const startTime = new Date();
            await this.onExecute();
            this.resultMetaData.timeElapsed = new Date().getTime() - startTime.getTime();
        }
        // do nothing if already running
    }
 
    /**
     * execute the command
     * @async
     * @returns {Promise<void>}
     */
    protected abstract async onExecute(): Promise<void>;
 
    /**
     * returns true, if the command has been finished
     * @returns {boolean}
     */
    public isFinished(): boolean {
        if (this.status === CommandStatus.failed || this.status === CommandStatus.success) {
            return true;
        }
        return false;
    }
 
    /**
     * returns the status of the command
     * @returns {CommandStatus}
     */
    public getStatus(): CommandStatus {
        return this.status;
    }
 
    /**
     * returns the completion percentage of the command
     * @returns {number} percentage of completion
     */
    public getPercentCompleted(): number {
        return this.percentCompleted;
    }
 
    /**
     * returns the result meta data of the command
     * @returns {null|any} the result of the command
     */
    public getResultMetaData(): CommandResultMetaData {
        return this.resultMetaData;
    }
 
}