Files
meshcore-bot/modules/commands/base_command.py

93 lines
3.1 KiB
Python

#!/usr/bin/env python3
"""
Base command class for all MeshCore Bot commands
Provides common functionality and interface for command implementations
"""
from abc import ABC, abstractmethod
from typing import Optional, List, Dict, Any
from ..models import MeshMessage
class BaseCommand(ABC):
"""Base class for all bot commands - Plugin Interface"""
# Plugin metadata - to be overridden by subclasses
name: str = ""
keywords: List[str] = []
description: str = ""
aliases: List[str] = []
requires_dm: bool = False
cooldown_seconds: int = 0
category: str = "general"
def __init__(self, bot):
self.bot = bot
self.logger = bot.logger
self._last_execution_time = 0
@abstractmethod
async def execute(self, message: MeshMessage) -> bool:
"""Execute the command with the given message"""
pass
def get_help_text(self) -> str:
"""Get help text for this command"""
return self.description or "No help available for this command."
def can_execute(self, message: MeshMessage) -> bool:
"""Check if this command can be executed with the given message"""
# Check if command requires DM and message is not DM
if self.requires_dm and not message.is_dm:
return False
# Check cooldown
if self.cooldown_seconds > 0:
import time
current_time = time.time()
if (current_time - self._last_execution_time) < self.cooldown_seconds:
return False
return True
def get_metadata(self) -> Dict[str, Any]:
"""Get plugin metadata for discovery and registration"""
return {
'name': self.name,
'keywords': self.keywords,
'description': self.description,
'aliases': self.aliases,
'requires_dm': self.requires_dm,
'cooldown_seconds': self.cooldown_seconds,
'category': self.category,
'class_name': self.__class__.__name__,
'module_name': self.__class__.__module__
}
async def send_response(self, message: MeshMessage, content: str) -> bool:
"""Unified method for sending responses to users"""
try:
if message.is_dm:
return await self.bot.command_manager.send_dm(message.sender_id, content)
else:
return await self.bot.command_manager.send_channel_message(message.channel, content)
except Exception as e:
self.logger.error(f"Failed to send response: {e}")
return False
def _record_execution(self):
"""Record the execution time for cooldown tracking"""
import time
self._last_execution_time = time.time()
def get_remaining_cooldown(self) -> int:
"""Get remaining cooldown time in seconds"""
if self.cooldown_seconds <= 0:
return 0
import time
current_time = time.time()
elapsed = current_time - self._last_execution_time
remaining = self.cooldown_seconds - elapsed
return max(0, int(remaining))