From 71803350eae9660f41fc8b61ddf63fbd54ff7f52 Mon Sep 17 00:00:00 2001 From: Aether Date: Mon, 23 Feb 2026 17:23:05 +0000 Subject: [PATCH] Add comprehensive application redesign draft and full API documentation - Application redesign with clean architecture, v3.0 roadmap - Complete API documentation with examples - Plugin system redesign - Security architecture - Implementation roadmap --- docs/EU_UTILITY_API_DOCUMENTATION.md | 894 +++++++++++++++++++++ docs/redesign/EU_UTILITY_REDESIGN_DRAFT.md | 713 ++++++++++++++++ 2 files changed, 1607 insertions(+) create mode 100644 docs/EU_UTILITY_API_DOCUMENTATION.md create mode 100644 docs/redesign/EU_UTILITY_REDESIGN_DRAFT.md diff --git a/docs/EU_UTILITY_API_DOCUMENTATION.md b/docs/EU_UTILITY_API_DOCUMENTATION.md new file mode 100644 index 0000000..52906d6 --- /dev/null +++ b/docs/EU_UTILITY_API_DOCUMENTATION.md @@ -0,0 +1,894 @@ +# EU-Utility Complete API Documentation +## Version 2.1.0 + +--- + +## 📖 Table of Contents + +1. [Overview](#overview) +2. [Core APIs](#core-apis) +3. [Plugin API](#plugin-api) +4. [Widget API](#widget-api) +5. [External API](#external-api) +6. [Nexus API Integration](#nexus-api-integration) +7. [Event System](#event-system) +8. [Data Storage](#data-storage) +9. [Security](#security) +10. [Examples](#examples) + +--- + +## Overview + +EU-Utility provides a three-tier API architecture: + +| API | Purpose | Audience | +|-----|---------|----------| +| **PluginAPI** | Access core services | Plugin developers | +| **WidgetAPI** | Create overlay widgets | Widget developers | +| **ExternalAPI** | Third-party integrations | External apps | + +--- + +## Core APIs + +### Service Locator + +```python +from core.api import get_api, get_widget_api, get_external_api + +# Get APIs +plugin_api = get_api() +widget_api = get_widget_api() +external_api = get_external_api() +``` + +### Available Services + +| Service | Method | Description | +|---------|--------|-------------| +| Log Reader | `get_log_reader()` | Read game chat logs | +| Window Manager | `get_window_manager()` | Control EU window | +| OCR | `get_ocr_service()` | Text recognition | +| Screenshot | `get_screenshot_service()` | Screen capture | +| Nexus API | `get_nexus_api()` | Item database | +| HTTP Client | `get_http_client()` | Web requests | +| Audio | `get_audio_manager()` | Sound playback | +| Notifications | `get_notification_manager()` | Toast notifications | +| Clipboard | `get_clipboard_manager()` | Copy/paste | +| Event Bus | `get_event_bus()` | Pub/sub events | +| Data Store | `get_data_store()` | Key-value storage | +| Task Manager | `get_task_manager()` | Background tasks | + +--- + +## Plugin API + +### Initialization + +```python +from plugins.base_plugin import BasePlugin +from core.api import get_api + +class MyPlugin(BasePlugin): + def initialize(self): + """Called when plugin loads.""" + self.api = get_api() + self.log_info(f"{self.name} initialized") +``` + +### Log Reader + +```python +# Read last N log lines +lines = api.read_log_lines(100) + +# Read since timestamp +from datetime import datetime, timedelta +recent = api.read_log_since(datetime.now() - timedelta(minutes=5)) + +# Read filtered by pattern +loot_lines = api.read_log_filtered(pattern="Loot:.*(Uber|Jackpot)") +``` + +**Returns:** `List[str]` - Log lines + +### Window Manager + +```python +# Get EU window info +window = api.get_eu_window() +if window: + print(f"Position: ({window['x']}, {window['y']})") + print(f"Size: {window['width']}x{window['height']}") + print(f"Focused: {window['is_focused']}") + +# Check if EU is focused +if api.is_eu_focused(): + api.play_sound("alert.wav") + +# Bring EU to front +api.bring_eu_to_front() + +# Get window screenshot +screenshot = api.capture_eu_window() +``` + +**Window Info Schema:** +```json +{ + "x": 100, + "y": 100, + "width": 1920, + "height": 1080, + "is_focused": true, + "title": "Entropia Universe" +} +``` + +### OCR Service + +```python +# Check if OCR is available +if api.ocr_available(): + # Read text from screen region + text = api.recognize_text((100, 100, 200, 50)) + print(f"Found: {text}") + + # Read from EU window specifically + eu_text = api.recognize_eu_region("chat") + + # Read with specific engine + text = api.recognize_text( + region=(100, 100, 200, 50), + engine="easyocr" # or "tesseract", "paddleocr" + ) +``` + +**Parameters:** +- `region`: Tuple `(x, y, width, height)` +- `engine`: Optional OCR engine name + +**Returns:** `str` - Recognized text + +### Screenshot + +```python +# Capture full screen +img = api.capture_screen() + +# Capture region +img = api.capture_screen((0, 0, 1920, 1080)) + +# Save to file +img = api.capture_screen(save_path="screenshot.png") + +# Capture EU window +img = api.capture_eu_window() + +# Check availability +if api.screenshot_available(): + img = api.capture_screen() +``` + +**Returns:** `PIL.Image` - Screenshot image + +### Nexus API (Item Database) + +```python +# Search items +items = api.search_items( + query="omegaton", + entity_type="weapons", # or "items", "mobs", "all" + limit=5 +) + +for item in items: + print(f"{item['name']}: {item['value']} PED") + +# Get item details +details = api.get_item_details(item_id=12345) + +# Get market data +market = api.get_market_data(item_id=12345) +print(f"Current: {market['current_price']} PED") +print(f"Markup: {market['markup']}%") + +# Get blueprint info +bp = api.get_blueprint_details(bp_id=67890) +``` + +**Search Response Schema:** +```json +[ + { + "id": "12345", + "name": "Omegaton M83 Predator", + "type": "weapon", + "category": "Rifle", + "value": 123.45, + "markup": 125.5, + "icon_url": "https://..." + } +] +``` + +### HTTP Client + +```python +# GET request +result = api.http_get( + url="https://api.example.com/data", + params={"key": "value"}, + cache=True, # Cache response + ttl=3600 # Cache for 1 hour +) + +if result['success']: + data = result['data'] + print(f"Status: {result['status_code']}") + +# POST request +result = api.http_post( + url="https://api.example.com/save", + data={"key": "value"}, + headers={"Authorization": "Bearer token"} +) + +# With retry +result = api.http_get( + url="https://api.example.com/data", + retry=3, + backoff=True +) +``` + +**Response Schema:** +```json +{ + "success": true, + "data": {...}, + "status_code": 200, + "cached": false, + "error": null +} +``` + +### Audio + +```python +# Play sound file +api.play_sound( + path="assets/sounds/alert.wav", + volume=0.7 # 0.0 to 1.0 +) + +# Play built-in sound +api.play_sound("success") +api.play_sound("error") +api.play_sound("notification") + +# Simple beep +api.beep() + +# Check availability +if api.audio_available(): + api.play_sound("alert.wav") +``` + +### Notifications + +```python +# Show toast notification +api.show_notification( + title="Loot Alert", + message="Found something valuable!", + duration=3000, # milliseconds + sound=True, + icon="loot" # or path to icon +) + +# Show with actions +api.show_notification( + title="Mission Complete", + message="You finished the mission!", + actions=[ + {"label": "View", "callback": on_view}, + {"label": "Dismiss", "callback": on_dismiss} + ] +) + +# Update existing notification +notification_id = api.show_notification(...) +api.update_notification( + notification_id, + message="Updated message" +) +``` + +### Clipboard + +```python +# Copy to clipboard +api.copy_to_clipboard("TT: 100 PED") + +# Copy formatted +api.copy_to_clipboard( + text="Item: Omegaton", + rich_text="Item: Omegaton" +) + +# Paste from clipboard +text = api.paste_from_clipboard() + +# Check if has content +if api.clipboard_has_content(): + text = api.paste_from_clipboard() +``` + +### Event Bus + +```python +# Subscribe to events +def on_loot(event): + print(f"Loot: {event.data}") + +sub_id = api.subscribe( + event_type="loot.received", + handler=on_loot +) + +# Subscribe with filter +def on_valuable_loot(event): + if event.data['value'] > 100: + print(f"Uber loot: {event.data}") + +api.subscribe( + event_type="loot.received", + handler=on_valuable_loot, + filter=lambda e: e.data.get('value', 0) > 100 +) + +# Subscribe once +api.subscribe_once( + event_type="skill.gain", + handler=on_skill_gain +) + +# Unsubscribe +api.unsubscribe(sub_id) + +# Publish event +api.publish( + event_type="my_plugin.event", + data={"key": "value"} +) + +# Typed events +from core.event_bus import LootEvent + +def on_loot_typed(event: LootEvent): + print(f"From {event.mob_name}: {event.total_tt}") + +api.subscribe_typed(LootEvent, on_loot_typed) +``` + +**Event Types:** +- `loot.received` - Loot event +- `skill.gain` - Skill increase +- `global.recorded` - Global/HOF +- `mission.complete` - Mission finished +- `chat.message` - Chat message +- `window.focus` - Window focus change + +### Data Store + +```python +# Save data +api.save_data( + key="my_plugin.settings", + data={"theme": "dark", "volume": 0.8} +) + +# Load data +settings = api.load_data( + key="my_plugin.settings", + default={"theme": "light", "volume": 1.0} +) + +# Delete data +api.delete_data("my_plugin.settings") + +# List keys +keys = api.list_data_keys(pattern="my_plugin.*") + +# Check exists +if api.has_data("my_plugin.settings"): + settings = api.load_data("my_plugin.settings") +``` + +### Tasks + +```python +# Run async task +task_id = api.run_task( + func=fetch_market_data, + args=(item_id,), + callback=on_data_received, + error_callback=on_error +) + +# Cancel task +api.cancel_task(task_id) + +# Schedule task +api.schedule_task( + func=check_prices, + interval=60, # seconds + repeat=True +) + +# Run in background +api.run_in_background( + func=heavy_computation, + priority="low" # "high", "normal", "low" +) +``` + +--- + +## Widget API + +### Creating Widgets + +```python +from core.api import get_widget_api + +widget_api = get_widget_api() + +# Create overlay widget +widget = widget_api.create_widget( + name="Loot Widget", + size=(300, 200), + position=(100, 100), + draggable=True, + resizable=True, + always_on_top=True +) + +# Set content +widget.set_content(my_qwidget) + +# Show/hide +widget.show() +widget.hide() + +# Update position +widget.move(200, 200) +widget.resize(400, 300) + +# Close +widget.close() +``` + +### Widget Properties + +```python +# Transparency +widget.set_opacity(0.8) # 0.0 to 1.0 + +# Click-through +widget.set_click_through(True) + +# Snap to edges +widget.set_snap_to_edges(True, margin=10) + +# Auto-hide +widget.set_auto_hide( + enabled=True, + hide_delay=3000, + show_on_hover=True +) +``` + +--- + +## External API + +### REST Endpoints + +```python +from core.api import get_external_api + +api = get_external_api() + +# Start HTTP server +api.start_server(port=8080) + +# Register endpoint +@api.endpoint("/loot/recent", methods=["GET"]) +def get_recent_loot(): + return {"loot": [...]} + +# With authentication +@api.endpoint("/settings", methods=["GET", "POST"], auth_required=True) +def settings(): + if request.method == "POST": + api.save_settings(request.json) + return api.load_settings() +``` + +### WebSocket + +```python +# WebSocket endpoint +@api.websocket("/events") +async def events(websocket): + async for message in websocket: + await websocket.send({"echo": message}) +``` + +--- + +## Nexus API Integration + +### Entity Types + +```python +from core.nexus_api import EntityType + +# Available types +EntityType.ITEM # Items +EntityType.WEAPON # Weapons +EntityType.ARMOR # Armor +EntityType.MOB # Creatures +EntityType.BLUEPRINT # Blueprints +EntityType.MATERIAL # Materials +EntityType.LOCATION # Locations +EntityType.TELEPORTER # Teleporters +EntityType.SKILL # Skills +``` + +### Search + +```python +nexus = get_nexus_api() + +# Basic search +results = nexus.search( + query="omegaton", + entity_type=EntityType.WEAPON, + limit=10 +) + +# Advanced search +results = nexus.search( + query="rifle", + entity_type=EntityType.WEAPON, + filters={ + "min_damage": 50, + "max_damage": 100, + "ammo_type": "blp" + }, + sort_by="markup", + sort_order="desc", + limit=20 +) +``` + +### Item Details + +```python +# Get full item info +item = nexus.get_item(item_id=12345) + +# Get market data +market = nexus.get_market_history( + item_id=12345, + days=30 +) + +# Get price alerts +alerts = nexus.get_price_alerts(item_id=12345) +``` + +### Blueprints + +```python +# Get blueprint details +bp = nexus.get_blueprint(bp_id=67890) + +# Get required materials +materials = nexus.get_bp_materials(bp_id=67890) + +# Calculate crafting cost +cost = nexus.calculate_craft_cost( + bp_id=67890, + quantity=100, + include_markup=True +) +``` + +--- + +## Event System + +### Event Structure + +```python +from dataclasses import dataclass +from datetime import datetime + +@dataclass +class Event: + type: str + data: dict + timestamp: datetime + source: str +``` + +### Event Types Reference + +| Event Type | Data Schema | Description | +|------------|-------------|-------------| +| `loot.received` | `{items: [], mob_name: str, total_tt: float}` | Loot received | +| `skill.gain` | `{skill: str, old_value: float, new_value: float}` | Skill increase | +| `global.recorded` | `{type: str, value: float, mob: str}` | Global/HOF | +| `mission.complete` | `{mission_id: str, name: str, rewards: []}` | Mission done | +| `chat.message` | `{channel: str, sender: str, message: str}` | Chat message | +| `window.focus` | `{window: str, is_focused: bool}` | Focus change | + +--- + +## Security + +### Permission Model + +```python +# Request permissions in plugin manifest +permissions = [ + "log_reader:read", + "overlay:create", + "data_store:write", + "network:external", + "ocr:read", + "clipboard:read", + "clipboard:write" +] +``` + +### Secure Data + +```python +# Encrypt sensitive data +api.save_secure_data( + key="api_keys.nexus", + data="secret_key", + password=user_password +) + +# Decrypt +data = api.load_secure_data( + key="api_keys.nexus", + password=user_password +) +``` + +--- + +## Examples + +### Complete Plugin Example + +```python +""" +Loot Tracker Plugin +Tracks hunting loot with analytics. +""" + +from PyQt6.QtWidgets import * +from PyQt6.QtCore import * +from plugins.base_plugin import BasePlugin +from core.api import get_api +from core.event_bus import LootEvent + +class LootTrackerPlugin(BasePlugin): + name = "Loot Tracker" + version = "2.0.0" + author = "ImpulsiveFPS" + description = "Track hunting loot with ROI analysis" + hotkey = "ctrl+shift+l" + + def initialize(self): + self.api = get_api() + self.total_loot = 0.0 + self.session_start = QDateTime.currentDateTime() + + # Subscribe to loot events + self.loot_sub = self.api.subscribe_typed( + LootEvent, + self.on_loot + ) + + # Load history + self.history = self.api.load_data( + "loot_tracker.history", + default=[] + ) + + self.log_info("Loot Tracker initialized") + + def on_loot(self, event: LootEvent): + """Handle loot event.""" + self.total_loot += event.total_tt + + # Add to history + self.history.append({ + "timestamp": event.timestamp.isoformat(), + "mob": event.mob_name, + "tt": event.total_tt, + "items": len(event.items) + }) + + # Save (keep last 1000) + self.api.save_data( + "loot_tracker.history", + self.history[-1000:] + ) + + # Update UI + self.update_display() + + # Notify on big loot + if event.total_tt > 50: + self.api.show_notification( + "Big Loot!", + f"{event.mob_name}: {event.total_tt:.2f} PED", + sound=True + ) + + def get_ui(self): + """Create plugin UI.""" + widget = QWidget() + layout = QVBoxLayout(widget) + + # Header + header = QLabel("Session Loot Tracker") + header.setStyleSheet("font-size: 18px; font-weight: bold;") + layout.addWidget(header) + + # Stats + self.total_label = QLabel(f"Total: {self.total_loot:.2f} PED") + self.total_label.setStyleSheet("font-size: 24px; color: #10b981;") + layout.addWidget(self.total_label) + + # Session time + self.time_label = QLabel("Session: 00:00:00") + layout.addWidget(self.time_label) + + # History list + self.history_list = QListWidget() + layout.addWidget(self.history_list) + + # Buttons + btn_layout = QHBoxLayout() + + export_btn = QPushButton("Export") + export_btn.clicked.connect(self.export_data) + btn_layout.addWidget(export_btn) + + clear_btn = QPushButton("Clear") + clear_btn.clicked.connect(self.clear_history) + btn_layout.addWidget(clear_btn) + + layout.addLayout(btn_layout) + + # Start update timer + self.timer = QTimer() + self.timer.timeout.connect(self.update_time) + self.timer.start(1000) + + self.update_display() + return widget + + def update_display(self): + """Update UI with current stats.""" + self.total_label.setText( + f"Total: {self.total_loot:.2f} PED" + ) + + # Update history list + self.history_list.clear() + for entry in reversed(self.history[-50:]): + text = f"{entry['mob']}: {entry['tt']:.2f} PED" + self.history_list.addItem(text) + + def update_time(self): + """Update session timer.""" + elapsed = self.session_start.secsTo( + QDateTime.currentDateTime() + ) + hours = elapsed // 3600 + minutes = (elapsed % 3600) // 60 + seconds = elapsed % 60 + self.time_label.setText( + f"Session: {hours:02d}:{minutes:02d}:{seconds:02d}" + ) + + def export_data(self): + """Export loot history to CSV.""" + import csv + from pathlib import Path + + path = Path.home() / "loot_history.csv" + with open(path, 'w', newline='') as f: + writer = csv.DictWriter(f, + fieldnames=['timestamp', 'mob', 'tt', 'items']) + writer.writeheader() + writer.writerows(self.history) + + self.api.show_notification( + "Export Complete", + f"Saved to {path}" + ) + + def clear_history(self): + """Clear loot history.""" + self.history = [] + self.total_loot = 0.0 + self.api.delete_data("loot_tracker.history") + self.update_display() + + def shutdown(self): + """Cleanup on shutdown.""" + self.api.unsubscribe(self.loot_sub) + self.api.save_data( + "loot_tracker.history", + self.history[-1000:] + ) + self.log_info("Loot Tracker shutdown") +``` + +--- + +## Error Handling + +### Common Errors + +```python +try: + result = api.http_get("https://api.example.com") +except APIError as e: + print(f"API Error: {e.code} - {e.message}") +except RateLimitError: + print("Rate limited, retrying...") +except ServiceNotAvailableError: + print("Service not available") +``` + +### Error Codes + +| Code | Description | +|------|-------------| +| 1001 | Service not available | +| 1002 | Rate limit exceeded | +| 1003 | Permission denied | +| 1004 | Invalid parameters | +| 1005 | Network error | +| 1006 | Timeout | + +--- + +## Version History + +| Version | Changes | +|---------|---------| +| 2.1.0 | Added WidgetAPI, improved EventBus | +| 2.0.0 | Complete API redesign | +| 1.5.0 | Added Nexus API integration | +| 1.0.0 | Initial release | + +--- + +*Complete API Documentation - EU-Utility v2.1.0* +*Generated: 2026-02-23* diff --git a/docs/redesign/EU_UTILITY_REDESIGN_DRAFT.md b/docs/redesign/EU_UTILITY_REDESIGN_DRAFT.md new file mode 100644 index 0000000..6b9b4ff --- /dev/null +++ b/docs/redesign/EU_UTILITY_REDESIGN_DRAFT.md @@ -0,0 +1,713 @@ +# EU-Utility Application Redesign Draft +## Version 3.0 - Professional Architecture + +--- + +## 🎯 Executive Summary + +Current EU-Utility is feature-rich but architecture is fragmented. This redesign creates a unified, scalable, maintainable application. + +**Key Improvements:** +- Clean Architecture (Domain-Driven Design) +- Unified API Gateway +- Reactive Event System +- Plugin Sandbox Security +- Cloud Sync Capabilities + +--- + +## 🏗️ New Architecture + +``` +┌─────────────────────────────────────────────────────────────┐ +│ PRESENTATION LAYER │ +│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ +│ │ Main UI │ │ Overlay │ │ System Tray │ │ +│ │ (PyQt6) │ │ Manager │ │ Icon │ │ +│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │ +└─────────┼────────────────┼────────────────────┼─────────────┘ + │ │ │ + └────────────────┴────────────────────┘ + │ + ┌────────▼────────┐ + │ API GATEWAY │ + │ (FastAPI/REST) │ + └────────┬────────┘ + │ + ┌────────────────────┼────────────────────┐ + │ │ │ +┌───────▼──────┐ ┌─────────▼─────────┐ ┌──────▼──────┐ +│ CORE │ │ PLUGIN ENGINE │ │ SERVICES │ +│ SERVICES │ │ │ │ │ +│ │ │ ┌─────────────┐ │ │ • Nexus │ +│ • Settings │ │ │ Plugin │ │ │ • OCR │ +│ • DataStore │ │ │ Manager │ │ │ • Overlay │ +│ • EventBus │ │ └──────┬──────┘ │ │ • Capture │ +│ • Auth │ │ │ │ └─────────────┘ +└──────────────┘ │ ┌──────▼──────┐ │ + │ │ Sandboxed │ │ + │ │ Plugins │ │ + │ └─────────────┘ │ + └───────────────────┘ +``` + +--- + +## 📦 Domain Modules + +### 1. Domain: Core + +```python +# domain/core/entities.py +from dataclasses import dataclass +from datetime import datetime +from typing import Optional, Dict, Any +from enum import Enum + +class PluginState(Enum): + INSTALLED = "installed" + ACTIVE = "active" + ERROR = "error" + DISABLED = "disabled" + +@dataclass +class Plugin: + """Core plugin entity.""" + id: str + name: str + version: str + author: str + description: str + state: PluginState + hotkey: Optional[str] = None + config: Dict[str, Any] = None + created_at: datetime = None + updated_at: datetime = None + +@dataclass +class UserSettings: + """User configuration entity.""" + user_id: str + hotkeys: Dict[str, str] + theme: str + plugins_enabled: list + overlay_position: tuple + ocr_engine: str + api_keys: Dict[str, str] +``` + +### 2. Domain: Game + +```python +# domain/game/entities.py +from dataclasses import dataclass +from datetime import datetime +from typing import List, Optional +from decimal import Decimal + +@dataclass +class LootItem: + """Represents a looted item.""" + name: str + quantity: int + tt_value: Decimal + market_value: Optional[Decimal] = None + +@dataclass +class LootEvent: + """Game loot event.""" + id: str + timestamp: datetime + mob_name: str + items: List[LootItem] + total_tt: Decimal + location: Optional[tuple] = None + +@dataclass +class SkillGain: + """Skill increase event.""" + skill_name: str + value_before: float + value_after: float + timestamp: datetime +``` + +### 3. Domain: Market + +```python +# domain/market/entities.py +from dataclasses import dataclass +from decimal import Decimal +from datetime import datetime +from typing import Optional + +@dataclass +class MarketItem: + """Market data for an item.""" + item_id: str + name: str + category: str + current_price: Decimal + markup_percent: Decimal + volume_24h: int + last_update: datetime + +@dataclass +class PriceAlert: + """User price alert.""" + item_id: str + user_id: str + target_price: Decimal + condition: str # 'above' or 'below' + is_active: bool +``` + +--- + +## 🔌 Plugin System Redesign + +### Plugin Manifest (v3.0) + +```json +{ + "manifest_version": "3.0", + "plugin": { + "id": "com.example.loot_tracker", + "name": "Advanced Loot Tracker", + "version": "2.1.0", + "author": "ImpulsiveFPS", + "description": "Professional loot tracking with analytics", + "category": "tracking", + "min_api_version": "3.0" + }, + "permissions": [ + "log_reader:read", + "overlay:create", + "data_store:write", + "notification:send", + "ocr:read" + ], + "resources": { + "memory_limit": "128MB", + "cpu_limit": "10%", + "storage_limit": "50MB" + }, + "ui": { + "has_overlay": true, + "has_settings": true, + "hotkey": "ctrl+shift+l", + "icon": "treasure-chest" + }, + "dependencies": { + "core": ">=3.0", + "plugins": [] + } +} +``` + +### Plugin Base Class + +```python +# application/plugin_base.py +from abc import ABC, abstractmethod +from typing import Dict, Any, Optional +from dataclasses import dataclass +import asyncio + +@dataclass +class PluginContext: + """Context provided to plugins.""" + api: 'PluginAPI' + settings: Dict[str, Any] + storage: 'PluginStorage' + logger: 'PluginLogger' + event_bus: 'EventBus' + +class BasePlugin(ABC): + """Base class for all EU-Utility plugins.""" + + # Required - defined in manifest + id: str + name: str + version: str + + # Optional - defined in manifest + description: str = "" + author: str = "" + category: str = "utility" + + def __init__(self, context: PluginContext): + self.ctx = context + self._state = PluginState.INSTALLED + self._config: Dict[str, Any] = {} + + @abstractmethod + async def initialize(self) -> bool: + """Initialize the plugin. Return True on success.""" + pass + + @abstractmethod + async def activate(self) -> bool: + """Called when plugin is activated.""" + pass + + @abstractmethod + async def deactivate(self) -> None: + """Called when plugin is deactivated.""" + pass + + @abstractmethod + def get_ui(self) -> Optional['QWidget']: + """Return the plugin's UI component.""" + pass + + async def on_event(self, event: 'Event') -> None: + """Handle events from the event bus.""" + pass + + def get_config_schema(self) -> Dict[str, Any]: + """Return JSON schema for plugin configuration.""" + return {} +``` + +--- + +## 🔐 Security Architecture + +### Permission System + +```python +# security/permissions.py +from enum import Enum, auto + +class PermissionScope(Enum): + """Permission scopes for plugins.""" + LOG_READER = auto() + OVERLAY = auto() + DATA_STORE = auto() + NETWORK = auto() + OCR = auto() + CLIPBOARD = auto() + FILE_SYSTEM = auto() + PROCESS = auto() + +class PermissionLevel(Enum): + """Permission levels.""" + NONE = 0 + READ = 1 + WRITE = 2 + ADMIN = 3 + +@dataclass +class Permission: + scope: PermissionScope + level: PermissionLevel + constraints: Dict[str, Any] = None +``` + +### Plugin Sandbox + +```python +# security/sandbox.py +import subprocess +import tempfile +from pathlib import Path + +class PluginSandbox: + """Isolated execution environment for plugins.""" + + def __init__(self, plugin_id: str, permissions: List[Permission]): + self.plugin_id = plugin_id + self.permissions = permissions + self._temp_dir = tempfile.mkdtemp(prefix=f"eu_plugin_{plugin_id}_") + + def execute(self, code: str) -> Any: + """Execute plugin code in restricted environment.""" + # Implementation uses restricted Python interpreter + # with limited builtins and custom __import__ + pass + + def cleanup(self) -> None: + """Clean up sandbox resources.""" + shutil.rmtree(self._temp_dir, ignore_errors=True) +``` + +--- + +## 🔄 Event System + +### Reactive Event Bus + +```python +# infrastructure/event_bus.py +from typing import Callable, TypeVar, Generic +import asyncio +from dataclasses import dataclass +from datetime import datetime + +T = TypeVar('T') + +@dataclass +class Event(Generic[T]): + """Generic event container.""" + type: str + payload: T + timestamp: datetime + source: str + +class ReactiveEventBus: + """Reactive event system with filtering and transformation.""" + + def __init__(self): + self._subscribers: Dict[str, List[Callable]] = {} + self._streams: Dict[str, 'EventStream'] = {} + + def subscribe(self, + event_type: str, + handler: Callable[[Event], None], + filter_fn: Optional[Callable[[Event], bool]] = None) -> str: + """Subscribe to events with optional filtering.""" + subscription_id = str(uuid.uuid4()) + # Implementation + return subscription_id + + def publish(self, event: Event) -> None: + """Publish event to all subscribers.""" + # Async dispatch + asyncio.create_task(self._dispatch(event)) + + def stream(self, event_type: str) -> 'EventStream': + """Get reactive stream for event type.""" + if event_type not in self._streams: + self._streams[event_type] = EventStream(event_type) + return self._streams[event_type] + +class EventStream: + """Reactive stream for events.""" + + def __init__(self, event_type: str): + self.event_type = event_type + self._handlers = [] + + def filter(self, predicate: Callable[[Event], bool]) -> 'EventStream': + """Filter events.""" + return self + + def map(self, transform: Callable[[Event], T]) -> 'EventStream': + """Transform events.""" + return self + + def debounce(self, seconds: float) -> 'EventStream': + """Debounce events.""" + return self + + def subscribe(self, handler: Callable[[T], None]) -> None: + """Subscribe to stream.""" + pass +``` + +--- + +## 📊 Data Layer + +### Repository Pattern + +```python +# infrastructure/repositories.py +from abc import ABC, abstractmethod +from typing import List, Optional, Generic, TypeVar + +T = TypeVar('T') +ID = TypeVar('ID') + +class Repository(ABC, Generic[T, ID]): + """Base repository interface.""" + + @abstractmethod + def get(self, id: ID) -> Optional[T]: + pass + + @abstractmethod + def get_all(self) -> List[T]: + pass + + @abstractmethod + def create(self, entity: T) -> T: + pass + + @abstractmethod + def update(self, entity: T) -> T: + pass + + @abstractmethod + def delete(self, id: ID) -> bool: + pass + +class SQLiteRepository(Repository[T, ID]): + """SQLite implementation.""" + + def __init__(self, db_path: str, entity_class: type): + self.db_path = db_path + self.entity_class = entity_class + self._init_db() +``` + +### Data Sync + +```python +# infrastructure/sync.py +from typing import Dict, Any +import aiohttp + +class CloudSync: + """Sync data with cloud backend.""" + + def __init__(self, api_base: str, api_key: str): + self.api_base = api_base + self.api_key = api_key + self._local_queue = [] + + async def sync_settings(self, settings: Dict[str, Any]) -> bool: + """Sync user settings to cloud.""" + async with aiohttp.ClientSession() as session: + async with session.post( + f"{self.api_base}/settings", + json=settings, + headers={"Authorization": f"Bearer {self.api_key}"} + ) as resp: + return resp.status == 200 + + async def get_remote_settings(self) -> Dict[str, Any]: + """Get settings from cloud.""" + pass +``` + +--- + +## 🚀 API Gateway + +### RESTful API + +```python +# api/gateway.py +from fastapi import FastAPI, Depends, HTTPException +from fastapi.middleware.cors import CORSMiddleware +from typing import List, Optional + +app = FastAPI( + title="EU-Utility API", + version="3.0.0", + description="Unified API for EU-Utility" +) + +# Authentication dependency +async def verify_token(token: str = Header(...)): + """Verify API token.""" + # Implementation + pass + +@app.get("/plugins", response_model=List[PluginSchema]) +async def list_plugins( + category: Optional[str] = None, + active_only: bool = True, + auth = Depends(verify_token) +): + """List all plugins.""" + pass + +@app.post("/plugins/{plugin_id}/activate") +async def activate_plugin( + plugin_id: str, + auth = Depends(verify_token) +): + """Activate a plugin.""" + pass + +@app.get("/market/search") +async def search_market( + query: str, + category: Optional[str] = None, + limit: int = 20 +): + """Search market items.""" + pass + +@app.get("/game/loot/recent") +async def get_recent_loot( + hours: int = 24, + auth = Depends(verify_token) +): + """Get recent loot events.""" + pass + +@app.post("/ocr/recognize") +async def ocr_recognize( + region: tuple, # (x, y, width, height) + auth = Depends(verify_token) +): + """Recognize text from screen region.""" + pass +``` + +--- + +## 📱 UI/UX Design + +### Component Library + +```python +# ui/components.py +from PyQt6.QtWidgets import * +from PyQt6.QtCore import * +from PyQt6.QtGui import * + +class EUCard(QFrame): + """Card component for EU-Utility.""" + + def __init__(self, title: str, parent=None): + super().__init__(parent) + self.setObjectName("EUCard") + self.setup_ui(title) + + def setup_ui(self, title: str): + layout = QVBoxLayout(self) + layout.setContentsMargins(16, 16, 16, 16) + + # Header + header = QLabel(title) + header.setObjectName("card-title") + layout.addWidget(header) + + # Content area + self.content = QFrame() + self.content_layout = QVBoxLayout(self.content) + layout.addWidget(self.content) + + # Styling + self.setStyleSheet(""" + #EUCard { + background-color: #2d2d2d; + border-radius: 12px; + border: 1px solid #3d3d3d; + } + #card-title { + color: #ffffff; + font-size: 16px; + font-weight: bold; + margin-bottom: 12px; + } + """) + +class EUButton(QPushButton): + """Primary button component.""" + + def __init__(self, text: str, variant: str = "primary"): + super().__init__(text) + self.variant = variant + self.setup_style() + + def setup_style(self): + colors = { + "primary": ("#6366f1", "#4f46e5"), + "secondary": ("#3d3d3d", "#4d4d4d"), + "danger": ("#ef4444", "#dc2626"), + "success": ("#10b981", "#059669") + } + bg, hover = colors.get(self.variant, colors["primary"]) + + self.setStyleSheet(f""" + EUButton {{ + background-color: {bg}; + color: white; + border: none; + border-radius: 8px; + padding: 10px 20px; + font-weight: 600; + }} + EUButton:hover {{ + background-color: {hover}; + }} + """) +``` + +--- + +## 📋 Implementation Roadmap + +### Phase 1: Foundation (Week 1-2) +- [ ] Set up new project structure +- [ ] Implement domain entities +- [ ] Create repository layer +- [ ] Set up dependency injection + +### Phase 2: Core Services (Week 3-4) +- [ ] Event bus implementation +- [ ] Plugin system v3.0 +- [ ] Security sandbox +- [ ] Settings management + +### Phase 3: API & UI (Week 5-6) +- [ ] API Gateway +- [ ] Component library +- [ ] Main UI refactoring +- [ ] Overlay system + +### Phase 4: Integration (Week 7-8) +- [ ] Plugin migration tool +- [ ] Data migration +- [ ] Testing suite +- [ ] Documentation + +### Phase 5: Release (Week 9) +- [ ] Beta testing +- [ ] Performance optimization +- [ ] Security audit +- [ ] Public release + +--- + +## 📊 Migration Strategy + +### From v2.x to v3.0 + +```python +# migration/v2_to_v3.py +class MigrationTool: + """Migrate plugins and data from v2 to v3.""" + + def migrate_plugin(self, v2_plugin_path: str) -> str: + """Convert v2 plugin to v3 format.""" + # Read v2 plugin + # Generate v3 manifest + # Update imports + # Return new plugin path + pass + + def migrate_settings(self, v2_settings: dict) -> dict: + """Migrate user settings.""" + mapping = { + "hotkeys.global_toggle": "hotkeys.overlay_toggle", + "plugins.enabled": "plugins.active", + # ... + } + # Apply mapping + return migrated_settings +``` + +--- + +## 🎯 Success Metrics + +| Metric | Target | +|--------|--------| +| Startup Time | < 2 seconds | +| Memory Usage | < 200MB | +| Plugin Load | < 100ms each | +| API Response | < 50ms | +| Code Coverage | > 80% | +| Plugin Compatibility | 100% v2 plugins work | + +--- + +*Draft Application Design - EU-Utility v3.0* +*Created: 2026-02-23*