| 28 | |
| 29 | |
| 30 | class UpdateService: |
| 31 | # NOTE: 提供暂停/恢复更新的高层接口;时间策略来自配置或默认值,保证幂等调用 |
| 32 | |
| 33 | def __init__(self, registry: RegistryAdapter) -> None: |
| 34 | self.registry = registry |
| 35 | |
| 36 | def pause(self, max_days: int, start_iso: str, end_iso: str) -> Result: |
| 37 | start = time.perf_counter() |
| 38 | log_event(logging.INFO, "update_pause_started", "开始暂停更新", action="pause_updates", status="started") |
| 39 | cmds = [ |
| 40 | f'reg add "{UPDATE}" /v "FlightSettingsMaxPauseDays" /t REG_DWORD /d {max_days} /f', |
| 41 | f'reg add "{UPDATE}" /v "PauseFeatureUpdatesStartTime" /t REG_SZ /d "{start_iso}" /f', |
| 42 | f'reg add "{UPDATE}" /v "PauseFeatureUpdatesEndTime" /t REG_SZ /d "{end_iso}" /f', |
| 43 | f'reg add "{UPDATE}" /v "PauseQualityUpdatesStartTime" /t REG_SZ /d "{start_iso}" /f', |
| 44 | f'reg add "{UPDATE}" /v "PauseQualityUpdatesEndTime" /t REG_SZ /d "{end_iso}" /f', |
| 45 | f'reg add "{UPDATE}" /v "PauseUpdatesStartTime" /t REG_SZ /d "{start_iso}" /f', |
| 46 | f'reg add "{UPDATE}" /v "PauseUpdatesExpiryTime" /t REG_SZ /d "{end_iso}" /f', |
| 47 | ] |
| 48 | ok, errors = self.registry.batch(cmds) |
| 49 | duration_ms = int((time.perf_counter() - start) * 1000) |
| 50 | if ok: |
| 51 | log_event(logging.INFO, "update_pause_finished", "暂停更新完成", action="pause_updates", status="ok", duration_ms=duration_ms) |
| 52 | return Result(True, data={"status": "paused", "effective_until": end_iso}) |
| 53 | log_event( |
| 54 | logging.ERROR, |
| 55 | "update_pause_finished", |
| 56 | "暂停更新失败", |
| 57 | action="pause_updates", |
| 58 | status="failed", |
| 59 | duration_ms=duration_ms, |
| 60 | error_type="REGISTRY_WRITE_FAILED", |
| 61 | error_message="; ".join(errors), |
| 62 | ) |
| 63 | return Result(False, error={"code": "REGISTRY_WRITE_FAILED", "message": "部分键写入失败", "details": errors}) |
| 64 | |
| 65 | def resume(self) -> Result: |
| 66 | start = time.perf_counter() |
| 67 | log_event(logging.INFO, "update_resume_started", "开始恢复更新", action="resume_updates", status="started") |
| 68 | cmds = [ |
| 69 | f'reg delete "{UPDATE}" /v "FlightSettingsMaxPauseDays" /f', |
| 70 | f'reg delete "{UPDATE}" /v "PauseFeatureUpdatesStartTime" /f', |
| 71 | f'reg delete "{UPDATE}" /v "PauseFeatureUpdatesEndTime" /f', |
| 72 | f'reg delete "{UPDATE}" /v "PauseQualityUpdatesStartTime" /f', |
| 73 | f'reg delete "{UPDATE}" /v "PauseQualityUpdatesEndTime" /f', |
| 74 | f'reg delete "{UPDATE}" /v "PauseUpdatesStartTime" /f', |
| 75 | f'reg delete "{UPDATE}" /v "PauseUpdatesExpiryTime" /f', |
| 76 | ] |
| 77 | ok, errors = self.registry.batch(cmds) |
| 78 | duration_ms = int((time.perf_counter() - start) * 1000) |
| 79 | if ok: |
| 80 | log_event(logging.INFO, "update_resume_finished", "恢复更新完成", action="resume_updates", status="ok", duration_ms=duration_ms) |
| 81 | return Result(True, data={"status": "resumed"}) |
| 82 | log_event( |
| 83 | logging.ERROR, |
| 84 | "update_resume_finished", |
| 85 | "恢复更新失败", |
| 86 | action="resume_updates", |
| 87 | status="failed", |