-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathguardian_client.py
More file actions
106 lines (80 loc) · 2.88 KB
/
Copy pathguardian_client.py
File metadata and controls
106 lines (80 loc) · 2.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
"""Small named-pipe client used by Explorer launchers and management tools."""
from __future__ import annotations
import subprocess
import time
from multiprocessing.connection import Client
from typing import Any
from guardian_common import (
BROKER_PATH,
PIPE_ADDRESS,
RUNTIME_PYTHONW,
auth_key,
)
class GuardianUnavailable(RuntimeError):
pass
def request(message: dict[str, Any]) -> dict[str, Any]:
connection = Client(PIPE_ADDRESS, family="AF_PIPE", authkey=auth_key())
try:
connection.send(message)
response = connection.recv()
finally:
connection.close()
if not isinstance(response, dict):
raise GuardianUnavailable("Guardian returned an invalid response")
return response
def ping() -> dict[str, Any] | None:
try:
return request({"action": "ping"})
except (OSError, EOFError, ConnectionError, GuardianUnavailable):
return None
def ensure_broker(timeout: float = 15.0) -> dict[str, Any]:
status = ping()
if status:
return status
if not RUNTIME_PYTHONW.is_file():
raise GuardianUnavailable(f"Guardian runtime is missing: {RUNTIME_PYTHONW}")
subprocess.Popen(
[str(RUNTIME_PYTHONW), str(BROKER_PATH)],
close_fds=True,
creationflags=subprocess.DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP,
)
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
time.sleep(0.2)
status = ping()
if status:
return status
raise GuardianUnavailable("Python Guardian did not become ready")
def preflight(script: str) -> dict[str, Any]:
ensure_broker()
return request({"action": "preflight", "script": script})
def submit(script: str, interpreter: str, arguments: list[str], keep: str) -> dict[str, Any]:
ensure_broker()
return request(
{
"action": "submit",
"script": script,
"interpreter": interpreter,
"arguments": arguments,
"keep": keep,
}
)
def stop_broker() -> dict[str, Any]:
response = request({"action": "stop"})
# Wake Listener.accept() once more so its loop can observe stop_event.
try:
request({"action": "ping"})
except (OSError, EOFError, ConnectionError, GuardianUnavailable):
pass
return response
def job_status(job_id: str) -> dict[str, Any]:
return request({"action": "job", "job_id": job_id})
def start_repair(job_id: str) -> dict[str, Any]:
ensure_broker()
return request({"action": "repair", "job_id": job_id})
def repair_status(job_id: str) -> dict[str, Any]:
return request({"action": "repair_status", "job_id": job_id})
def retry_job(job_id: str) -> dict[str, Any]:
return request({"action": "retry", "job_id": job_id})
def undo_repair(job_id: str) -> dict[str, Any]:
return request({"action": "undo_repair", "job_id": job_id})