bowling-analysis-system
Version:
A comprehensive system for analyzing bowling techniques using video processing and metrics calculation
214 lines (193 loc) • 5.63 kB
JavaScript
/**
* Base command class for implementing the command pattern
* All command handlers should extend this
* @class Command
*/
class Command {
/**
* Creates an instance of Command
* @param {Object} options - Command options
* @param {String} options.name - Command name
* @param {String} [options.description=''] - Command description
* @param {Object} [options.logger] - Logger instance
*/
constructor(options = {}) {
if (!options.name) {
throw new Error('Command name is required');
}
this.name = options.name;
this.description = options.description || '';
this.logger = options.logger || console;
this.executed = false;
this.successful = false;
this.result = null;
this.error = null;
this.startTime = null;
this.endTime = null;
}
/**
* Get command metadata
* @returns {Object} - Command metadata
*/
getMetadata() {
return {
name: this.name,
description: this.description,
executed: this.executed,
successful: this.successful,
duration: this.endTime && this.startTime ? this.endTime - this.startTime : null
};
}
/**
* Execute the command
* @param {Object} args - Command arguments
* @param {Object} [context={}] - Command context
* @returns {Promise<Object>} - Execution result
*/
async execute(args, context = {}) {
this.startTime = Date.now();
this.executed = true;
this.successful = false;
this.error = null;
try {
// Validate arguments first
await this.validate(args, context);
// Execute the command
this.result = await this._executeInternal(args, context);
this.successful = true;
return this.result;
} catch (error) {
this.error = error;
this.logger.error(`Error executing command '${this.name}':`, error);
// Try to roll back if needed
if (context.autoRollback !== false) {
try {
await this.rollback(args, context);
} catch (rollbackError) {
this.logger.error(`Error rolling back command '${this.name}':`, rollbackError);
}
}
throw error;
} finally {
this.endTime = Date.now();
}
}
/**
* Internal execution method to be implemented by subclasses
* @param {Object} args - Command arguments
* @param {Object} context - Command context
* @returns {Promise<Object>} - Execution result
* @protected
*/
async _executeInternal(args, context) {
throw new Error(`Command ${this.name} does not implement _executeInternal method`);
}
/**
* Validate command arguments
* @param {Object} args - Command arguments
* @param {Object} [context={}] - Validation context
* @returns {Promise<Boolean>} - Validation result
*/
async validate(args, context = {}) {
try {
return await this._validateInternal(args, context);
} catch (error) {
this.logger.error(`Validation error in command '${this.name}':`, error);
throw error;
}
}
/**
* Internal validation method to be implemented by subclasses
* @param {Object} args - Command arguments
* @param {Object} context - Validation context
* @returns {Promise<Boolean>} - Validation result
* @protected
*/
async _validateInternal(args, context) {
// Default implementation passes validation
return true;
}
/**
* Roll back command execution
* @param {Object} args - Command arguments
* @param {Object} [context={}] - Rollback context
* @returns {Promise<Boolean>} - Rollback result
*/
async rollback(args, context = {}) {
if (!this.executed) {
// Nothing to roll back
return true;
}
try {
return await this._rollbackInternal(args, context);
} catch (error) {
this.logger.error(`Rollback error in command '${this.name}':`, error);
throw error;
}
}
/**
* Internal rollback method to be implemented by subclasses
* @param {Object} args - Command arguments
* @param {Object} context - Rollback context
* @returns {Promise<Boolean>} - Rollback result
* @protected
*/
async _rollbackInternal(args, context) {
// Default implementation does nothing
this.logger.warn(`Command '${this.name}' does not implement rollback`);
return true;
}
/**
* Get command help text
* @returns {String} - Help text
*/
getHelp() {
return `
Command: ${this.name}
${this.description}
This command has not provided custom help documentation.
`;
}
/**
* Get command result
* @returns {Object|null} - Command result or null if not executed
*/
getResult() {
return this.result;
}
/**
* Get command error
* @returns {Error|null} - Command error or null if successful
*/
getError() {
return this.error;
}
/**
* Check if command was successful
* @returns {Boolean} - Success indicator
*/
isSuccessful() {
return this.successful;
}
/**
* Check if command has been executed
* @returns {Boolean} - Execution indicator
*/
isExecuted() {
return this.executed;
}
/**
* Reset command state
* @returns {Command} - For method chaining
*/
reset() {
this.executed = false;
this.successful = false;
this.result = null;
this.error = null;
this.startTime = null;
this.endTime = null;
return this;
}
}
module.exports = Command;