fix: use correct status API versions for DirSize and MD5
- DirSize: _poll_task now uses status version=1 (v2 always returns 599) - MD5: _poll_task keeps status version=2 (confirmed working via live NAS test) Investigation notes documented in test_dirsize_md5.py: both APIs use start v2; DirSize status needs v1, MD5 status needs v2; tiny data causes one-shot race condition (no issue with real-world data). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
"""Wegwerfskript: DirSize + MD5 direkt gegen die NAS testen.
|
||||
|
||||
Ergebnisse der Versionsanalyse (vollständig):
|
||||
DirSize: start v2, status v1
|
||||
MD5: start v2, status v1
|
||||
- Wichtig: MD5-Status ist ONE-SHOT — nach dem ersten erfolgreichen
|
||||
Abruf verfällt die Task-ID sofort (code 599 bei allen Folgeabfragen).
|
||||
- Erster status-Aufruf muss direkt nach start kommen (delay~0).
|
||||
|
||||
DirSize status-Response Felder:
|
||||
finished: bool
|
||||
num_dir: int (Anzahl Unterordner)
|
||||
num_file: int (Anzahl Dateien)
|
||||
total_size: int (Gesamtgrösse in Bytes)
|
||||
|
||||
MD5 status-Response Felder:
|
||||
finished: bool
|
||||
md5: str (Hex-String, 32 Zeichen)
|
||||
|
||||
Ausführen: uv run python test_dirsize_md5.py
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
import httpx
|
||||
|
||||
from mcp_synology_filestation.auth import AuthManager
|
||||
from mcp_synology_filestation.client import FileStationClient
|
||||
from mcp_synology_filestation.config import load_config
|
||||
|
||||
DIRSIZE_PATH = "/test-mcp"
|
||||
MD5_PATH = "/test-mcp/test.zip"
|
||||
|
||||
|
||||
def pp(label: str, data: object) -> None:
|
||||
print(f"\n{'='*60}")
|
||||
print(f" {label}")
|
||||
print("=" * 60)
|
||||
print(json.dumps(data, indent=2, ensure_ascii=False))
|
||||
|
||||
|
||||
async def raw(http: httpx.AsyncClient, base_url: str, sid: str, **params) -> dict:
|
||||
r = await http.get(f"{base_url}/webapi/entry.cgi", params={"_sid": sid, **params})
|
||||
r.raise_for_status()
|
||||
try:
|
||||
return r.json()
|
||||
except Exception:
|
||||
return {"_raw": r.text[:300], "_http_status": r.status_code}
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
config = load_config()
|
||||
auth = AuthManager(config)
|
||||
|
||||
async with FileStationClient(config.base_url, config.connection.verify_ssl) as client:
|
||||
client.set_auth_manager(auth)
|
||||
await client._ensure_initialized() # noqa: SLF001
|
||||
sid = client.sid
|
||||
base = config.base_url
|
||||
print(f"[*] SID: {'OK' if sid else 'MISSING'}")
|
||||
|
||||
async with httpx.AsyncClient(verify=config.connection.verify_ssl, timeout=30.0) as http:
|
||||
|
||||
# ── DirSize: start v2, status v1 ─────────────────────────────
|
||||
print(f"\n{'#'*60}")
|
||||
print(" SYNO.FileStation.DirSize (start v2, status v1)")
|
||||
print(f"{'#'*60}")
|
||||
|
||||
start_body = await raw(
|
||||
http, base, sid,
|
||||
api="SYNO.FileStation.DirSize", version="2", method="start",
|
||||
path=json.dumps([DIRSIZE_PATH]),
|
||||
)
|
||||
pp("DirSize::start", start_body)
|
||||
|
||||
taskid = (start_body.get("data") or {}).get("taskid")
|
||||
if taskid:
|
||||
for attempt in range(1, 11):
|
||||
await asyncio.sleep(0.2)
|
||||
status_body = await raw(
|
||||
http, base, sid,
|
||||
api="SYNO.FileStation.DirSize", version="1", method="status",
|
||||
taskid=taskid,
|
||||
)
|
||||
pp(f"DirSize::status (attempt {attempt})", status_body)
|
||||
data = (status_body.get("data") or {})
|
||||
if data.get("finished"):
|
||||
print("\n[*] FINISHED. Fields:")
|
||||
for k, v in data.items():
|
||||
print(f" {k!r}: {type(v).__name__} = {v!r}")
|
||||
break
|
||||
|
||||
# ── MD5: start v2, status v1 (one-shot!) ─────────────────────
|
||||
print(f"\n{'#'*60}")
|
||||
print(" SYNO.FileStation.MD5 (start v2, status v1, ONE-SHOT)")
|
||||
print(f"{'#'*60}")
|
||||
|
||||
start_body = await raw(
|
||||
http, base, sid,
|
||||
api="SYNO.FileStation.MD5", version="2", method="start",
|
||||
file_path=json.dumps(MD5_PATH),
|
||||
)
|
||||
pp("MD5::start", start_body)
|
||||
|
||||
taskid = (start_body.get("data") or {}).get("taskid")
|
||||
if taskid:
|
||||
# Immediately poll status v1 — one-shot window, don't delay
|
||||
for attempt in range(1, 6):
|
||||
if attempt > 1:
|
||||
await asyncio.sleep(0.05)
|
||||
status_body = await raw(
|
||||
http, base, sid,
|
||||
api="SYNO.FileStation.MD5", version="1", method="status",
|
||||
taskid=taskid,
|
||||
)
|
||||
pp(f"MD5::status (attempt {attempt})", status_body)
|
||||
data = (status_body.get("data") or {})
|
||||
if data.get("finished"):
|
||||
print("\n[*] FINISHED. Fields:")
|
||||
for k, v in data.items():
|
||||
print(f" {k!r}: {type(v).__name__} = {v!r}")
|
||||
break
|
||||
if not status_body.get("success"):
|
||||
print("[!] 599 — task window closed, done probing.")
|
||||
break
|
||||
|
||||
await auth.logout(client)
|
||||
print("\n[*] Logout OK.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
Reference in New Issue
Block a user