fix: correct DirSize/MD5 polling — initial_delay=0 and MD5 status v1
Live NAS investigation (test_dirsize_md5.py) revealed two bugs: 1. _poll_task() always slept 200ms before the first status call. DirSize and MD5 complete near-instantly on small data, so the result window closes before the first poll. Fix: add initial_delay parameter (default 0.2s for CopyMove/Delete/Compress/Extract); DirSize and MD5 pass initial_delay=0.0 to poll immediately after start. 2. get_md5 used status version=2, but the NAS only serves the result on status v1 (v2 always returns 599 regardless of timing). Fix: change _poll_task version to 1 for SYNO.FileStation.MD5. MD5 is one-shot: the result is consumed on the first successful status read. Polling at 0ms ensures we catch it before it expires. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -61,13 +61,21 @@ def register_filestation(
|
||||
|
||||
# ── internal polling helper ───────────────────────────────────────────
|
||||
|
||||
async def _poll_task(api: str, version: int, taskid: str) -> tuple[bool, dict[str, Any] | str]:
|
||||
"""Poll a DSM async task (CopyMove / Delete) until finished or timeout.
|
||||
async def _poll_task(
|
||||
api: str,
|
||||
version: int,
|
||||
taskid: str,
|
||||
initial_delay: float = 0.2,
|
||||
) -> tuple[bool, dict[str, Any] | str]:
|
||||
"""Poll a DSM async task until finished or timeout.
|
||||
|
||||
Args:
|
||||
api: DSM API name (e.g. "SYNO.FileStation.CopyMove").
|
||||
version: API version to use for the status call.
|
||||
taskid: Task ID returned by the corresponding start method.
|
||||
initial_delay: Seconds to wait before the first status poll.
|
||||
Set to 0.0 for tasks that may finish before the first poll
|
||||
interval (e.g. DirSize on small directories, MD5 on small files).
|
||||
|
||||
Returns:
|
||||
``(True, status_dict)`` on success, or ``(False, "Error: …")`` on
|
||||
@@ -76,13 +84,13 @@ def register_filestation(
|
||||
from mcp_synology_filestation.client import SynologyError as _SynologyError
|
||||
|
||||
delay = 0.2
|
||||
elapsed = 0.0
|
||||
elapsed = initial_delay
|
||||
timeout = 60.0
|
||||
|
||||
while True:
|
||||
await asyncio.sleep(delay)
|
||||
elapsed += delay
|
||||
if initial_delay > 0:
|
||||
await asyncio.sleep(initial_delay)
|
||||
|
||||
while True:
|
||||
try:
|
||||
status_data = await client.request(
|
||||
api,
|
||||
@@ -102,6 +110,8 @@ def register_filestation(
|
||||
"Error: Operation timed out after 60 seconds — check NAS manually.",
|
||||
)
|
||||
|
||||
await asyncio.sleep(delay)
|
||||
elapsed += delay
|
||||
delay = min(delay * 2, 2.0)
|
||||
|
||||
@mcp.tool()
|
||||
@@ -805,7 +815,7 @@ def register_filestation(
|
||||
if not taskid:
|
||||
return "Error: DSM did not return a task ID."
|
||||
|
||||
ok, result = await _poll_task("SYNO.FileStation.DirSize", 1, taskid)
|
||||
ok, result = await _poll_task("SYNO.FileStation.DirSize", 1, taskid, initial_delay=0.0)
|
||||
if not ok:
|
||||
return result # type: ignore[return-value]
|
||||
|
||||
@@ -866,7 +876,7 @@ def register_filestation(
|
||||
if not taskid:
|
||||
return "Error: DSM did not return a task ID."
|
||||
|
||||
ok, result = await _poll_task("SYNO.FileStation.MD5", 2, taskid)
|
||||
ok, result = await _poll_task("SYNO.FileStation.MD5", 1, taskid, initial_delay=0.0)
|
||||
if not ok:
|
||||
return result # type: ignore[return-value]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user