message / app /utils /network_utils.py
hunian
refactor(docker): 简化 Dockerfile 并升级基础镜像版本
b6db694
Raw
History Blame Contribute Delete
4.53 kB
"""
网络工具
处理Git克隆、文件下载等
"""
import os
import tempfile
import logging
from pathlib import Path
from typing import Optional, Tuple, Callable
from urllib.parse import urlparse
import subprocess
logger = logging.getLogger(__name__)
class NetworkUtils:
"""网络工具类"""
@staticmethod
def clone_git_repository(repo_url: str, target_dir: Path, branch: str = "main") -> Tuple[bool, str]:
"""克隆Git仓库"""
try:
# 验证Git URL
if not NetworkUtils._is_valid_git_url(repo_url):
return False, "无效的Git仓库URL"
# 确保目标目录不存在或为空
if target_dir.exists():
# 如果目录存在且非空,先删除
if any(target_dir.iterdir()):
import shutil
shutil.rmtree(target_dir)
# 执行Git克隆命令
cmd = ["git", "clone", "--branch", branch, "--depth", "1", repo_url, str(target_dir)]
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=300 # 5分钟超时
)
if result.returncode == 0:
logger.info(f"成功克隆Git仓库: {repo_url} -> {target_dir}")
return True, "克隆成功"
else:
error_msg = result.stderr.strip()
logger.error(f"克隆Git仓库失败: {error_msg}")
return False, f"克隆失败: {error_msg}"
except subprocess.TimeoutExpired:
logger.error("克隆Git仓库超时")
return False, "克隆超时,请检查网络连接"
except Exception as e:
logger.error(f"克隆Git仓库异常: {e}")
return False, f"克隆异常: {str(e)}"
@staticmethod
def _is_valid_git_url(url: str) -> bool:
"""验证Git URL格式"""
try:
parsed = urlparse(url)
if parsed.scheme in ('http', 'https', 'git'):
return True
# 支持SSH格式的URL
if url.startswith('git@') and '.git' in url:
return True
return False
except Exception:
return False
@staticmethod
def download_file(url: str, target_path: Path) -> Tuple[bool, str]:
"""下载文件"""
try:
import requests
response = requests.get(url, stream=True, timeout=30)
response.raise_for_status()
with open(target_path, 'wb') as f:
for chunk in response.iter_content(chunk_size=8192):
f.write(chunk)
logger.info(f"成功下载文件: {url} -> {target_path}")
return True, "下载成功"
except requests.RequestException as e:
logger.error(f"下载文件失败: {e}")
return False, f"下载失败: {str(e)}"
except Exception as e:
logger.error(f"下载文件异常: {e}")
return False, f"下载异常: {str(e)}"
@staticmethod
def get_git_info(repo_url: str) -> Tuple[bool, dict]:
"""获取Git仓库信息"""
try:
with tempfile.TemporaryDirectory() as temp_dir:
temp_path = Path(temp_dir)
# 克隆仓库(浅克隆以加快速度)
success, message = NetworkUtils.clone_git_repository(repo_url, temp_path)
if not success:
return False, {"error": message}
# 检查插件结构
from app.utils.file_utils import file_utils
valid, msg, metadata = file_utils.validate_plugin_structure(temp_path)
if valid:
return True, {
"name": metadata.get("name"),
"version": metadata.get("version"),
"description": metadata.get("description"),
"author": metadata.get("author")
}
else:
return False, {"error": msg}
except Exception as e:
logger.error(f"获取Git信息失败: {e}")
return False, {"error": str(e)}
# 创建全局实例
network_utils = NetworkUtils()