uploader-bot/docs/VERSIONING_COMPATIBILITY.md

489 lines
20 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 использует семантическое версионирование в формате `MAJOR.MINOR.PATCH`:
- **MAJOR**: Критические изменения протокола, несовместимые изменения
- **MINOR**: Новая функциональность, обратно совместимая
- **PATCH**: Исправления ошибок, совместимые изменения
### Примеры версий
- `3.0.0` - Основная версия с децентрализованной архитектурой
- `3.1.0` - Добавление новых функций синхронизации
- `3.1.2` - Исправление ошибок в синхронизации
## 🔒 Правила совместимости
### Критические ограничения (MAJOR версии)
```python
class VersionCompatibility:
"""Система проверки совместимости версий нод"""
def __init__(self, current_version: str):
self.current_version = self.parse_version(current_version)
def parse_version(self, version_string: str) -> dict:
"""Парсинг версии в структурированный формат"""
try:
major, minor, patch = version_string.split('.')
return {
"major": int(major),
"minor": int(minor),
"patch": int(patch),
"string": version_string
}
except ValueError:
raise ValueError(f"Invalid version format: {version_string}")
def check_compatibility(self, peer_version: str) -> dict:
"""
Проверка совместимости с версией пира
Returns:
dict: {
"compatible": bool,
"level": "compatible|warning|blocked",
"message": str,
"allow_connection": bool
}
"""
peer_ver = self.parse_version(peer_version)
current_ver = self.current_version
# Проверка MAJOR версии
if peer_ver["major"] != current_ver["major"]:
return {
"compatible": False,
"level": "blocked",
"message": f"Incompatible major version: {peer_version} vs {current_ver['string']}. Connection blocked.",
"allow_connection": False
}
# Проверка MINOR версии
if peer_ver["minor"] != current_ver["minor"]:
newer_version = peer_ver if peer_ver["minor"] > current_ver["minor"] else current_ver
older_version = peer_ver if peer_ver["minor"] < current_ver["minor"] else current_ver
return {
"compatible": True,
"level": "warning",
"message": f"Different minor version: {peer_version} vs {current_ver['string']}. Some features may be unavailable.",
"allow_connection": True,
"recommendation": f"Consider updating to v{newer_version['major']}.{newer_version['minor']}.x"
}
# PATCH различия - полная совместимость
if peer_ver["patch"] != current_ver["patch"]:
return {
"compatible": True,
"level": "compatible",
"message": f"Compatible versions: {peer_version} vs {current_ver['string']}",
"allow_connection": True
}
# Идентичные версии
return {
"compatible": True,
"level": "compatible",
"message": f"Identical versions: {peer_version}",
"allow_connection": True
}
```
### Матрица совместимости
| Peer Version | Current Version | Result | Action |
|--------------|-----------------|--------|---------|
| `3.0.x` | `3.0.x` | ✅ Compatible | Allow connection |
| `3.1.x` | `3.0.x` | ⚠️ Warning | Allow with warning |
| `3.0.x` | `3.1.x` | ⚠️ Warning | Allow with warning |
| `4.0.x` | `3.x.x` | ❌ Blocked | Reject connection |
| `2.x.x` | `3.x.x` | ❌ Blocked | Reject connection |
## 🤝 Протокол handshake с проверкой версий
### Расширенный handshake
```python
class VersionAwareHandshake:
"""Handshake с проверкой версий"""
async def perform_handshake(self, peer_connection: PeerConnection) -> bool:
"""Выполнение handshake с проверкой совместимости версий"""
# Отправка handshake с информацией о версии
handshake_msg = {
"type": "handshake",
"node_id": self.node_id,
"public_key": self.public_key_hex,
"version": {
"protocol": MY_NETWORK_VERSION,
"node": NODE_VERSION,
"features": self.get_supported_features(),
"capabilities": self.get_node_capabilities()
},
"timestamp": datetime.utcnow().isoformat()
}
# Подписание сообщения
handshake_msg["signature"] = await self.sign_message(handshake_msg)
# Отправка handshake
await peer_connection.send_message(handshake_msg)
# Получение ответа
response = await peer_connection.receive_message(timeout=30)
if response.get("type") != "handshake_response":
logger.error("Invalid handshake response type")
return False
# Проверка версии пира
peer_version = response.get("version", {}).get("protocol")
if not peer_version:
logger.error("Peer did not provide version information")
return False
# Проверка совместимости
compatibility = self.version_checker.check_compatibility(peer_version)
if not compatibility["allow_connection"]:
logger.error(f"Version incompatibility: {compatibility['message']}")
await peer_connection.send_message({
"type": "handshake_error",
"reason": "version_incompatible",
"message": compatibility["message"]
})
return False
# Логирование предупреждений
if compatibility["level"] == "warning":
logger.warning(f"Version compatibility warning: {compatibility['message']}")
# Отправка предупреждения пиру
await peer_connection.send_message({
"type": "version_warning",
"message": compatibility["message"],
"recommendation": compatibility.get("recommendation")
})
# Сохранение информации о версии пира
peer_connection.version_info = response.get("version")
peer_connection.compatibility = compatibility
logger.info(f"Handshake successful with peer {response.get('node_id')} (v{peer_version})")
return True
def get_supported_features(self) -> List[str]:
"""Получение списка поддерживаемых функций"""
return [
"content_sync",
"p2p_discovery",
"content_filtering",
"version_negotiation",
"encrypted_transport"
]
def get_node_capabilities(self) -> dict:
"""Получение возможностей ноды"""
return {
"max_peers": self.config.max_connections,
"storage_capacity": self.get_available_storage(),
"node_type": self.config.node_type,
"content_types": self.get_supported_content_types()
}
```
## 📋 Версионная информация ноды
### API эндпоинт для версии
```python
@app.route('/api/v1/system/version', methods=['GET'])
async def get_version_info(request):
"""Получение информации о версии ноды"""
return response.json({
"version": {
"protocol": MY_NETWORK_VERSION,
"node": NODE_VERSION,
"api": API_VERSION,
"build": BUILD_VERSION,
"build_date": BUILD_DATE
},
"compatibility": {
"min_protocol_version": "3.0.0",
"max_protocol_version": "3.9.9",
"deprecated_versions": ["2.x.x"],
"supported_features": [
"content_sync",
"p2p_discovery",
"content_filtering",
"version_negotiation"
]
},
"node_info": {
"node_id": node_service.node_id,
"node_type": node_service.config.node_type,
"uptime": node_service.get_uptime_seconds(),
"capabilities": node_service.get_node_capabilities()
}
})
@app.route('/api/v1/system/compatibility', methods=['POST'])
async def check_version_compatibility(request):
"""Проверка совместимости с другой версией"""
data = request.json
peer_version = data.get("version")
if not peer_version:
return response.json({"error": "Version is required"}, status=400)
try:
compatibility = version_checker.check_compatibility(peer_version)
return response.json(compatibility)
except ValueError as e:
return response.json({"error": str(e)}, status=400)
```
## 🔄 Автоматическое обновление
### Проверка обновлений
```python
class UpdateChecker:
"""Система проверки и уведомления об обновлениях"""
def __init__(self, current_version: str, update_url: str):
self.current_version = current_version
self.update_url = update_url
self.last_check = None
async def check_for_updates(self) -> dict:
"""Проверка доступных обновлений"""
try:
# Запрос информации о последней версии
async with aiohttp.ClientSession() as session:
async with session.get(f"{self.update_url}/latest-version") as response:
if response.status == 200:
data = await response.json()
latest_version = data.get("version")
if latest_version:
update_info = self._compare_versions(latest_version)
self.last_check = datetime.utcnow()
return update_info
except Exception as e:
logger.error(f"Failed to check for updates: {e}")
return {"update_available": False, "error": "Failed to check updates"}
def _compare_versions(self, latest_version: str) -> dict:
"""Сравнение текущей и последней версии"""
current = self._parse_version(self.current_version)
latest = self._parse_version(latest_version)
if latest["major"] > current["major"]:
return {
"update_available": True,
"update_type": "major",
"current_version": self.current_version,
"latest_version": latest_version,
"critical": True,
"message": "Major update available with breaking changes"
}
elif latest["minor"] > current["minor"]:
return {
"update_available": True,
"update_type": "minor",
"current_version": self.current_version,
"latest_version": latest_version,
"critical": False,
"message": "Minor update available with new features"
}
elif latest["patch"] > current["patch"]:
return {
"update_available": True,
"update_type": "patch",
"current_version": self.current_version,
"latest_version": latest_version,
"critical": False,
"message": "Patch update available with bug fixes"
}
return {
"update_available": False,
"current_version": self.current_version,
"latest_version": latest_version,
"message": "You are running the latest version"
}
async def get_update_recommendations(self) -> List[str]:
"""Получение рекомендаций по обновлению"""
update_info = await self.check_for_updates()
if not update_info.get("update_available"):
return ["Your node is up to date"]
recommendations = []
if update_info.get("critical"):
recommendations.append("🔴 Critical update available - update immediately for compatibility")
if update_info.get("update_type") == "major":
recommendations.append("⚠️ Major version update - review breaking changes before updating")
recommendations.append("📋 Backup your data before major version updates")
elif update_info.get("update_type") == "minor":
recommendations.append("✨ New features available in minor update")
recommendations.append("🔄 Safe to update - backwards compatible")
elif update_info.get("update_type") == "patch":
recommendations.append("🐛 Bug fixes available - recommended to update")
return recommendations
```
## 📊 Мониторинг версий в сети
### Статистика версий
```python
class NetworkVersionMonitor:
"""Мониторинг версий нод в сети"""
def __init__(self):
self.peer_versions = {}
async def track_peer_version(self, peer_id: str, version_info: dict):
"""Отслеживание версии пира"""
self.peer_versions[peer_id] = {
"version": version_info,
"last_seen": datetime.utcnow(),
"compatible": True
}
async def get_network_version_stats(self) -> dict:
"""Статистика версий в сети"""
if not self.peer_versions:
return {"total_peers": 0, "version_distribution": {}}
version_counts = {}
total_peers = len(self.peer_versions)
compatible_peers = 0
for peer_id, peer_data in self.peer_versions.items():
version = peer_data["version"]["protocol"]
version_counts[version] = version_counts.get(version, 0) + 1
if peer_data["compatible"]:
compatible_peers += 1
return {
"total_peers": total_peers,
"compatible_peers": compatible_peers,
"compatibility_rate": compatible_peers / total_peers if total_peers > 0 else 0,
"version_distribution": version_counts,
"most_common_version": max(version_counts.items(), key=lambda x: x[1])[0] if version_counts else None
}
async def get_outdated_peers(self) -> List[dict]:
"""Список пиров с устаревшими версиями"""
current_major = self._parse_version(MY_NETWORK_VERSION)["major"]
outdated = []
for peer_id, peer_data in self.peer_versions.items():
peer_version = peer_data["version"]["protocol"]
peer_major = self._parse_version(peer_version)["major"]
if peer_major < current_major:
outdated.append({
"peer_id": peer_id,
"version": peer_version,
"age": (datetime.utcnow() - peer_data["last_seen"]).total_seconds()
})
return sorted(outdated, key=lambda x: x["age"], reverse=True)
```
## 🚨 Предупреждения и уведомления
### Система уведомлений о версиях
```python
class VersionNotificationManager:
"""Управление уведомлениями о версиях"""
async def notify_version_mismatch(self, peer_id: str, peer_version: str, compatibility: dict):
"""Уведомление о несоответствии версий"""
if compatibility["level"] == "blocked":
logger.error(f"🚫 Connection blocked: Peer {peer_id} version {peer_version} incompatible")
# Можно добавить отправку в мониторинг
await self._send_to_monitoring({
"type": "version_incompatibility",
"peer_id": peer_id,
"peer_version": peer_version,
"severity": "critical"
})
elif compatibility["level"] == "warning":
logger.warning(f"⚠️ Version warning: Peer {peer_id} version {peer_version} - {compatibility['message']}")
await self._send_to_monitoring({
"type": "version_warning",
"peer_id": peer_id,
"peer_version": peer_version,
"severity": "warning",
"recommendation": compatibility.get("recommendation")
})
async def notify_update_available(self, update_info: dict):
"""Уведомление о доступном обновлении"""
if update_info.get("critical"):
logger.error(f"🔴 Critical update available: {update_info['latest_version']}")
else:
logger.info(f"✨ Update available: {update_info['latest_version']}")
# Отправка в систему мониторинга
await self._send_to_monitoring({
"type": "update_available",
"current_version": update_info["current_version"],
"latest_version": update_info["latest_version"],
"update_type": update_info["update_type"],
"critical": update_info.get("critical", False)
})
```
## 📖 API эндпоинты для версионирования
```python
# Информация о версии
GET /api/v1/system/version # Полная информация о версии
GET /api/v1/system/compatibility # Информация о совместимости
POST /api/v1/system/compatibility/check # Проверка совместимости с версией
# Обновления
GET /api/v1/system/updates/check # Проверка доступных обновлений
GET /api/v1/system/updates/recommendations # Рекомендации по обновлению
# Статистика сети
GET /api/v1/network/versions # Статистика версий в сети
GET /api/v1/network/compatibility/stats # Статистика совместимости
```
Эта система обеспечивает надежную работу сети при наличии нод с разными версиями, предотвращая проблемы совместимости и обеспечивая плавные обновления.