Disconnect at once after restart, reboot, quit or hibernate
The device goes down without answering, so the editor waited out the 30 s Sox timeout before dropping the session. The invoke now waits 3 s (time for DASP to resend it once) and the editor disconnects either way; an error reply from the device is still reported and keeps the connection. Covers the App right-click actions and the restart Put with Files offers. - sox: request/requests/invoke take a timeout Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -8,7 +8,7 @@ so later rebinding would only ever be seen by the module that did it.
|
||||
import configparser
|
||||
import os
|
||||
|
||||
VERSION = "0.0.0.167"
|
||||
VERSION = "0.0.0.168"
|
||||
PROPERTIES_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), "editor.properties")
|
||||
DEFAULT_GRID_SIZE = 10
|
||||
DEFAULT_ADD_TIMESTAMP = True
|
||||
|
||||
@@ -617,27 +617,35 @@ def _invoke_app_action(slot_name):
|
||||
if slot is None:
|
||||
app_state.set_status(f"Action slot '{slot_name}' not found on app", warn=True)
|
||||
return False
|
||||
goes_down = slot_name in ("hibernate", "quit", "restart", "reboot")
|
||||
goes_down = slot_name in _GOES_DOWN
|
||||
try:
|
||||
ds.sox_client.invoke(0, slot["id"])
|
||||
app_state.set_status(f"Invoked '{slot_name}' on device")
|
||||
# A device going down often does so before it answers: give the request a few
|
||||
# seconds (time for DASP to resend it once), then disconnect either way rather
|
||||
# than wait for the session to drop.
|
||||
ds.sox_client.invoke(0, slot["id"], timeout=_GOES_DOWN_WAIT if goes_down else 30.0)
|
||||
except sox.SoxException as e:
|
||||
# A P-ION restarts before it answers: no reply is what a restart looks like.
|
||||
if not (goes_down and "timeout" in str(e).lower()):
|
||||
refused = "timeout" not in str(e).lower() and "closed" not in str(e).lower()
|
||||
if not goes_down or refused:
|
||||
app_state.set_status(f"Invoke '{slot_name}' failed: {e}", warn=True)
|
||||
return False
|
||||
app_state.set_status(f"Invoked '{slot_name}'; the device went down without replying")
|
||||
except Exception as e:
|
||||
app_state.set_status(f"Invoke '{slot_name}' failed: {e}", warn=True)
|
||||
return False
|
||||
if slot_name == "save":
|
||||
app_state.mark_clean()
|
||||
app_state.set_status(f"Invoked '{slot_name}' on device")
|
||||
elif goes_down:
|
||||
host = app_state.device_host
|
||||
do_device_disconnect()
|
||||
app_state.set_status(f"Sent '{slot_name}' to {host} and disconnected")
|
||||
else:
|
||||
app_state.set_status(f"Invoked '{slot_name}' on device")
|
||||
return True
|
||||
|
||||
|
||||
_APP_ACTIONS = ["save", "hibernate", "quit", "restart", "reboot"]
|
||||
_GOES_DOWN = ("hibernate", "quit", "restart", "reboot") # the device stops answering
|
||||
_GOES_DOWN_WAIT = 3.0 # seconds to wait for its reply before disconnecting
|
||||
|
||||
|
||||
def do_get_with_file():
|
||||
@@ -871,7 +879,8 @@ def do_put_with_files():
|
||||
f"{len(plan.app_files) + len(plan.media)} files written to the device."
|
||||
f"{NL}{NL}Restart the device now to complete provisioning?"):
|
||||
if _invoke_app_action("restart"):
|
||||
app_state.set_status(f"Put {os.path.basename(path)}; the device is restarting")
|
||||
app_state.set_status(f"Put {os.path.basename(path)}; the device is "
|
||||
"restarting, disconnected")
|
||||
|
||||
_run_with_progress("Put with Files", prepare, planned)
|
||||
|
||||
|
||||
@@ -667,13 +667,13 @@ class SoxClient:
|
||||
|
||||
# ── Invoke Action ───────────────────────────────────────────
|
||||
|
||||
def invoke(self, comp_id, slot_id, type_id=None, arg=None):
|
||||
def invoke(self, comp_id, slot_id, type_id=None, arg=None, timeout=30.0):
|
||||
req = _prepare_request(ord('i'))
|
||||
req.write_u2(comp_id)
|
||||
req.write_u1(slot_id)
|
||||
if arg is not None and type_id is not None:
|
||||
encode_value(req, type_id, arg)
|
||||
res = self.request(req)
|
||||
res = self.request(req, timeout)
|
||||
res.check_response('I')
|
||||
|
||||
# ── Add Component ───────────────────────────────────────────
|
||||
@@ -1062,17 +1062,17 @@ class SoxClient:
|
||||
|
||||
# ── Networking ──────────────────────────────────────────────
|
||||
|
||||
def request(self, req):
|
||||
results = self.requests([req])
|
||||
def request(self, req, timeout=30.0):
|
||||
results = self.requests([req], timeout)
|
||||
return results[0]
|
||||
|
||||
def requests(self, reqs):
|
||||
def requests(self, reqs, timeout=30.0):
|
||||
"""Sends the batch and waits for every reply."""
|
||||
if self.is_closed:
|
||||
raise SoxException("SoxClient closed")
|
||||
|
||||
if len(reqs) > 255:
|
||||
return self._chunk_requests(reqs)
|
||||
return self._chunk_requests(reqs, timeout)
|
||||
|
||||
with self._lock:
|
||||
for i, req in enumerate(reqs):
|
||||
@@ -1085,7 +1085,7 @@ class SoxClient:
|
||||
for req in reqs:
|
||||
self._session.send(req.to_bytes())
|
||||
|
||||
deadline = time.monotonic() + 30.0
|
||||
deadline = time.monotonic() + timeout
|
||||
while True:
|
||||
remaining = deadline - time.monotonic()
|
||||
if remaining <= 0:
|
||||
@@ -1107,11 +1107,11 @@ class SoxClient:
|
||||
self._responses = None
|
||||
raise SoxException("Request timeout")
|
||||
|
||||
def _chunk_requests(self, reqs):
|
||||
def _chunk_requests(self, reqs, timeout=30.0):
|
||||
results = []
|
||||
for i in range(0, len(reqs), 255):
|
||||
chunk = reqs[i:i + 255]
|
||||
results.extend(self.requests(chunk))
|
||||
results.extend(self.requests(chunk, timeout))
|
||||
return results
|
||||
|
||||
# called by receiver thread
|
||||
|
||||
Reference in New Issue
Block a user