From 21ee44650980327ad4c6119849bc47c8aafeeb0f Mon Sep 17 00:00:00 2001 From: Eric Callahan Date: Sat, 7 Aug 2021 11:39:48 -0400 Subject: [PATCH] history: use the job_state module to manage job events Signed-off-by: Eric Callahan --- moonraker/components/history.py | 115 ++++++++++++++++---------------- 1 file changed, 59 insertions(+), 56 deletions(-) diff --git a/moonraker/components/history.py b/moonraker/components/history.py index aa6d486..08eadf6 100644 --- a/moonraker/components/history.py +++ b/moonraker/components/history.py @@ -3,7 +3,6 @@ # This file may be distributed under the terms of the GNU GPLv3 license. from __future__ import annotations -import logging import time # Annotation imports @@ -19,10 +18,9 @@ if TYPE_CHECKING: from confighelper import ConfigHelper from websockets import WebRequest from . import database - from . import klippy_apis + from .job_state import JobState from .file_manager import file_manager DBComp = database.MoonrakerDatabase - APIComp = klippy_apis.KlippyAPI FMComp = file_manager.FileManager HIST_NAMESPACE = "history" @@ -46,14 +44,20 @@ class History: 'longest_print': 0. }) - self.server.register_event_handler( - "server:klippy_ready", self._init_ready) - self.server.register_event_handler( - "server:status_update", self._status_update) self.server.register_event_handler( "server:klippy_disconnect", self._handle_disconnect) self.server.register_event_handler( "server:klippy_shutdown", self._handle_shutdown) + self.server.register_event_handler( + "job_state:started", self._on_job_started) + self.server.register_event_handler( + "job_state:complete", self._on_job_complete) + self.server.register_event_handler( + "job_state:cancelled", self._on_job_cancelled) + self.server.register_event_handler( + "job_state:standby", self._on_job_standby) + self.server.register_event_handler( + "job_state:error", self._on_job_error) self.server.register_notification("history:history_changed") self.server.register_endpoint( @@ -69,21 +73,11 @@ class History: self.current_job: Optional[PrinterJob] = None self.current_job_id: Optional[str] = None - self.print_stats: Dict[str, Any] = {} self.next_job_id: int = 0 self.cached_job_ids = self.history_ns.keys() if self.cached_job_ids: self.next_job_id = int(self.cached_job_ids[-1], 16) + 1 - async def _init_ready(self) -> None: - klippy_apis: APIComp = self.server.lookup_component('klippy_apis') - sub: Dict[str, Optional[List[str]]] = {"print_stats": None} - try: - result = await klippy_apis.subscribe_objects(sub) - except self.server.error as e: - logging.info(f"Error subscribing to print_stats") - self.print_stats = result.get("print_stats", {}) - async def _handle_job_request(self, web_request: WebRequest ) -> Dict[str, Any]: @@ -173,50 +167,50 @@ class History: ) -> Dict[str, Dict[str, float]]: return {'job_totals': self.job_totals} - async def _status_update(self, data: Dict[str, Any]) -> None: - ps = data.get("print_stats", {}) - if "state" in ps: - old_state: str = self.print_stats['state'] - new_state: str = ps['state'] - new_ps = dict(self.print_stats) - new_ps.update(ps) + def _on_job_started(self, + prev_stats: Dict[str, Any], + new_stats: Dict[str, Any] + ) -> None: + if self.current_job is not None: + # Finish with the previous state + self.finish_job("cancelled", prev_stats) + self.add_job(PrinterJob(new_stats)) - if new_state is not old_state: - if new_state == "printing" and self.current_job is None: - # always add new job if no existing job is present - self.add_job(PrinterJob(new_ps)) - elif self.current_job is not None: - if new_state == "complete": - self.finish_job("completed", new_ps) - elif new_state == "cancelled": - self.finish_job("cancelled", new_ps) - elif new_state == "standby": - # Backward compatibility with - # `CLEAR_PAUSE/SDCARD_RESET_FILE` workflow - self.finish_job("cancelled", self.print_stats) - elif new_state == "error": - self.finish_job("error", new_ps) - elif new_state == "printing" and \ - self._check_need_cancel(new_ps): - # Finish with the previous state - self.finish_job("cancelled", self.print_stats) - self.add_job(PrinterJob(new_ps)) + def _on_job_complete(self, + prev_stats: Dict[str, Any], + new_stats: Dict[str, Any] + ) -> None: + self.finish_job("completed", new_stats) - self.print_stats.update(ps) + def _on_job_cancelled(self, + prev_stats: Dict[str, Any], + new_stats: Dict[str, Any] + ) -> None: + self.finish_job("cancelled", new_stats) + + def _on_job_error(self, + prev_stats: Dict[str, Any], + new_stats: Dict[str, Any] + ) -> None: + self.finish_job("error", new_stats) + + def _on_job_standby(self, + prev_stats: Dict[str, Any], + new_stats: Dict[str, Any] + ) -> None: + # Backward compatibility with + # `CLEAR_PAUSE/SDCARD_RESET_FILE` workflow + self.finish_job("cancelled", prev_stats) def _handle_shutdown(self) -> None: - self.finish_job("klippy_shutdown", self.print_stats) + jstate: JobState = self.server.lookup_component("job_state") + last_ps = jstate.get_last_stats() + self.finish_job("klippy_shutdown", last_ps) def _handle_disconnect(self) -> None: - self.finish_job("klippy_disconnect", self.print_stats) - - def _check_need_cancel(self, new_stats: Dict[str, Any]) -> bool: - # Cancel if the file name has changed, total duration has - # decreased, or if job is not resuming from a pause - ps = self.print_stats - return ps['filename'] != new_stats['filename'] or \ - ps['total_duration'] > new_stats['total_duration'] or \ - ps['state'] != "paused" + jstate: JobState = self.server.lookup_component("job_state") + last_ps = jstate.get_last_stats() + self.finish_job("klippy_disconnect", last_ps) def add_job(self, job: PrinterJob) -> None: if len(self.cached_job_ids) >= MAX_JOBS: @@ -241,6 +235,13 @@ class History: def finish_job(self, status: str, pstats: Dict[str, Any]) -> None: if self.current_job is None: return + cj = self.current_job + if ( + pstats.get('filename') != cj.get('filename') or + pstats.get('total_duration', 0.) < cj.get('total_duration') + ): + # Print stats have been reset, do not update this job with them + pstats = {} self.current_job.finish(status, pstats) # Regrab metadata incase metadata wasn't parsed yet due to file upload @@ -318,7 +319,9 @@ class History: return job def on_exit(self) -> None: - self.finish_job("server_exit", self.print_stats) + jstate: JobState = self.server.lookup_component("job_state") + last_ps = jstate.get_last_stats() + self.finish_job("server_exit", last_ps) class PrinterJob: def __init__(self, data: Dict[str, Any] = {}) -> None: