feat: add marketplace metrics, privacy features, and service registry endpoints
- Add Prometheus metrics for marketplace API throughput and error rates with new dashboard panels - Implement confidential transaction models with encryption support and access control - Add key management system with registration, rotation, and audit logging - Create services and registry routers for service discovery and management - Integrate ZK proof generation for privacy-preserving receipts - Add metrics instru
This commit is contained in:
215
apps/miner-node/plugins/discovery.py
Normal file
215
apps/miner-node/plugins/discovery.py
Normal file
@ -0,0 +1,215 @@
|
||||
"""
|
||||
Plugin discovery and matching system
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
from typing import Dict, List, Set, Optional
|
||||
import requests
|
||||
|
||||
from .registry import registry
|
||||
from .base import ServicePlugin
|
||||
from .exceptions import PluginNotFoundError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ServiceDiscovery:
|
||||
"""Discovers and matches services to plugins"""
|
||||
|
||||
def __init__(self, pool_hub_url: str, miner_id: str):
|
||||
self.pool_hub_url = pool_hub_url
|
||||
self.miner_id = miner_id
|
||||
self.enabled_services: Set[str] = set()
|
||||
self.service_configs: Dict[str, Dict] = {}
|
||||
self._last_update = 0
|
||||
self._update_interval = 60 # seconds
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Start the discovery service"""
|
||||
logger.info("Starting service discovery")
|
||||
|
||||
# Initialize plugin registry
|
||||
await registry.initialize()
|
||||
|
||||
# Initial sync
|
||||
await self.sync_services()
|
||||
|
||||
# Start background sync task
|
||||
asyncio.create_task(self._sync_loop())
|
||||
|
||||
async def sync_services(self) -> None:
|
||||
"""Sync enabled services from pool-hub"""
|
||||
try:
|
||||
# Get service configurations from pool-hub
|
||||
response = requests.get(
|
||||
f"{self.pool_hub_url}/v1/services/",
|
||||
headers={"X-Miner-ID": self.miner_id}
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
services = response.json()
|
||||
|
||||
# Update local state
|
||||
new_enabled = set()
|
||||
new_configs = {}
|
||||
|
||||
for service in services:
|
||||
if service.get("enabled", False):
|
||||
service_id = service["service_type"]
|
||||
new_enabled.add(service_id)
|
||||
new_configs[service_id] = service
|
||||
|
||||
# Find changes
|
||||
added = new_enabled - self.enabled_services
|
||||
removed = self.enabled_services - new_enabled
|
||||
updated = set()
|
||||
|
||||
for service_id in self.enabled_services & new_enabled:
|
||||
if new_configs[service_id] != self.service_configs.get(service_id):
|
||||
updated.add(service_id)
|
||||
|
||||
# Apply changes
|
||||
for service_id in removed:
|
||||
await self._disable_service(service_id)
|
||||
|
||||
for service_id in added:
|
||||
await self._enable_service(service_id, new_configs[service_id])
|
||||
|
||||
for service_id in updated:
|
||||
await self._update_service(service_id, new_configs[service_id])
|
||||
|
||||
# Update state
|
||||
self.enabled_services = new_enabled
|
||||
self.service_configs = new_configs
|
||||
self._last_update = asyncio.get_event_loop().time()
|
||||
|
||||
logger.info(f"Synced services: {len(self.enabled_services)} enabled")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to sync services: {e}")
|
||||
|
||||
async def _enable_service(self, service_id: str, config: Dict) -> None:
|
||||
"""Enable a service"""
|
||||
try:
|
||||
# Check if plugin exists
|
||||
if service_id not in registry.list_plugins():
|
||||
logger.warning(f"No plugin available for service: {service_id}")
|
||||
return
|
||||
|
||||
# Load plugin
|
||||
plugin = registry.load_plugin(service_id)
|
||||
|
||||
# Validate hardware requirements
|
||||
await self._validate_hardware_requirements(plugin, config)
|
||||
|
||||
# Configure plugin if needed
|
||||
if hasattr(plugin, 'configure'):
|
||||
await plugin.configure(config.get('config', {}))
|
||||
|
||||
logger.info(f"Enabled service: {service_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to enable service {service_id}: {e}")
|
||||
|
||||
async def _disable_service(self, service_id: str) -> None:
|
||||
"""Disable a service"""
|
||||
try:
|
||||
# Unload plugin to free resources
|
||||
registry.unload_plugin(service_id)
|
||||
logger.info(f"Disabled service: {service_id}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to disable service {service_id}: {e}")
|
||||
|
||||
async def _update_service(self, service_id: str, config: Dict) -> None:
|
||||
"""Update service configuration"""
|
||||
# For now, just disable and re-enable
|
||||
await self._disable_service(service_id)
|
||||
await self._enable_service(service_id, config)
|
||||
|
||||
async def _validate_hardware_requirements(self, plugin: ServicePlugin, config: Dict) -> None:
|
||||
"""Validate that miner meets plugin requirements"""
|
||||
requirements = plugin.get_hardware_requirements()
|
||||
|
||||
# This would check against actual miner hardware
|
||||
# For now, just log the requirements
|
||||
logger.debug(f"Hardware requirements for {plugin.service_id}: {requirements}")
|
||||
|
||||
async def _sync_loop(self) -> None:
|
||||
"""Background sync loop"""
|
||||
while True:
|
||||
await asyncio.sleep(self._update_interval)
|
||||
await self.sync_services()
|
||||
|
||||
async def execute_service(self, service_id: str, request: Dict) -> Dict:
|
||||
"""Execute a service request"""
|
||||
try:
|
||||
# Check if service is enabled
|
||||
if service_id not in self.enabled_services:
|
||||
raise PluginNotFoundError(f"Service {service_id} is not enabled")
|
||||
|
||||
# Get plugin
|
||||
plugin = registry.get_plugin(service_id)
|
||||
if not plugin:
|
||||
raise PluginNotFoundError(f"No plugin loaded for service: {service_id}")
|
||||
|
||||
# Execute request
|
||||
result = await plugin.execute(request)
|
||||
|
||||
# Convert result to dict
|
||||
return {
|
||||
"success": result.success,
|
||||
"data": result.data,
|
||||
"error": result.error,
|
||||
"metrics": result.metrics,
|
||||
"execution_time": result.execution_time
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to execute service {service_id}: {e}")
|
||||
return {
|
||||
"success": False,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
def get_enabled_services(self) -> List[str]:
|
||||
"""Get list of enabled services"""
|
||||
return list(self.enabled_services)
|
||||
|
||||
def get_service_status(self) -> Dict[str, Dict]:
|
||||
"""Get status of all services"""
|
||||
status = {}
|
||||
|
||||
for service_id in registry.list_plugins():
|
||||
plugin = registry.get_plugin(service_id)
|
||||
status[service_id] = {
|
||||
"enabled": service_id in self.enabled_services,
|
||||
"loaded": plugin is not None,
|
||||
"config": self.service_configs.get(service_id, {}),
|
||||
"capabilities": plugin.capabilities if plugin else []
|
||||
}
|
||||
|
||||
return status
|
||||
|
||||
async def health_check(self) -> Dict[str, bool]:
|
||||
"""Health check all enabled services"""
|
||||
results = {}
|
||||
|
||||
for service_id in self.enabled_services:
|
||||
plugin = registry.get_plugin(service_id)
|
||||
if plugin:
|
||||
try:
|
||||
results[service_id] = await plugin.health_check()
|
||||
except Exception as e:
|
||||
logger.error(f"Health check failed for {service_id}: {e}")
|
||||
results[service_id] = False
|
||||
else:
|
||||
results[service_id] = False
|
||||
|
||||
return results
|
||||
|
||||
async def stop(self) -> None:
|
||||
"""Stop the discovery service"""
|
||||
logger.info("Stopping service discovery")
|
||||
registry.cleanup_all()
|
||||
Reference in New Issue
Block a user