Compare commits

...

5 Commits

8 changed files with 830 additions and 145 deletions

View File

@ -17,7 +17,7 @@ This was written with Python 3.11
```
dynamic-module-manager/
core_daemon/
├── core_daemon.py
├── daemon_cli.py
├── modules/
@ -63,8 +63,6 @@ See `modules/extra_commands.py` and `modules/http_service.py` for an example of
# Todo
- Maybe add ability to search for modules in directories set by a command
- Create module to add auth for the cli connections...
- Create module for module to module communication...
- Add error handling to core_daemon and daemon_cli...

View File

@ -1,109 +1,164 @@
import os
import time
import sys
import importlib
import socket
import json
import threading
import logging
import traceback
import hashlib
# Add the modules folder to the Python path
modules_path = os.path.join(os.path.dirname(__file__), 'modules')
sys.path.append(modules_path)
from hook_manager import hook_manager
from module_manager import ModuleManager
class ModuleManager:
def __init__(self):
self.loaded_modules = {}
self.extra_commands = {}
def load_module(self, module_name):
try:
# Try to import from the modules folder
module = importlib.import_module(f'modules.{module_name}')
self.loaded_modules[module_name] = module
if hasattr(module, 'initialize'):
module.initialize()
if hasattr(module, 'get_commands'):
new_commands = module.get_commands()
self.extra_commands.update(new_commands)
return True, f"Module '{module_name}' loaded and initialized successfully."
except ImportError as e:
return False, f"Error: Unable to load module '{module_name}'. {str(e)}"
def unload_module(self, module_name):
if module_name in self.loaded_modules:
module = self.loaded_modules[module_name]
if hasattr(module, 'shutdown'):
module.shutdown()
if hasattr(module, 'get_commands'):
commands_to_remove = module.get_commands().keys()
for cmd in commands_to_remove:
self.extra_commands.pop(cmd, None)
del self.loaded_modules[module_name]
return True, f"Module '{module_name}' unloaded and shut down."
return False, f"Module '{module_name}' is not loaded."
def list_modules(self):
return list(self.loaded_modules.keys())
def list_commands(self):
return list(self.extra_commands.keys())
def execute_command(self, command, args):
if command in self.extra_commands:
return True, self.extra_commands[command](args)
return False, "Command not found"
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
class CoreDaemon:
def __init__(self, host='localhost', port=9999):
def __init__(self, host='localhost', port=9999, module_dirs=None):
self.host = host
self.port = port
self.module_manager = ModuleManager()
self.module_dirs = module_dirs or ['modules']
self.module_manager = ModuleManager(self.module_dirs)
self.script_path = sys.argv[0]
self.initial_hash = self.calculate_file_hash(self.script_path)
self.hook_manager = hook_manager
def calculate_file_hash(self, file_path):
sha256_hash = hashlib.sha256()
with open(file_path, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest()
def start(self):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((self.host, self.port))
s.listen()
print(f"Core daemon listening on {self.host}:{self.port}")
while True:
conn, addr = s.accept()
threading.Thread(target=self.handle_client, args=(conn,)).start()
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((self.host, self.port))
s.listen()
logging.info(f"Core daemon listening on {self.host}:{self.port}")
while True:
conn, addr = s.accept()
threading.Thread(target=self.handle_client, args=(conn,)).start()
except Exception as e:
logging.error(f"Error starting core daemon: {str(e)}")
sys.exit(1)
def shutdown(self):
logging.info("Shutting down core daemon...")
return {'success': True, 'message': 'Core daemon is shutting down'}
def _delayed_shutdown(self):
time.sleep(1) # Give time for the response to be sent
os._exit(0)
def handle_client(self, conn):
with conn:
while True:
data = conn.recv(1024)
if not data:
break
command = json.loads(data.decode())
response = self.process_command(command)
conn.sendall(json.dumps(response).encode())
try:
data = conn.recv(1024)
if not data:
break
command = json.loads(data.decode())
response = self.process_command(command)
conn.sendall(json.dumps(response).encode())
except json.JSONDecodeError:
logging.error("Received invalid JSON data")
conn.sendall(json.dumps({'success': False, 'message': 'Invalid command format'}).encode())
except Exception as e:
logging.error(f"Error handling client request: {str(e)}")
conn.sendall(json.dumps({'success': False, 'message': 'Internal server error'}).encode())
def check_for_updates(self):
logging.info("Checking for updates...")
script_modified = False
current_script_hash = self.calculate_file_hash(self.script_path)
if current_script_hash != self.initial_hash:
script_modified = True
modified_modules = self.module_manager.check_modules_modified()
if script_modified or modified_modules:
message = "Updates detected:\n"
if script_modified:
message += "- Core script has been modified\n"
if modified_modules:
message += f"- Modified modules: {', '.join(modified_modules)}\n"
return True, message
else:
return False, "No updates detected."
def upgrade(self):
print("Upgrading core daemon...")
# Here you would typically download or copy the new version
# For this example, we'll just restart the script
os.execv(sys.executable, ['python'] + sys.argv)
update_available, message = self.check_for_updates()
if update_available:
logging.info(message)
# Here you would typically perform any necessary upgrade steps
# For this example, we'll just restart the script
os.execv(sys.executable, ['python'] + sys.argv)
return True, "Upgrade initiated. Restarting with new version."
else:
logging.info("No updates detected. Skipping upgrade.")
return False, "No upgrade needed. Current version is up to date."
def process_command(self, command):
action = command.get('action')
if action == 'load':
success, message = self.module_manager.load_module(command.get('module'))
elif action == 'unload':
success, message = self.module_manager.unload_module(command.get('module'))
elif action == 'list':
modules = self.module_manager.list_modules()
success, message = True, modules
elif action == 'execute':
success, message = self.module_manager.execute_command(command.get('command'), command.get('args'))
elif action == 'upgrade':
self.upgrade()
success, message = True, "Upgrade initiated"
elif action == 'list_commands':
commands = self.module_manager.list_commands()
success, message = True, commands
else:
success, message = False, "Unknown command"
return {'success': success, 'message': message}
# Execute pre-command hooks
pre_command_results = self.hook_manager.execute_hook('pre_command', command)
for result in pre_command_results:
if result is False:
return {'success': False, 'message': "Command rejected by pre-command hook"}
try:
if action == 'load':
success, message = self.module_manager.load_module(command.get('module'))
elif action == 'unload':
success, message = self.module_manager.unload_module(command.get('module'))
elif action == 'list':
success, modules = True, self.module_manager.list_modules()
message = modules
elif action == 'execute':
success, message = self.module_manager.execute_command(command.get('command'), command.get('args'))
elif action == 'upgrade':
success, message = self.upgrade()
elif action == 'list_commands':
success, commands = True, self.module_manager.list_commands()
message = commands
elif action == 'add_module_dir':
success, message = self.module_manager.add_module_dir(command.get('dir'))
elif action == 'shutdown':
response = self.shutdown()
# After sending the response, exit the program
threading.Thread(target=self._delayed_shutdown).start()
return response
else:
success, message = False, "Unknown command"
except Exception as e:
logging.error(f"Error processing command {action}: {str(e)}")
success, message = False, f"Error processing command: {str(e)}"
response = {'success': success, 'message': message}
# Execute post-command hooks
self.hook_manager.execute_hook('post_command', command, response)
return response
if __name__ == "__main__":
daemon = CoreDaemon()
daemon.start()
import argparse
parser = argparse.ArgumentParser(description="Core Daemon with dynamic module loading")
parser.add_argument('--host', default='localhost', help='Host to bind the daemon to')
parser.add_argument('--port', type=int, default=9999, help='Port to bind the daemon to')
parser.add_argument('--module-dirs', nargs='*', default=['modules'], help='Directories to load modules from')
args = parser.parse_args()
try:
daemon = CoreDaemon(host=args.host, port=args.port, module_dirs=args.module_dirs)
daemon.start()
except Exception as e:
logging.critical(f"Critical error in core daemon: {str(e)}")
logging.debug(traceback.format_exc())
sys.exit(1)

View File

@ -11,83 +11,84 @@ class ModuleShell(cmd.Cmd):
super().__init__()
self.host = host
self.port = port
self.update_commands()
self.session_id = None
def send_command(self, command):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((self.host, self.port))
s.sendall(json.dumps(command).encode())
return json.loads(s.recv(1024).decode())
def send_command(self, action, **kwargs):
command = {'action': action, **kwargs}
if self.session_id:
command['session_id'] = self.session_id
def update_commands(self):
response = self.send_command({'action': 'list_commands'})
if response['success']:
self.dynamic_commands = response['message']
else:
self.dynamic_commands = []
def default(self, line):
parts = line.split()
command = parts[0]
args = ' '.join(parts[1:])
response = self.send_command({'action': 'execute', 'command': command, 'args': args})
if response['success']:
print(response['message'])
else:
print(f"Error: {response['message']}")
def completenames(self, text, *ignored):
dotext = 'do_'+text
return [a[3:] for a in self.get_names() if a.startswith(dotext)] + \
[cmd for cmd in self.dynamic_commands if cmd.startswith(text)]
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((self.host, self.port))
s.sendall(json.dumps(command).encode())
data = s.recv(1024).decode()
return json.loads(data) if data else None
except Exception as e:
print(f"Error: {str(e)}")
return None
def do_load(self, arg):
"""Load a module: load <module_name>"""
response = self.send_command({'action': 'load', 'module': arg})
print(response['message'])
self.update_commands() # Update commands after loading a new module
response = self.send_command('load', module=arg)
if response:
print(response.get('message', 'Unknown response'))
def do_unload(self, arg):
"""Unload a module: unload <module_name>"""
response = self.send_command({'action': 'unload', 'module': arg})
print(response['message'])
self.update_commands() # Update commands after unloading a module
response = self.send_command('unload', module=arg)
if response:
print(response.get('message', 'Unknown response'))
def do_list(self, arg):
"""List all loaded modules"""
response = self.send_command({'action': 'list'})
modules = response['message']
if modules:
print("Loaded modules:")
for module in modules:
print(f"- {module}")
response = self.send_command('list')
if response and response.get('success'):
modules = response.get('message', [])
if modules:
print("Loaded modules:")
for module in modules:
print(f"- {module}")
else:
print("No modules are currently loaded.")
else:
print("No modules are currently loaded.")
def do_list_available(self, arg):
"""List available modules in the modules folder"""
modules_path = os.path.join(os.path.dirname(__file__), 'modules')
available_modules = [f[:-3] for f in os.listdir(modules_path) if f.endswith('.py') and not f.startswith('__')]
print("Available modules:")
for module in available_modules:
print(f"- {module}")
def complete_load(self, text, line, begidx, endidx):
modules_path = os.path.join(os.path.dirname(__file__), 'modules')
available_modules = [f[:-3] for f in os.listdir(modules_path) if f.endswith('.py') and not f.startswith('__')]
return [m for m in available_modules if m.startswith(text)]
print("Failed to retrieve module list.")
def do_execute(self, arg):
"""Execute a command: execute <command> [args]"""
parts = arg.split()
if not parts:
print("Error: No command specified.")
return
command = parts[0]
args = ' '.join(parts[1:])
response = self.send_command('execute', command=command, args=args)
if response:
print(response.get('message', 'Unknown response'))
def do_upgrade(self, arg):
"""Upgrade the core daemon"""
response = self.send_command({'action': 'upgrade'})
print(response['message'])
"""Upgrade the core daemon and modules"""
response = self.send_command('upgrade')
if response:
print(response.get('message', 'Unknown response'))
def do_exit(self, arg):
"""Exit the shell"""
print("Exiting...")
return True
def do_shutdown(self, arg):
"""Shutdown the core daemon"""
response = self.send_command('shutdown')
if response:
print(response.get('message', 'Unknown response'))
print("Core daemon is shutting down. Exiting CLI.")
return True
def default(self, line):
"""Handle unknown commands by trying to execute them"""
self.do_execute(line)
def main():
ModuleShell().cmdloop()

110
hook_manager.py Normal file
View File

@ -0,0 +1,110 @@
"""
hook_manager.py
This module provides the HookManager class which allows for the registration,
unregistration, and execution of hooks. Hooks are functions that can be executed
at specific points in the program flow, such as before or after commands or module
loading/unloading.
Classes:
HookManager: Manages the registration, unregistration, and execution of hooks.
Variables:
hook_manager (HookManager): An instance of HookManager for global usage.
"""
import logging
from typing import Callable, List, Dict
class HookManager:
"""
A manager for handling hooks that can be registered, unregistered, and executed
at various points in a program's flow.
Attributes:
hooks (dict): A dictionary containing lists of functions for each hook point.
"""
def __init__(self):
"""
Initializes a new instance of the HookManager class with predefined hook points.
"""
self.hooks: Dict[str, List[Callable]] = {
'pre_command': [],
'post_command': [],
'pre_module_load': [],
'post_module_load': [],
'pre_module_unload': [],
'post_module_unload': [],
}
logging.info("HookManager initialized with hooks: %s", list(self.hooks.keys()))
def register_hook(self, hook_name: str, func: Callable):
"""
Registers a function to a specified hook.
Args:
hook_name (str): The name of the hook to register the function to.
func (function): The function to register.
Raises:
ValueError: If the specified hook name is not recognized.
"""
if hook_name in self.hooks:
self.hooks[hook_name].append(func)
logging.info("Registered function %s to hook %s", func.__name__, hook_name)
else:
logging.error("Attempted to register to unknown hook: %s", hook_name)
raise ValueError(f"Unknown hook: {hook_name}")
def unregister_hook(self, hook_name: str, func: Callable):
"""
Unregisters a function from a specified hook.
Args:
hook_name (str): The name of the hook to unregister the function from.
func (function): The function to unregister.
Raises:
ValueError: If the specified hook name is not recognized.
"""
if hook_name in self.hooks:
if func in self.hooks[hook_name]:
self.hooks[hook_name].remove(func)
logging.info("Unregistered function %s from hook %s", func.__name__, hook_name)
else:
logging.warning("Function %s not found in hook %s", func.__name__, hook_name)
else:
logging.error("Attempted to unregister from unknown hook: %s", hook_name)
raise ValueError(f"Unknown hook: {hook_name}")
def execute_hook(self, hook_name: str, *args, **kwargs) -> List:
"""
Executes all functions registered to a specified hook with the provided arguments.
Args:
hook_name (str): The name of the hook to execute the functions for.
*args: Variable length argument list to pass to the hook functions.
**kwargs: Arbitrary keyword arguments to pass to the hook functions.
Returns:
list: A list of results from each hook function executed.
Raises:
ValueError: If the specified hook name is not recognized.
"""
if hook_name not in self.hooks:
logging.error("Attempted to execute unknown hook: %s", hook_name)
raise ValueError(f"Unknown hook: {hook_name}")
results = []
for func in self.hooks[hook_name]:
try:
result = func(*args, **kwargs)
results.append(result)
logging.info("Executed function %s in hook %s", func.__name__, hook_name)
except Exception as e:
logging.error("Error executing function %s in hook %s: %s", func.__name__, hook_name, str(e))
return results
hook_manager = HookManager()

252
module_manager.py Normal file
View File

@ -0,0 +1,252 @@
"""
module_manager.py
This module provides the ModuleManager class which allows for the management
of dynamically loadable modules. The ModuleManager supports loading, unloading,
and execution of modules, as well as handling module-specific commands and hooks.
Classes:
ModuleManager: Manages loading, unloading, and executing modules and their commands.
Variables:
hook_manager (HookManager): An instance of HookManager for managing hooks.
"""
import os
import sys
import importlib
import logging
import hashlib
from hook_manager import HookManager
hook_manager = HookManager()
class ModuleManager:
"""
A manager for handling dynamically loadable modules, including loading, unloading,
and executing module-specific commands and hooks.
Attributes:
module_dirs (list): A list of directories to search for modules.
loaded_modules (dict): A dictionary of loaded modules.
extra_commands (dict): A dictionary of additional commands provided by modules.
module_hashes (dict): A dictionary storing file paths and their hashes.
hook_manager (HookManager): An instance of HookManager for managing hooks.
"""
def __init__(self, module_dirs):
"""
Initializes a new instance of the ModuleManager class.
Args:
module_dirs (list): A list of directories to search for modules.
"""
self.module_dirs = module_dirs
self.loaded_modules = {}
self.extra_commands = {}
self.module_hashes = {} # store file paths and hashes
self._update_sys_path()
self.hook_manager = hook_manager # Use the global hook_manager!
def _update_sys_path(self):
"""
Updates the system path to include the directories in module_dirs.
"""
for dir in self.module_dirs:
full_path = os.path.abspath(dir)
if full_path not in sys.path:
sys.path.append(full_path)
logging.info(f"Added {full_path} to sys.path")
def add_module_dir(self, new_dir):
"""
Adds a new directory to the list of module directories and updates the system path.
Args:
new_dir (str): The new directory to add.
Returns:
tuple: A tuple containing a boolean indicating success and a message.
"""
try:
full_path = os.path.abspath(new_dir)
if full_path not in self.module_dirs:
self.module_dirs.append(full_path)
self._update_sys_path()
return True, f"Added module directory: {full_path}"
return False, f"Module directory already exists: {full_path}"
except Exception as e:
logging.error(f"Error adding module directory: {str(e)}")
return False, f"Error adding module directory: {str(e)}"
def calculate_file_hash(self, file_path):
"""
Calculates the SHA-256 hash of a file.
Args:
file_path (str): The path to the file.
Returns:
str: The SHA-256 hash of the file.
"""
sha256_hash = hashlib.sha256()
try:
with open(file_path, "rb") as f:
for byte_block in iter(lambda: f.read(4096), b""):
sha256_hash.update(byte_block)
return sha256_hash.hexdigest()
except FileNotFoundError:
logging.error(f"File not found: {file_path}")
return None
except Exception as e:
logging.error(f"Error calculating hash for file '{file_path}': {str(e)}")
return None
def load_module(self, module_name):
"""
Loads a module by name, initializing it and registering its commands and hooks.
Args:
module_name (str): The name of the module to load.
Returns:
tuple: A tuple containing a boolean indicating success and a message.
"""
self.hook_manager.execute_hook('pre_module_load', module_name)
for dir in self.module_dirs:
try:
module_path = os.path.join(dir, f"{module_name}.py")
if not os.path.exists(module_path):
continue
module = importlib.import_module(f'{os.path.basename(dir)}.{module_name}')
self.loaded_modules[module_name] = module
# Calculate and store the hash of the module file
module_hash = self.calculate_file_hash(module_path)
if module_hash:
self.module_hashes[module_path] = module_hash
self._initialize_module(module)
self.hook_manager.execute_hook('post_module_load', module_name)
return True, f"Module '{module_name}' loaded and initialized successfully from {dir}."
except ImportError as e:
logging.error(f"ImportError for module '{module_name}' from {dir}: {str(e)}")
continue
except Exception as e:
logging.error(f"Error loading module '{module_name}' from {dir}: {str(e)}")
return False, f"Error loading module '{module_name}' from {dir}: {str(e)}"
return False, f"Error: Unable to load module '{module_name}' from any of the module directories."
def _initialize_module(self, module):
"""
Initializes a loaded module by calling its initialize method, registering commands, and registering hooks.
Args:
module: The loaded module.
"""
if hasattr(module, 'initialize'):
module.initialize()
if hasattr(module, 'get_commands'):
new_commands = module.get_commands()
self.extra_commands.update(new_commands)
if hasattr(module, 'register_hooks'):
module.register_hooks(self.hook_manager)
def unload_module(self, module_name):
"""
Unloads a module by name, shutting it down and removing its commands and hooks.
Args:
module_name (str): The name of the module to unload.
Returns:
tuple: A tuple containing a boolean indicating success and a message.
"""
self.hook_manager.execute_hook('pre_module_unload', module_name)
if module_name in self.loaded_modules:
try:
module = self.loaded_modules[module_name]
self._shutdown_module(module)
self.hook_manager.execute_hook('post_module_unload', module_name)
# Remove the module's hash from our tracking
module_path = module.__file__
self.module_hashes.pop(module_path, None)
del self.loaded_modules[module_name]
logging.info(f"Module '{module_name}' unloaded successfully.")
return True, f"Module '{module_name}' unloaded and shut down."
except Exception as e:
logging.error(f"Error unloading module '{module_name}': {str(e)}")
return False, f"Error unloading module '{module_name}': {str(e)}"
return False, f"Module '{module_name}' is not loaded."
def _shutdown_module(self, module):
"""
Shuts down a loaded module by calling its shutdown method and removing its commands and hooks.
Args:
module: The loaded module.
"""
if hasattr(module, 'shutdown'):
module.shutdown()
if hasattr(module, 'get_commands'):
commands_to_remove = module.get_commands().keys()
for cmd in commands_to_remove:
self.extra_commands.pop(cmd, None)
if hasattr(module, 'unregister_hooks'):
module.unregister_hooks(self.hook_manager)
def list_modules(self):
"""
Lists all currently loaded modules.
Returns:
list: A list of names of loaded modules.
"""
return list(self.loaded_modules.keys())
def list_commands(self):
"""
Lists all commands provided by the loaded modules.
Returns:
list: A list of command names.
"""
return list(self.extra_commands.keys())
def execute_command(self, command, args):
"""
Executes a command provided by a loaded module.
Args:
command (str): The name of the command to execute.
args (list): The arguments to pass to the command.
Returns:
tuple: A tuple containing a boolean indicating success and the command result or an error message.
"""
if command in self.extra_commands:
try:
result = self.extra_commands[command](args)
return True, result
except Exception as e:
logging.error(f"Error executing command '{command}': {str(e)}")
return False, f"Error executing command '{command}': {str(e)}"
return False, f"Command '{command}' not found"
def check_modules_modified(self):
"""
Checks if any loaded modules have been modified on disk by comparing file hashes.
Returns:
list: A list of names of modified modules.
"""
modified_modules = []
for module_path, stored_hash in self.module_hashes.items():
current_hash = self.calculate_file_hash(module_path)
if current_hash and current_hash != stored_hash:
module_name = os.path.splitext(os.path.basename(module_path))[0]
modified_modules.append(module_name)
return modified_modules

95
modules/message_bus.py Normal file
View File

@ -0,0 +1,95 @@
import queue
import threading
class MessageBus:
def __init__(self):
self.queues = {}
self.lock = threading.Lock()
def create_queue(self, queue_name):
with self.lock:
if queue_name not in self.queues:
self.queues[queue_name] = queue.Queue()
return True
return False
def delete_queue(self, queue_name):
with self.lock:
if queue_name in self.queues:
del self.queues[queue_name]
return True
return False
def send_message(self, queue_name, message):
with self.lock:
if queue_name in self.queues:
self.queues[queue_name].put(message)
return True
return False
def receive_message(self, queue_name, timeout=None):
with self.lock:
if queue_name in self.queues:
try:
return self.queues[queue_name].get(timeout=timeout)
except queue.Empty:
return None
return None
message_bus = MessageBus()
def do_create_queue(args):
"""Create a new message queue: create_queue <queue_name>"""
queue_name = args.strip()
if message_bus.create_queue(queue_name):
return f"Queue '{queue_name}' created successfully"
else:
return f"Queue '{queue_name}' already exists"
def do_delete_queue(args):
"""Delete a message queue: delete_queue <queue_name>"""
queue_name = args.strip()
if message_bus.delete_queue(queue_name):
return f"Queue '{queue_name}' deleted successfully"
else:
return f"Queue '{queue_name}' does not exist"
def do_send_message(args):
"""Send a message to a queue: send_message <queue_name> <message>"""
parts = args.split(maxsplit=1)
if len(parts) != 2:
return "Invalid arguments. Usage: send_message <queue_name> <message>"
queue_name, message = parts
if message_bus.send_message(queue_name, message):
return f"Message sent to queue '{queue_name}'"
else:
return f"Queue '{queue_name}' does not exist"
def do_receive_message(args):
"""Receive a message from a queue: receive_message <queue_name> [timeout]"""
parts = args.split()
if len(parts) not in (1, 2):
return "Invalid arguments. Usage: receive_message <queue_name> [timeout]"
queue_name = parts[0]
timeout = float(parts[1]) if len(parts) == 2 else None
message = message_bus.receive_message(queue_name, timeout)
if message is not None:
return f"Received message from queue '{queue_name}': {message}"
else:
return f"No message available in queue '{queue_name}'"
commands = {
'create_queue': do_create_queue,
'delete_queue': do_delete_queue,
'send_message': do_send_message,
'receive_message': do_receive_message,
}
def get_commands():
return commands
def initialize():
print("Message bus module initialized")
def shutdown():
print("Message bus module shut down")

View File

@ -0,0 +1,49 @@
message_bus = None
def set_message_bus(bus):
global message_bus
message_bus = bus
def do_something_and_notify(args):
# Do something...
result = "Operation completed"
# Notify another module if message bus is available
if message_bus:
message_bus.send_message('notifications', f"Operation result: {result}")
return "Operation completed and notification sent"
else:
return "Operation completed (notification not sent, message bus not available)"
def do_check_notifications(args):
if not message_bus:
return "Message bus not available"
message = message_bus.receive_message('notifications', timeout=1)
if message:
return f"Received notification: {message}"
else:
return "No new notifications"
commands = {
'do_something': do_something_and_notify,
'check_notifications': do_check_notifications,
}
def get_commands():
return commands
def initialize():
global message_bus
try:
from message_bus import message_bus as mb
message_bus = mb
message_bus.create_queue('notifications')
print("Example module initialized with message bus")
except ImportError:
print("Example module initialized without message bus")
def shutdown():
if message_bus:
message_bus.delete_queue('notifications')
print("Example module shut down")

125
modules/user_auth.py Normal file
View File

@ -0,0 +1,125 @@
import hashlib
import uuid
import time
class UserAuth:
def __init__(self):
self.users = {} # Store users as {username: {password_hash, salt}}
self.sessions = {} # Store sessions as {session_id: {username, expiry}}
self.session_duration = 3600 # 1 hour
def hash_password(self, password, salt=None):
if salt is None:
salt = uuid.uuid4().hex
return hashlib.sha256((password + salt).encode()).hexdigest(), salt
def register_user(self, username, password):
if username in self.users:
return False, "User already exists"
password_hash, salt = self.hash_password(password)
self.users[username] = {"password_hash": password_hash, "salt": salt}
return True, "User registered successfully"
def authenticate(self, username, password):
if username not in self.users:
return False, "User not found"
user = self.users[username]
password_hash, _ = self.hash_password(password, user["salt"])
if password_hash == user["password_hash"]:
session_id = uuid.uuid4().hex
expiry = time.time() + self.session_duration
self.sessions[session_id] = {"username": username, "expiry": expiry}
return True, session_id
return False, "Invalid password"
def authenticate_request(self, session_id, action):
if action in ['register', 'login']: # These actions don't require authentication
return True, None
success, result = self.validate_session(session_id)
if not success:
return False, "Authentication required"
return True, result # result here is the username
def validate_session(self, session_id):
if session_id not in self.sessions:
return False, "Invalid session"
session = self.sessions[session_id]
if time.time() > session["expiry"]:
del self.sessions[session_id]
return False, "Session expired"
return True, session["username"]
def logout(self, session_id):
if session_id in self.sessions:
del self.sessions[session_id]
return True, "Logged out successfully"
return False, "Invalid session"
user_auth = UserAuth()
def do_register(args):
"""Register a new user: register <username> <password>"""
try:
username, password = args.split()
success, message = user_auth.register_user(username, password)
return message
except ValueError:
return "Invalid arguments. Usage: register <username> <password>"
def do_login(args):
"""Login a user: login <username> <password>"""
try:
username, password = args.split()
success, result = user_auth.authenticate(username, password)
if success:
return f"Login successful. Session ID: {result}"
return result
except ValueError:
return "Invalid arguments. Usage: login <username> <password>"
def do_validate(args):
"""Validate a session: validate <session_id>"""
success, result = user_auth.validate_session(args)
if success:
return f"Valid session for user: {result}"
return result
def do_logout(args):
"""Logout a user: logout <session_id>"""
success, message = user_auth.logout(args)
return message
def auth_pre_command_hook(command):
action = command.get('action')
session_id = command.get('session_id')
if action in ['register', 'login']:
return True
success, result = user_auth.validate_session(session_id)
if not success:
return False
return True
commands = {
'register': do_register,
'login': do_login,
'validate': do_validate,
'logout': do_logout,
}
def get_commands():
return commands
def initialize():
print("User authentication module initialized")
def shutdown():
print("User authentication module shut down")
def register_hooks(hook_manager):
hook_manager.register_hook('pre_command', auth_pre_command_hook)
def unregister_hooks(hook_manager):
hook_manager.unregister_hook('pre_command', auth_pre_command_hook)