uploader-bot/docs/NEW_ARCHITECTURE.md

391 lines
18 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# MY Network v3.0 - Децентрализованная архитектура контента
## 🎯 Обзор
MY Network v3.0 представляет собой полностью децентрализованную платформу дистрибьюции контента, где каждая нода принимает независимые решения о принятии и хранении контента. Система исключает централизованное управление и кворумное принятие решений.
## 🏗️ Принципы децентрализации
### 1. Автономность нод
- **Независимое принятие решений**: Каждая нода самостоятельно решает принимать контент или нет
- **Локальные правила**: Настройки фильтрации и политики хранения на уровне ноды
- **Отсутствие консенсуса**: Нет необходимости в голосовании или кворуме
### 2. Доступность без цензуры
- **Множественные источники**: Контент может быть доступен на разных нодах
- **Отсутствие единой точки отказа**: Недоступность одной ноды не влияет на сеть
- **Устойчивость к цензуре**: Контент остается доступным пока есть хотя бы одна нода
### 3. Гибкая топология сети
- **Публичные ноды**: С открытыми портами для входящих соединений
- **Приватные ноды**: Только исходящие соединения, получение контента
- **Bootstrap ноды**: Точки входа в сеть для новых участников
## 🔄 Архитектура синхронизации
### Замена кворумной системы
```python
class ContentAcceptanceManager:
"""Управление принятием контента без консенсуса"""
def __init__(self, node_config: dict):
self.node_config = node_config
self.filters = ContentFilters(node_config)
async def should_accept_content(self, content_metadata: dict) -> bool:
"""
Решение о принятии контента (заглушка для будущего расширения)
В текущей версии всегда возвращает True.
В будущем здесь будут фильтры по:
- Авторам (whitelist/blacklist)
- Типам контента
- Размерам файлов
- Тегам и категориям
"""
# TODO: Добавить логику фильтрации
return True
async def process_content_announcement(self, peer_id: str, announcement: dict):
"""Обработка анонса нового контента от пира"""
content_hash = announcement.get("content_hash")
# Проверка - нужен ли нам этот контент
if await self.should_accept_content(announcement):
# Добавляем в очередь синхронизации
await self.sync_manager.queue_content_sync(peer_id, content_hash)
else:
logger.info(f"Content {content_hash} rejected by local filters")
```
### Протокол синхронизации P2P
```python
class P2PSyncProtocol:
"""Децентрализованный протокол синхронизации"""
async def announce_new_content(self, content: StoredContent):
"""Анонс нового контента всем подключенным пирам"""
announcement = {
"type": "content_announcement",
"content_hash": content.hash,
"file_size": content.file_size,
"content_type": content.content_type,
"encrypted": content.encrypted,
"timestamp": datetime.utcnow().isoformat(),
"author_id": content.author_id,
"tags": content.tags
}
# Рассылаем анонс всем активным пирам
for peer_id in self.active_peers:
try:
await self.send_to_peer(peer_id, announcement)
except Exception as e:
logger.warning(f"Failed to announce to peer {peer_id}: {e}")
async def request_content_sync(self, peer_id: str, content_hash: str):
"""Запрос синхронизации конкретного контента"""
request = {
"type": "sync_request",
"content_hash": content_hash,
"requesting_node": self.node_id,
"timestamp": datetime.utcnow().isoformat()
}
response = await self.send_request_to_peer(peer_id, request)
if response.get("status") == "approved":
await self._sync_content_from_peer(peer_id, content_hash)
else:
logger.info(f"Sync request for {content_hash} denied by {peer_id}")
```
## 🔐 Система шифрования и хэширования
### Единые хэши encrypted_content
```python
class ContentHashManager:
"""Управление хэшированием контента для децентрализованной сети"""
@staticmethod
def calculate_content_hash(content_data: bytes) -> str:
"""
Вычисление единого хэша для encrypted_content
Использует SHA-256 для обеспечения одинакового хэша
на всех нодах для одного и того же контента
"""
return hashlib.sha256(content_data).hexdigest()
@staticmethod
def encrypt_content_for_storage(content_data: bytes) -> tuple[bytes, str]:
"""
Шифрование контента для хранения
Returns:
tuple: (encrypted_data, encryption_key)
"""
# Генерируем уникальный ключ для этого контента
encryption_key = secrets.token_hex(32) # 256-bit key
# Шифруем контент симметричным алгоритмом
cipher = AES.new(
key=bytes.fromhex(encryption_key),
mode=AES.MODE_GCM
)
encrypted_data, auth_tag = cipher.encrypt_and_digest(content_data)
# Добавляем nonce и auth_tag к зашифрованным данным
final_encrypted = cipher.nonce + auth_tag + encrypted_data
return final_encrypted, encryption_key
@staticmethod
def decrypt_content(encrypted_data: bytes, encryption_key: str) -> bytes:
"""Расшифровка контента"""
# Извлекаем nonce, auth_tag и данные
nonce = encrypted_data[:16]
auth_tag = encrypted_data[16:32]
ciphertext = encrypted_data[32:]
# Расшифровываем
cipher = AES.new(
key=bytes.fromhex(encryption_key),
mode=AES.MODE_GCM,
nonce=nonce
)
return cipher.decrypt_and_verify(ciphertext, auth_tag)
```
### Контроль доступа к контенту
```python
class ContentAccessControl:
"""Система контроля доступа к контенту"""
async def can_provide_content(self, requester_node: str, content_hash: str) -> bool:
"""
Решение о предоставлении контента запрашивающей ноде
В текущей версии разрешает доступ всем.
В будущем здесь будут проверки:
- Доверенность ноды
- Коммерческая лицензия
- Региональные ограничения
"""
# TODO: Добавить логику контроля доступа
return True
async def generate_preview_id(self, content_hash: str) -> str:
"""
Генерация ID для preview, не связанного с основным хэшем
Preview ID намеренно не связан с encrypted_content хэшем
для обеспечения безопасности
"""
# Используем случайный UUID для preview
preview_id = str(uuid4())
# Сохраняем связь в локальной базе
await self._store_preview_mapping(content_hash, preview_id)
return preview_id
async def get_content_by_preview_id(self, preview_id: str) -> Optional[bytes]:
"""Получение preview контента по preview_id"""
content_hash = await self._get_content_hash_by_preview_id(preview_id)
if not content_hash:
return None
# Загружаем preview версию (не основной контент!)
preview_content = await StoredContent.get_preview_by_hash(content_hash)
return preview_content.data if preview_content else None
```
## 🌐 Топология сети
### Типы нод
```python
class NodeTypes:
"""Типы нод в MY Network"""
BOOTSTRAP = "bootstrap" # Точки входа в сеть
PUBLIC = "public" # Открытые ноды с входящими соединениями
PRIVATE = "private" # Закрытые ноды, только исходящие соединения
SEED = "seed" # Ноды с большим объемом контента для новых участников
class NodeConfiguration:
"""Конфигурация ноды"""
def __init__(self, config: dict):
self.node_type = config.get("node_type", NodeTypes.PUBLIC)
self.allow_incoming = config.get("allow_incoming", True)
self.max_connections = config.get("max_connections", 50)
self.bootstrap_nodes = config.get("bootstrap_nodes", [])
def is_private_node(self) -> bool:
"""Проверка является ли нода приватной"""
return self.node_type == NodeTypes.PRIVATE or not self.allow_incoming
def can_accept_incoming_connections(self) -> bool:
"""Может ли нода принимать входящие соединения"""
return self.allow_incoming and self.node_type != NodeTypes.PRIVATE
```
### Обнаружение и подключение к нодам
```python
class NetworkDiscovery:
"""Обнаружение нод в децентрализованной сети"""
async def discover_network_nodes(self) -> List[NodeInfo]:
"""Обнаружение доступных нод в сети"""
discovered_nodes = []
# Получаем список нод от bootstrap серверов
for bootstrap_node in self.config.bootstrap_nodes:
try:
nodes = await self._get_nodes_from_bootstrap(bootstrap_node)
discovered_nodes.extend(nodes)
except Exception as e:
logger.warning(f"Failed to get nodes from bootstrap {bootstrap_node}: {e}")
# Получаем список нод от подключенных пиров
for peer_id in self.connected_peers:
try:
nodes = await self._get_nodes_from_peer(peer_id)
discovered_nodes.extend(nodes)
except Exception as e:
logger.warning(f"Failed to get nodes from peer {peer_id}: {e}")
# Убираем дубликаты и себя
unique_nodes = self._deduplicate_nodes(discovered_nodes)
return [node for node in unique_nodes if node.node_id != self.node_id]
async def connect_to_network(self):
"""Подключение к сети MY Network"""
if not self.config.bootstrap_nodes:
logger.error("No bootstrap nodes configured")
return
connected_count = 0
target_connections = min(10, len(self.config.bootstrap_nodes) * 2)
# Подключаемся к bootstrap нодам
for bootstrap_node in self.config.bootstrap_nodes:
try:
if await self._connect_to_node(bootstrap_node):
connected_count += 1
logger.info(f"Connected to bootstrap node: {bootstrap_node}")
except Exception as e:
logger.warning(f"Failed to connect to bootstrap {bootstrap_node}: {e}")
# Если недостаточно соединений, ищем дополнительные ноды
if connected_count < target_connections:
additional_nodes = await self.discover_network_nodes()
for node_info in additional_nodes:
if connected_count >= target_connections:
break
try:
if await self._connect_to_node(node_info):
connected_count += 1
logger.info(f"Connected to discovered node: {node_info.node_id}")
except Exception as e:
logger.warning(f"Failed to connect to node {node_info.node_id}: {e}")
logger.info(f"Network connection complete. Connected to {connected_count} nodes")
```
## 📊 Мониторинг децентрализованной сети
### Статистика сети
```python
class NetworkStatistics:
"""Сбор статистики децентрализованной сети"""
async def collect_network_stats(self) -> dict:
"""Сбор статистики о состоянии сети"""
return {
"node_info": {
"node_id": self.node_id,
"node_type": self.config.node_type,
"version": self.version,
"uptime": self.get_uptime_seconds()
},
"connections": {
"total_peers": len(self.connected_peers),
"bootstrap_peers": len(self.bootstrap_connections),
"incoming_connections": self.get_incoming_connection_count(),
"outgoing_connections": self.get_outgoing_connection_count()
},
"content": {
"total_items": await self.get_local_content_count(),
"encrypted_items": await self.get_encrypted_content_count(),
"public_items": await self.get_public_content_count(),
"storage_used": await self.get_storage_usage_bytes()
},
"sync_activity": {
"content_synced_24h": await self.get_sync_count_24h(),
"pending_sync_items": self.sync_manager.get_pending_count(),
"failed_sync_attempts": self.sync_manager.get_failed_count(),
"last_sync_time": self.sync_manager.last_sync_time
},
"network_health": {
"reachable_nodes": await self.count_reachable_nodes(),
"network_latency_avg": await self.calculate_avg_network_latency(),
"content_availability": await self.calculate_content_availability()
}
}
```
## 🔧 API для децентрализованной сети
### Новые эндпоинты
```python
# Управление нодой
GET /api/v1/node/status # Статус ноды и подключений
GET /api/v1/node/peers # Список подключенных пиров
POST /api/v1/node/connect # Подключение к новому пиру
POST /api/v1/node/disconnect # Отключение от пира
# Обнаружение сети
GET /api/v1/network/discover # Обнаружение доступных нод
GET /api/v1/network/stats # Статистика сети
GET /api/v1/network/topology # Топология подключений
# Синхронизация контента
GET /api/v1/sync/status # Статус синхронизации
POST /api/v1/sync/request # Запрос синхронизации контента
GET /api/v1/sync/pending # Список ожидающей синхронизации
POST /api/v1/sync/cancel # Отмена синхронизации
# Поиск контента в сети
GET /api/v1/content/search # Поиск контента по хэшу в сети
GET /api/v1/content/{hash}/nodes # Список нод с конкретным контентом
POST /api/v1/content/announce # Анонс нового контента в сеть
# Управление доступом
POST /api/v1/access/request # Запрос доступа к контенту
GET /api/v1/access/policies # Политики доступа к контенту
PUT /api/v1/access/policies # Обновление политик доступа
```
Эта архитектура обеспечивает полную децентрализацию при сохранении гибкости и безопасности системы.