necst.web.operator_console

HTTP helpers for the NECST Operator Console.

This module is the thin boundary between the browser-facing Operator Console and the shared read-only status / operator action layers. It deliberately keeps validation and command dispatch small and explicit:

  • read-only status is built from status_model;

  • write-like actions are sent only through necst.core.operator_actions;

  • unimplemented or site-disabled actions are rejected before any telescope command can be sent.

class ConsoleLogEntry(time, ok, message, action='', session_id='', data=<factory>)[source]

Bases: object

One operator-log line displayed in the browser and JSONL log.

Parameters:
  • time (str) –

  • ok (bool) –

  • message (str) –

  • action (str) –

  • session_id (str) –

  • data (Dict[str, Any]) –

time: str
ok: bool
message: str
action: str = ''
session_id: str = ''
data: Dict[str, Any]
class ConsoleAuthorityState(held=False, session_id=None, necst_held=False, necst_identity=None, mode='none', note='')[source]

Bases: object

Operator-console authority state.

held and session_id are the browser/session gate. When running in live mode, necst_held means this console process also holds actual NECST authority through a persistent Commander. Observation/RSky/SkyDip launchers run as separate processes, so the console must release actual authority before starting them to avoid blocking the child process.

Parameters:
  • held (bool) –

  • session_id (Optional[str]) –

  • necst_held (bool) –

  • necst_identity (Optional[str]) –

  • mode (str) –

  • note (str) –

held: bool = False
session_id: Optional[str] = None
necst_held: bool = False
necst_identity: Optional[str] = None
mode: str = 'none'
note: str = ''
class OperatorConsoleState(telescope, progress_root, progress_url, progress_monitor=None, action_mode='live', live_actions_enabled=True, status_refresh_ms=1000, status_no_ros=False, quiet=False, events_limit=12, site_summary=<factory>, mount_limits=<factory>, site_capabilities=<factory>, chopper_config=<factory>, live_cache=None, observation_log=None, operator_log_path=None, launcher_log_dir=None, obs_roots=<factory>, process_registry=<factory>, log=<factory>, authority=<factory>, authority_handle=None, last_command_az=None, last_command_el=None, last_mount_target_az=None, last_mount_target_el=None, last_mount_target_started_at=None, last_mount_target_reached_since=None, last_safety_release_requested_at=None, last_manual_state='idle', last_active_task='none', last_observation_abort_requested_at=None, last_observation_stop_requested_at=None, last_observation_safety_labels=<factory>, last_chopper_state='unknown', last_chopper_position=None, shutdown_requested=False, cleanup_started_at=None, cleanup_finished_at=None, cleanup_status='not_started', cleanup_summary=<factory>, shutdown_terminate_launchers=True, shutdown_launcher_timeout_sec=3.0, shutdown_launcher_kill_timeout_sec=1.0, exclusive_start_action=None, exclusive_start_session_id=None, exclusive_start_started_at=None, exclusive_start_message='', safe_start=False, rescue_mode=False, local_state_reset_archive=None, local_state_reset_summary=<factory>, last_status_exception_message='', last_status_exception_at=None, node_health_cache=<factory>, node_health_checked_at_unix=0.0, last_node_health_event_key='', last_launcher_failure=<factory>, lock=<factory>)[source]

Bases: object

Mutable server state that is not part of NECST telemetry.

Parameters:
  • telescope (str) –

  • progress_root (Path) –

  • progress_url (str) –

  • progress_monitor (Optional[ProgressMonitorManager]) –

  • action_mode (str) –

  • live_actions_enabled (bool) –

  • status_refresh_ms (int) –

  • status_no_ros (bool) –

  • quiet (bool) –

  • events_limit (int) –

  • site_summary (SiteConfigSummary) –

  • mount_limits (Dict[str, float]) –

  • site_capabilities (Dict[str, bool]) –

  • chopper_config (Dict[str, Any]) –

  • live_cache (Optional[LiveTelemetryCache]) –

  • observation_log (Optional[ObservationLogManager]) –

  • operator_log_path (Optional[Path]) –

  • launcher_log_dir (Optional[Path]) –

  • obs_roots (List[Path]) –

  • process_registry (ProcessRegistry) –

  • log (List[ConsoleLogEntry]) –

  • authority (ConsoleAuthorityState) –

  • authority_handle (Any) –

  • last_command_az (Optional[float]) –

  • last_command_el (Optional[float]) –

  • last_mount_target_az (Optional[float]) –

  • last_mount_target_el (Optional[float]) –

  • last_mount_target_started_at (Optional[float]) –

  • last_mount_target_reached_since (Optional[float]) –

  • last_safety_release_requested_at (Optional[float]) –

  • last_manual_state (str) –

  • last_active_task (str) –

  • last_observation_abort_requested_at (Optional[float]) –

  • last_observation_stop_requested_at (Optional[float]) –

  • last_observation_safety_labels (List[str]) –

  • last_chopper_state (str) –

  • last_chopper_position (Optional[float]) –

  • shutdown_requested (bool) –

  • cleanup_started_at (Optional[float]) –

  • cleanup_finished_at (Optional[float]) –

  • cleanup_status (str) –

  • cleanup_summary (Dict[str, Any]) –

  • shutdown_terminate_launchers (bool) –

  • shutdown_launcher_timeout_sec (float) –

  • shutdown_launcher_kill_timeout_sec (float) –

  • exclusive_start_action (Optional[str]) –

  • exclusive_start_session_id (Optional[str]) –

  • exclusive_start_started_at (Optional[float]) –

  • exclusive_start_message (str) –

  • safe_start (bool) –

  • rescue_mode (bool) –

  • local_state_reset_archive (Optional[str]) –

  • local_state_reset_summary (Dict[str, Any]) –

  • last_status_exception_message (str) –

  • last_status_exception_at (Optional[float]) –

  • node_health_cache (Dict[str, Any]) –

  • node_health_checked_at_unix (float) –

  • last_node_health_event_key (str) –

  • last_launcher_failure (Dict[str, Any]) –

  • lock (RLock) –

telescope: str
progress_root: Path
progress_url: str
progress_monitor: Optional[ProgressMonitorManager] = None
action_mode: str = 'live'
live_actions_enabled: bool = True
status_refresh_ms: int = 1000
status_no_ros: bool = False
quiet: bool = False
events_limit: int = 12
site_summary: SiteConfigSummary
mount_limits: Dict[str, float]
site_capabilities: Dict[str, bool]
chopper_config: Dict[str, Any]
live_cache: Optional[LiveTelemetryCache] = None
observation_log: Optional[ObservationLogManager] = None
operator_log_path: Optional[Path] = None
launcher_log_dir: Optional[Path] = None
obs_roots: List[Path]
process_registry: ProcessRegistry
log: List[ConsoleLogEntry]
authority: ConsoleAuthorityState
authority_handle: Any = None
last_command_az: Optional[float] = None
last_command_el: Optional[float] = None
last_mount_target_az: Optional[float] = None
last_mount_target_el: Optional[float] = None
last_mount_target_started_at: Optional[float] = None
last_mount_target_reached_since: Optional[float] = None
last_safety_release_requested_at: Optional[float] = None
last_manual_state: str = 'idle'
last_active_task: str = 'none'
last_observation_abort_requested_at: Optional[float] = None
last_observation_stop_requested_at: Optional[float] = None
last_observation_safety_labels: List[str]
last_chopper_state: str = 'unknown'
last_chopper_position: Optional[float] = None
shutdown_requested: bool = False
cleanup_started_at: Optional[float] = None
cleanup_finished_at: Optional[float] = None
cleanup_status: str = 'not_started'
cleanup_summary: Dict[str, Any]
shutdown_terminate_launchers: bool = True
shutdown_launcher_timeout_sec: float = 3.0
shutdown_launcher_kill_timeout_sec: float = 1.0
exclusive_start_action: Optional[str] = None
exclusive_start_session_id: Optional[str] = None
exclusive_start_started_at: Optional[float] = None
exclusive_start_message: str = ''
safe_start: bool = False
rescue_mode: bool = False
local_state_reset_archive: Optional[str] = None
local_state_reset_summary: Dict[str, Any]
last_status_exception_message: str = ''
last_status_exception_at: Optional[float] = None
node_health_cache: Dict[str, Any]
node_health_checked_at_unix: float = 0.0
last_node_health_event_key: str = ''
last_launcher_failure: Dict[str, Any]
lock: RLock
add_log(ok, message, *, action='', session_id='', data=None)[source]
Parameters:
  • ok (bool) –

  • message (str) –

  • action (str) –

  • session_id (str) –

  • data (Optional[Mapping[str, Any]]) –

Return type:

None

resolve_site_summary(*, site_config_path=None, az_min=None, az_max=None, el_min=None, el_max=None)[source]

Resolve active site settings for console display and validation.

Parameters:
  • site_config_path (Optional[Union[PathLike[str], str]]) –

  • az_min (Optional[float]) –

  • az_max (Optional[float]) –

  • el_min (Optional[float]) –

  • el_max (Optional[float]) –

Return type:

SiteConfigSummary

resolve_mount_limits(*, az_min=None, az_max=None, el_min=None, el_max=None, site_config_path=None)[source]

Resolve mount limits from site config, then CLI fallback values.

Parameters:
  • az_min (Optional[float]) –

  • az_max (Optional[float]) –

  • el_min (Optional[float]) –

  • el_max (Optional[float]) –

  • site_config_path (Optional[Union[PathLike[str], str]]) –

Return type:

Dict[str, float]

validate_mount_target(params, mount_limits)[source]

Validate mount mechanical Az/El in degrees using site TOML limits.

Parameters:
  • params (Mapping[str, Any]) –

  • mount_limits (Mapping[str, Any]) –

Return type:

Tuple[float, float]

validate_observation_selection(params)[source]

Static obs-file selection validation; does not touch hardware.

Parameters:

params (Mapping[str, Any]) –

Return type:

Tuple[str, str, Optional[int]]

resolve_obs_roots(configured_roots=None)[source]

Return NECST-side browse roots for preview and obs selection.

If --obs-root or NECST_CONSOLE_OBS_ROOTS is supplied, those paths define the chooser locations. Otherwise the console provides practical defaults visible to the process running the console, including Home, common obs/data directories, the current directory, and /. This makes the chooser usable without command-line options while still allowing a site to restrict it explicitly.

Parameters:

configured_roots (Optional[List[os.PathLike[str] | str]]) –

Return type:

List[Path]

obs_roots_payload(roots)[source]
Parameters:

roots (List[Path]) –

Return type:

Dict[str, Any]

list_server_obs_files(roots, directory='')[source]
Parameters:
  • roots (List[Path]) –

  • directory (str) –

Return type:

Dict[str, Any]

preview_server_obs_file(roots, path, *, max_bytes=65536)[source]
Parameters:
  • roots (List[Path]) –

  • path (str) –

  • max_bytes (int) –

Return type:

Dict[str, Any]

validate_site_capability(state, capability, *, action_label=None)[source]

Reject actions disabled by the active site config before command dispatch.

Parameters:
Return type:

None

chopper_dry_run_payload(state, command)[source]

Return dry-run details using configured chopper endpoints.

Parameters:
Return type:

Dict[str, Any]

run_self_check(state, *, include_progress_health=True)[source]

Run read-only console self-checks without sending telescope commands.

Parameters:
Return type:

Dict[str, Any]

reset_local_console_state_files(*, progress_root, operator_log_dir, reason='operator request')[source]

Archive only local console/progress state files.

This never sends telescope, recorder, spectrometer, or ROS commands. It is intentionally limited to files that can make the web console believe a stale observation is still current after an interrupted previous run.

Parameters:
  • progress_root (os.PathLike[str] | str) –

  • operator_log_dir (os.PathLike[str] | str) –

  • reason (str) –

Return type:

Dict[str, Any]

dispatch_action(state, action, params, session_id)[source]

Validate and dispatch one browser action.

Return (ok, message, data). Invalid or not-yet-connected actions return ok=False before any operator command is sent.

Parameters:
  • state (OperatorConsoleState) –

  • action (str) –

  • params (Mapping[str, Any]) –

  • session_id (str) –

Return type:

Tuple[bool, str, Dict[str, Any]]

build_minimal_rescue_status(state, exc)[source]

Return a status payload that is deliberately hard to break.

The browser must keep showing STOP/ABORT and local recovery controls even if the normal status builder has a bug or a corrupted local pointer file.

Parameters:
Return type:

Dict[str, Any]

build_console_status(state)[source]
Parameters:

state (OperatorConsoleState) –

Return type:

Dict[str, Any]

load_demo_html(status_refresh_ms=1000)[source]

Load the v7 demo HTML so the real console keeps the approved layout.

Parameters:

status_refresh_ms (int) –

Return type:

str

class OperatorConsoleHTTPServer(server_address, handler_class, *, state, html=None)[source]

Bases: ThreadingHTTPServer

Parameters:
  • server_address (Tuple[str, int]) –

  • handler_class (type[BaseHTTPRequestHandler]) –

  • state (OperatorConsoleState) –

  • html (Optional[str]) –

daemon_threads = True
allow_reuse_address = True
class OperatorConsoleHandler(request, client_address, server)[source]

Bases: BaseHTTPRequestHandler

Parameters:

server (OperatorConsoleHTTPServer) –

server: OperatorConsoleHTTPServer
log_message(fmt, *args)[source]

Log an arbitrary message.

This is used by all other logging functions. Override it if you have specific logging wishes.

The first argument, FORMAT, is a format string for the message to be logged. If the format string contains any % escapes requiring parameters, they should be specified as subsequent arguments (it’s just like printf!).

The client ip and current date/time are prefixed to every message.

Unicode control characters are replaced with escaped hex before writing the output to stderr.

Parameters:
  • fmt (str) –

  • args (Any) –

Return type:

None

do_GET()[source]
Return type:

None

do_POST()[source]
Return type:

None

run_server(*, host, port, telescope, progress_root, progress_url, progress_host='127.0.0.1', progress_port=8091, progress_refresh_ms=500, progress_no_ros=False, progress_log_dir=None, obs_roots=None, status_no_ros=False, action_mode='live', live_actions_enabled=True, status_refresh_ms=1000, quiet=False, open_browser=False, events_limit=12, site_config_path=None, operator_log_dir=None, launcher_log_dir=None, obslog_dir=None, obslog_prefix=None, obslog_user=None, shutdown_terminate_launchers=True, shutdown_launcher_timeout_sec=3.0, shutdown_launcher_kill_timeout_sec=1.0, safe_start=False, reset_local_state=False, rescue=False, az_min=None, az_max=None, el_min=None, el_max=None, stop_event=None)[source]
Parameters:
  • host (str) –

  • port (int) –

  • telescope (str) –

  • progress_root (Path) –

  • progress_url (str) –

  • progress_host (str) –

  • progress_port (int) –

  • progress_refresh_ms (int) –

  • progress_no_ros (bool) –

  • progress_log_dir (Optional[Union[PathLike[str], str]]) –

  • obs_roots (Optional[List[os.PathLike[str] | str]]) –

  • status_no_ros (bool) –

  • action_mode (str) –

  • live_actions_enabled (bool) –

  • status_refresh_ms (int) –

  • quiet (bool) –

  • open_browser (bool) –

  • events_limit (int) –

  • site_config_path (Optional[Union[PathLike[str], str]]) –

  • operator_log_dir (Optional[Union[PathLike[str], str]]) –

  • launcher_log_dir (Optional[Union[PathLike[str], str]]) –

  • obslog_dir (Optional[Union[PathLike[str], str]]) –

  • obslog_prefix (Optional[str]) –

  • obslog_user (Optional[str]) –

  • shutdown_terminate_launchers (bool) –

  • shutdown_launcher_timeout_sec (float) –

  • shutdown_launcher_kill_timeout_sec (float) –

  • safe_start (bool) –

  • reset_local_state (bool) –

  • rescue (bool) –

  • az_min (Optional[float]) –

  • az_max (Optional[float]) –

  • el_min (Optional[float]) –

  • el_max (Optional[float]) –

  • stop_event (Optional[Event]) –

Return type:

int