json rpc commander 封装

This commit is contained in:
root
2025-07-11 21:27:17 +08:00
parent 2a16067367
commit 7b50c6e28e
37 changed files with 3518 additions and 2596 deletions

View File

@@ -0,0 +1,22 @@
#!/usr/bin/env python3
"""
进度管理模块
"""
from .types import ProgressInfo, TaskResult
from .task import ProgressiveTask
from .reporter import ProgressReporter
from .generator import ProgressGenerator
from .decorators import with_progress
from .commander import ProgressJSONRPCCommander, create_progress_commander
__all__ = [
"ProgressInfo",
"TaskResult",
"ProgressiveTask",
"ProgressReporter",
"ProgressGenerator",
"with_progress",
"ProgressJSONRPCCommander",
"create_progress_commander"
]

View File

@@ -0,0 +1,216 @@
#!/usr/bin/env python3
"""
带进度的JSON-RPC Commander
"""
import time
from abc import abstractmethod
from typing import Dict, Any, Callable
from contextlib import contextmanager
from .types import ProgressInfo, TaskResult
from .task import ProgressiveTask
from .reporter import ProgressReporter
from ..commander import JSONRPCCommander
from ..logger import logger
class ProgressJSONRPCCommander(JSONRPCCommander):
"""带进度条的JSON-RPC Commander基类"""
def __init__(self, service_name: str):
super().__init__(service_name)
self.progress_reporter = ProgressReporter(service_name)
@contextmanager
def create_task(self, task_name: str, total_steps: int = 100):
"""创建带进度的任务上下文"""
task = ProgressiveTask(task_name, total_steps)
task.set_progress_callback(self.progress_reporter.report_progress)
try:
task.start()
yield task
task.finish()
except Exception as e:
task._report_progress(f"任务失败: {str(e)}")
raise
def execute_progressive_command(self, command: str, args: Dict[str, Any]) -> TaskResult:
"""
执行带进度的命令
Args:
command: 命令名称
args: 命令参数
Returns:
任务结果
"""
start_time = time.time()
try:
# 调用子类实现的进度命令执行
result = self._execute_with_progress(command, args)
total_time = time.time() - start_time
return TaskResult(
success=True,
result=result,
total_time=total_time
)
except Exception as e:
total_time = time.time() - start_time
logger.error(f"Progressive command failed: {e}")
return TaskResult(
success=False,
error=str(e),
total_time=total_time
)
@abstractmethod
def _execute_with_progress(self, command: str, args: Dict[str, Any]) -> Any:
"""
执行带进度的命令 - 子类必须实现
Args:
command: 命令名称
args: 命令参数
Returns:
命令执行结果
"""
pass
def execute_command(self, command: str, args: Dict[str, Any]) -> Any:
"""
执行命令(重写基类方法以支持进度)
Args:
command: 命令名称
args: 命令参数
Returns:
命令执行结果
"""
# 先进行参数类型转换
converted_args = self._convert_args_types(command, args)
# 检查是否是需要进度报告的命令
if self._is_progressive_command(command):
task_result = self.execute_progressive_command(command, converted_args)
if task_result.success:
return task_result.result
else:
raise Exception(task_result.error)
else:
# 普通命令,调用子类实现
return self._execute_simple_command(command, converted_args)
def _convert_args_types(self, command: str, args: Dict[str, Any]) -> Dict[str, Any]:
"""
转换参数类型
Args:
command: 命令名称
args: 原始参数
Returns:
转换后的参数
"""
if command not in self.commands:
return args
command_config = self.commands[command]
converted_args = args.copy()
# 转换可选参数的类型
for arg_name, arg_config in command_config.optional_args.items():
if arg_name in converted_args:
arg_type = arg_config.get('type', str)
try:
if arg_type == bool:
# 布尔类型特殊处理
value = converted_args[arg_name]
if isinstance(value, str):
converted_args[arg_name] = value.lower() in ('true', '1', 'yes', 'on')
elif arg_type != str and isinstance(converted_args[arg_name], str):
# 其他类型从字符串转换
converted_args[arg_name] = arg_type(converted_args[arg_name])
except (ValueError, TypeError) as e:
logger.warning(f"Failed to convert argument {arg_name}: {e}")
return converted_args
def _is_progressive_command(self, command: str) -> bool:
"""
判断是否是需要进度报告的命令
子类可以重写此方法来指定哪些命令需要进度报告
Args:
command: 命令名称
Returns:
是否需要进度报告
"""
# 默认所有命令都需要进度报告
return True
def _execute_simple_command(self, command: str, args: Dict[str, Any]) -> Any:
"""
执行简单命令(不需要进度报告)
子类可以重写此方法来处理不需要进度的命令
Args:
command: 命令名称
args: 命令参数
Returns:
命令执行结果
"""
# 默认调用带进度的执行方法
return self._execute_with_progress(command, args)
# 便捷函数
def create_progress_commander(service_name: str):
"""创建带进度的JSON-RPC Commander"""
class SimpleProgressCommander(ProgressJSONRPCCommander):
def __init__(self):
super().__init__(service_name)
self.command_handlers: Dict[str, Callable] = {}
self._progressive_commands = set()
def _register_commands(self):
pass
def add_command(self, name: str, handler: Callable, description: str,
required_args: list = None, optional_args: dict = None,
progressive: bool = True):
"""添加命令"""
self.register_command(name, description, required_args, optional_args)
self.command_handlers[name] = handler
# 标记是否需要进度报告
if progressive:
self._progressive_commands.add(name)
def _is_progressive_command(self, command: str) -> bool:
return command in self._progressive_commands
def _execute_with_progress(self, command: str, args: Dict[str, Any]) -> Any:
if command in self.command_handlers:
return self.command_handlers[command](**args)
else:
raise ValueError(f"No handler for command: {command}")
def _execute_simple_command(self, command: str, args: Dict[str, Any]) -> Any:
if command in self.command_handlers:
return self.command_handlers[command](**args)
else:
raise ValueError(f"No handler for command: {command}")
return SimpleProgressCommander()

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env python3
"""
进度装饰器
"""
def with_progress(total_steps: int = 100, task_name: str = None):
"""
为函数添加进度报告的装饰器
Args:
total_steps: 总步数
task_name: 任务名称
"""
def decorator(func):
def wrapper(self, *args, **kwargs):
name = task_name or func.__name__
if hasattr(self, 'create_task'):
with self.create_task(name, total_steps) as task:
# 将task对象传递给函数
return func(self, task, *args, **kwargs)
else:
# 如果不是ProgressJSONRPCCommander直接执行
return func(self, *args, **kwargs)
return wrapper
return decorator

View File

@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""
进度生成器工具
"""
from .task import ProgressiveTask
class ProgressGenerator:
"""进度生成器工具类"""
@staticmethod
def for_iterable(iterable, task: ProgressiveTask, description: str = "处理中"):
"""为可迭代对象添加进度报告"""
total = len(iterable) if hasattr(iterable, '__len__') else 100
task.total_steps = total
for i, item in enumerate(iterable):
task.update(i, f"{description} {i+1}/{total}")
yield item
task.finish(f"{description}完成")
@staticmethod
def for_range(start: int, end: int, task: ProgressiveTask, description: str = "处理中"):
"""为范围添加进度报告"""
total = end - start
task.total_steps = total
for i in range(start, end):
task.update(i - start, f"{description} {i+1}/{total}")
yield i
task.finish(f"{description}完成")
@staticmethod
def for_steps(steps: int, task: ProgressiveTask, description: str = "处理中"):
"""为步数添加进度报告"""
task.total_steps = steps
for i in range(steps):
task.update(i, f"{description} {i+1}/{steps}")
yield i
task.finish(f"{description}完成")

View File

@@ -0,0 +1,58 @@
#!/usr/bin/env python3
"""
进度报告器
"""
from .types import ProgressInfo
from ..jsonrpc import create_progress_reporter
from ..logger import logger
class ProgressReporter:
"""进度报告器"""
def __init__(self, service_name: str):
self.service_name = service_name
self.rpc_progress_reporter = None
self._setup_progress_reporter()
def _setup_progress_reporter(self) -> None:
"""设置进度报告器"""
try:
self.rpc_progress_reporter = create_progress_reporter()
logger.debug(f"Progress reporter initialized for {self.service_name}")
except Exception as e:
logger.warning(f"Failed to initialize progress reporter: {e}")
self.rpc_progress_reporter = None
def report_progress(self, progress: ProgressInfo) -> None:
"""报告进度"""
if self.rpc_progress_reporter:
# JSON-RPC进度报告
self.rpc_progress_reporter.report(
step=self.service_name,
progress=progress.percentage / 100.0, # 转换为0-1范围
message=progress.message,
details={
"current": progress.current,
"total": progress.total,
"elapsed_time": progress.elapsed_time,
"estimated_remaining": progress.estimated_remaining
}
)
else:
# 简单的控制台输出
print(f"Progress: {progress.percentage:.1f}% - {progress.message}")
def report_step(self, step_name: str, message: str) -> None:
"""报告步骤"""
if self.rpc_progress_reporter:
self.rpc_progress_reporter.step(step_name, message)
else:
print(f"Step: {step_name} - {message}")
def report_complete(self, message: str = "完成") -> None:
"""报告完成"""
if self.rpc_progress_reporter:
self.rpc_progress_reporter.complete(message)
else:
print(f"Complete: {message}")

View File

@@ -0,0 +1,69 @@
#!/usr/bin/env python3
"""
渐进式任务管理
"""
import time
from typing import Optional, Callable
from .types import ProgressInfo
from ..logger import logger
class ProgressiveTask:
"""渐进式任务包装器"""
def __init__(self, task_name: str, total_steps: int = 100):
self.task_name = task_name
self.total_steps = total_steps
self.current_step = 0
self.start_time = None
self.progress_callback: Optional[Callable[[ProgressInfo], None]] = None
def set_progress_callback(self, callback: Callable[[ProgressInfo], None]):
"""设置进度回调"""
self.progress_callback = callback
def start(self):
"""开始任务"""
self.start_time = time.time()
self.current_step = 0
self._report_progress("任务开始")
logger.debug(f"Task started: {self.task_name}")
def update(self, step: int = None, message: str = ""):
"""更新进度"""
if step is not None:
self.current_step = step
else:
self.current_step += 1
self._report_progress(message)
def finish(self, message: str = "任务完成"):
"""完成任务"""
self.current_step = self.total_steps
self._report_progress(message)
logger.debug(f"Task finished: {self.task_name}")
def _report_progress(self, message: str):
"""报告进度"""
if self.progress_callback and self.start_time:
elapsed = time.time() - self.start_time
# 估算剩余时间
if self.current_step > 0:
avg_time_per_step = elapsed / self.current_step
remaining_steps = self.total_steps - self.current_step
estimated_remaining = avg_time_per_step * remaining_steps
else:
estimated_remaining = 0.0
progress = ProgressInfo(
current=self.current_step,
total=self.total_steps,
message=message,
elapsed_time=elapsed,
estimated_remaining=estimated_remaining
)
self.progress_callback(progress)

View File

@@ -0,0 +1,31 @@
#!/usr/bin/env python3
"""
进度相关的数据类型定义
"""
from dataclasses import dataclass
from typing import Any, Optional
@dataclass
class ProgressInfo:
"""进度信息"""
current: int
total: int
message: str = ""
percentage: float = 0.0
elapsed_time: float = 0.0
estimated_remaining: float = 0.0
def __post_init__(self):
"""计算百分比"""
if self.total > 0:
self.percentage = (self.current / self.total) * 100
@dataclass
class TaskResult:
"""任务结果"""
success: bool
result: Any = None
error: str = None
total_time: float = 0.0
final_progress: Optional[ProgressInfo] = None