init
This commit is contained in:
@@ -0,0 +1,320 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Peer Registry for Personal Internet Cell
|
||||
Handles peer registration and management
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import logging
|
||||
from threading import RLock
|
||||
from datetime import datetime
|
||||
from typing import Dict, List, Any, Optional
|
||||
from base_service_manager import BaseServiceManager
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class PeerRegistry(BaseServiceManager):
|
||||
"""Manages peer registration and management"""
|
||||
|
||||
def __init__(self, data_dir: str = '/app/data', config_dir: str = '/app/config'):
|
||||
super().__init__('peer_registry', data_dir, config_dir)
|
||||
self.lock = RLock()
|
||||
self.peers = []
|
||||
self.peers_file = os.path.join(data_dir, 'peers.json')
|
||||
self._load_peers()
|
||||
|
||||
def get_status(self) -> Dict[str, Any]:
|
||||
"""Get peer registry status"""
|
||||
try:
|
||||
with self.lock:
|
||||
status = {
|
||||
'running': True,
|
||||
'status': 'online',
|
||||
'peers_count': len(self.peers),
|
||||
'active_peers': len([p for p in self.peers if p.get('active', True)]),
|
||||
'inactive_peers': len([p for p in self.peers if not p.get('active', True)]),
|
||||
'last_updated': datetime.utcnow().isoformat(),
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
}
|
||||
|
||||
return status
|
||||
except Exception as e:
|
||||
return self.handle_error(e, "get_status")
|
||||
|
||||
def test_connectivity(self) -> Dict[str, Any]:
|
||||
"""Test peer registry connectivity"""
|
||||
try:
|
||||
# Test file system access
|
||||
fs_test = self._test_filesystem_access()
|
||||
|
||||
# Test peer data integrity
|
||||
integrity_test = self._test_data_integrity()
|
||||
|
||||
# Test peer operations
|
||||
operations_test = self._test_peer_operations()
|
||||
|
||||
results = {
|
||||
'filesystem_access': fs_test,
|
||||
'data_integrity': integrity_test,
|
||||
'peer_operations': operations_test,
|
||||
'success': fs_test.get('success', False) and integrity_test.get('success', False),
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
}
|
||||
|
||||
return results
|
||||
except Exception as e:
|
||||
return self.handle_error(e, "test_connectivity")
|
||||
|
||||
def _test_filesystem_access(self) -> Dict[str, Any]:
|
||||
"""Test filesystem access for peer data"""
|
||||
try:
|
||||
# Test if we can read/write to the peers file
|
||||
test_peer = {
|
||||
'peer': 'test_peer',
|
||||
'ip': '192.168.1.100',
|
||||
'public_key': 'test_key',
|
||||
'active': False,
|
||||
'test': True
|
||||
}
|
||||
|
||||
# Test write
|
||||
with self.lock:
|
||||
original_peers = self.peers.copy()
|
||||
self.peers.append(test_peer)
|
||||
self._save_peers()
|
||||
|
||||
# Test read
|
||||
with self.lock:
|
||||
loaded_peers = self.peers.copy()
|
||||
# Remove test peer
|
||||
self.peers = [p for p in self.peers if not p.get('test', False)]
|
||||
self._save_peers()
|
||||
|
||||
# Restore original state
|
||||
with self.lock:
|
||||
self.peers = original_peers
|
||||
self._save_peers()
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': 'Filesystem access working',
|
||||
'read_write': True
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Filesystem access failed: {str(e)}',
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
def _test_data_integrity(self) -> Dict[str, Any]:
|
||||
"""Test peer data integrity"""
|
||||
try:
|
||||
with self.lock:
|
||||
# Check if peers data is valid JSON
|
||||
peers_copy = self.peers.copy()
|
||||
|
||||
# Validate peer structure
|
||||
valid_peers = 0
|
||||
invalid_peers = 0
|
||||
|
||||
for peer in peers_copy:
|
||||
if isinstance(peer, dict) and 'peer' in peer and 'ip' in peer:
|
||||
valid_peers += 1
|
||||
else:
|
||||
invalid_peers += 1
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'message': 'Data integrity check passed',
|
||||
'valid_peers': valid_peers,
|
||||
'invalid_peers': invalid_peers,
|
||||
'total_peers': len(peers_copy)
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Data integrity check failed: {str(e)}',
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
def _test_peer_operations(self) -> Dict[str, Any]:
|
||||
"""Test peer operations"""
|
||||
try:
|
||||
# Test adding a peer
|
||||
test_peer = {
|
||||
'peer': 'test_operation_peer',
|
||||
'ip': '192.168.1.101',
|
||||
'public_key': 'test_operation_key',
|
||||
'active': False,
|
||||
'test': True
|
||||
}
|
||||
|
||||
# Test add
|
||||
add_success = self.add_peer(test_peer)
|
||||
|
||||
# Test get
|
||||
retrieved_peer = self.get_peer('test_operation_peer')
|
||||
get_success = retrieved_peer is not None
|
||||
|
||||
# Test update
|
||||
update_success = self.update_peer_ip('test_operation_peer', '192.168.1.102')
|
||||
|
||||
# Test remove
|
||||
remove_success = self.remove_peer('test_operation_peer')
|
||||
|
||||
return {
|
||||
'success': add_success and get_success and update_success and remove_success,
|
||||
'message': 'Peer operations working',
|
||||
'add_success': add_success,
|
||||
'get_success': get_success,
|
||||
'update_success': update_success,
|
||||
'remove_success': remove_success
|
||||
}
|
||||
except Exception as e:
|
||||
return {
|
||||
'success': False,
|
||||
'message': f'Peer operations test failed: {str(e)}',
|
||||
'error': str(e)
|
||||
}
|
||||
|
||||
def _load_peers(self):
|
||||
"""Load peers from file"""
|
||||
try:
|
||||
# Ensure directory exists
|
||||
os.makedirs(os.path.dirname(self.peers_file), exist_ok=True)
|
||||
|
||||
if os.path.exists(self.peers_file):
|
||||
with open(self.peers_file, 'r') as f:
|
||||
try:
|
||||
self.peers = json.load(f)
|
||||
self.logger.info(f"Loaded {len(self.peers)} peers from file")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error loading peers: {e}")
|
||||
self.peers = []
|
||||
else:
|
||||
self.peers = []
|
||||
self.logger.info("No peers file found, starting with empty registry")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error in _load_peers: {e}")
|
||||
self.peers = []
|
||||
|
||||
def _save_peers(self):
|
||||
"""Save peers to file"""
|
||||
try:
|
||||
# Ensure directory exists
|
||||
os.makedirs(os.path.dirname(self.peers_file), exist_ok=True)
|
||||
|
||||
with open(self.peers_file, 'w') as f:
|
||||
json.dump(self.peers, f, indent=2)
|
||||
|
||||
self.logger.info(f"Saved {len(self.peers)} peers to file")
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error saving peers: {e}")
|
||||
|
||||
def list_peers(self) -> List[Dict[str, Any]]:
|
||||
"""List all peers"""
|
||||
with self.lock:
|
||||
return list(self.peers)
|
||||
|
||||
def get_peer(self, name: str) -> Optional[Dict[str, Any]]:
|
||||
"""Get a specific peer by name"""
|
||||
with self.lock:
|
||||
for peer in self.peers:
|
||||
if peer.get('peer') == name:
|
||||
return peer
|
||||
return None
|
||||
|
||||
def add_peer(self, peer_info: Dict[str, Any]) -> bool:
|
||||
"""Add a new peer"""
|
||||
try:
|
||||
with self.lock:
|
||||
if self.get_peer(peer_info.get('peer')):
|
||||
self.logger.warning(f"Peer {peer_info.get('peer')} already exists")
|
||||
return False
|
||||
|
||||
# Add timestamp
|
||||
peer_info['created_at'] = datetime.utcnow().isoformat()
|
||||
peer_info['active'] = peer_info.get('active', True)
|
||||
|
||||
self.peers.append(peer_info)
|
||||
self._save_peers()
|
||||
|
||||
self.logger.info(f"Added peer: {peer_info.get('peer')}")
|
||||
return True
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error adding peer: {e}")
|
||||
return False
|
||||
|
||||
def remove_peer(self, name: str) -> bool:
|
||||
"""Remove a peer"""
|
||||
try:
|
||||
with self.lock:
|
||||
before = len(self.peers)
|
||||
self.peers = [p for p in self.peers if p.get('peer') != name]
|
||||
self._save_peers()
|
||||
|
||||
removed = len(self.peers) < before
|
||||
if removed:
|
||||
self.logger.info(f"Removed peer: {name}")
|
||||
else:
|
||||
self.logger.warning(f"Peer {name} not found for removal")
|
||||
|
||||
return removed
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error removing peer {name}: {e}")
|
||||
return False
|
||||
|
||||
def update_peer_ip(self, name: str, new_ip: str) -> bool:
|
||||
"""Update peer IP address"""
|
||||
try:
|
||||
with self.lock:
|
||||
for peer in self.peers:
|
||||
if peer.get('peer') == name:
|
||||
old_ip = peer.get('ip')
|
||||
peer['ip'] = new_ip
|
||||
peer['updated_at'] = datetime.utcnow().isoformat()
|
||||
self._save_peers()
|
||||
|
||||
self.logger.info(f"Updated peer {name} IP from {old_ip} to {new_ip}")
|
||||
return True
|
||||
|
||||
self.logger.warning(f"Peer {name} not found for IP update")
|
||||
return False
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error updating peer {name} IP: {e}")
|
||||
return False
|
||||
|
||||
def get_peer_stats(self) -> Dict[str, Any]:
|
||||
"""Get peer registry statistics"""
|
||||
try:
|
||||
with self.lock:
|
||||
active_peers = [p for p in self.peers if p.get('active', True)]
|
||||
inactive_peers = [p for p in self.peers if not p.get('active', True)]
|
||||
|
||||
# Count peers by IP range
|
||||
ip_ranges = {}
|
||||
for peer in self.peers:
|
||||
ip = peer.get('ip', '')
|
||||
if ip:
|
||||
range_key = '.'.join(ip.split('.')[:3]) + '.0/24'
|
||||
ip_ranges[range_key] = ip_ranges.get(range_key, 0) + 1
|
||||
|
||||
return {
|
||||
'total_peers': len(self.peers),
|
||||
'active_peers': len(active_peers),
|
||||
'inactive_peers': len(inactive_peers),
|
||||
'ip_ranges': ip_ranges,
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
}
|
||||
except Exception as e:
|
||||
self.logger.error(f"Error getting peer stats: {e}")
|
||||
return {
|
||||
'total_peers': 0,
|
||||
'active_peers': 0,
|
||||
'inactive_peers': 0,
|
||||
'ip_ranges': {},
|
||||
'error': str(e),
|
||||
'timestamp': datetime.utcnow().isoformat()
|
||||
}
|
||||
Reference in New Issue
Block a user