uploader-bot/docs/VERSIONING_COMPATIBILITY.md

20 KiB
Raw Blame History

MY Network v3.0 - Система версионирования и совместимости

🏷️ Семантическое версионирование

MY Network использует семантическое версионирование в формате MAJOR.MINOR.PATCH:

  • MAJOR: Критические изменения протокола, несовместимые изменения
  • MINOR: Новая функциональность, обратно совместимая
  • PATCH: Исправления ошибок, совместимые изменения

Примеры версий

  • 3.0.0 - Основная версия с децентрализованной архитектурой
  • 3.1.0 - Добавление новых функций синхронизации
  • 3.1.2 - Исправление ошибок в синхронизации

🔒 Правила совместимости

Критические ограничения (MAJOR версии)

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

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 эндпоинт для версии

@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)

🔄 Автоматическое обновление

Проверка обновлений

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

📊 Мониторинг версий в сети

Статистика версий

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)

🚨 Предупреждения и уведомления

Система уведомлений о версиях

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 эндпоинты для версионирования

# Информация о версии
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 # Статистика совместимости

Эта система обеспечивает надежную работу сети при наличии нод с разными версиями, предотвращая проблемы совместимости и обеспечивая плавные обновления.