d8d7c6fd47
Three path formats tested against NAS: a) plain string -> 599 (wrong, task fails silently) b) json.dumps([path]) -> works (JSON array is the correct format) c) json.dumps(path) -> 599 (wrong, double-encoded string) Confirms current implementation (json.dumps(paths)) is correct. MD5 probe simplified to final confirmed settings (status v1, 0ms). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
167 lines
5.4 KiB
Python
167 lines
5.4 KiB
Python
"""Wegwerfskript: DirSize + MD5 direkt gegen die NAS testen.
|
|
|
|
Finale Befunde:
|
|
DirSize: start v2 (path als plain string ODER JSON-Array), status v1 (0ms delay)
|
|
MD5: start v2, status v1 (0ms delay, ONE-SHOT)
|
|
|
|
DirSize status-Response Felder:
|
|
finished: bool
|
|
num_dir: int (Anzahl Unterordner)
|
|
num_file: int (Anzahl Dateien)
|
|
total_size: int (Gesamtgroesse in Bytes)
|
|
|
|
MD5 status-Response Felder:
|
|
finished: bool
|
|
md5: str (Hex-String, 32 Zeichen)
|
|
|
|
Ausfuehren: uv run python test_dirsize_md5.py
|
|
"""
|
|
|
|
import asyncio
|
|
import json
|
|
import time
|
|
|
|
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, elapsed_ms: float | None = None) -> None:
|
|
print(f"\n{'='*60}")
|
|
suffix = f" [{elapsed_ms:.1f} ms nach start]" if elapsed_ms is not None else ""
|
|
print(f" {label}{suffix}")
|
|
print("=" * 60)
|
|
print(json.dumps(data, indent=2, ensure_ascii=False))
|
|
|
|
|
|
async def raw(http: httpx.AsyncClient, url: str, sid: str, **params) -> dict:
|
|
r = await http.get(url, 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 probe_dirsize_path_variants(
|
|
http: httpx.AsyncClient, sid: str, api_url: str
|
|
) -> None:
|
|
"""Test all three path encoding variants for DirSize start."""
|
|
print(f"\n{'#'*60}")
|
|
print(" DIRSIZE path-Varianten (a=plain, b=json.dumps, c=manuell)")
|
|
print(f"{'#'*60}")
|
|
|
|
variants = [
|
|
("a) plain string", DIRSIZE_PATH),
|
|
("b) json.dumps([path])", json.dumps([DIRSIZE_PATH])),
|
|
("c) json.dumps(path)", json.dumps(DIRSIZE_PATH)),
|
|
]
|
|
|
|
for label, path_val in variants:
|
|
print(f"\n--- Variante {label} ---")
|
|
print(f" path={path_val!r}")
|
|
|
|
t0 = time.perf_counter()
|
|
start_body = await raw(
|
|
http, api_url, sid,
|
|
api="SYNO.FileStation.DirSize", version="2", method="start",
|
|
path=path_val,
|
|
)
|
|
pp(f"DirSize::start [{label}]", start_body, (time.perf_counter() - t0) * 1000)
|
|
|
|
taskid = (start_body.get("data") or {}).get("taskid")
|
|
if not taskid:
|
|
print(" => Kein taskid (start fehlgeschlagen)")
|
|
continue
|
|
|
|
# Poll immediately
|
|
t1 = time.perf_counter()
|
|
status_body = await raw(
|
|
http, api_url, sid,
|
|
api="SYNO.FileStation.DirSize", version="1", method="status",
|
|
taskid=taskid,
|
|
)
|
|
pp(f"DirSize::status [{label}]", status_body, (t1 - t0) * 1000)
|
|
|
|
data = (status_body.get("data") or {})
|
|
if data.get("finished"):
|
|
print(f" => OK: num_dir={data.get('num_dir')} "
|
|
f"num_file={data.get('num_file')} "
|
|
f"total_size={data.get('total_size')}")
|
|
else:
|
|
code = (status_body.get("error") or {}).get("code", "?")
|
|
print(f" => FEHLER code={code}")
|
|
|
|
|
|
async def probe_md5(http: httpx.AsyncClient, sid: str, api_url: str) -> None:
|
|
"""Test MD5 with status v1 at 0ms (correct settings)."""
|
|
print(f"\n{'#'*60}")
|
|
print(" MD5 -- start v2, status v1, 0ms delay")
|
|
print(f"{'#'*60}")
|
|
|
|
t0 = time.perf_counter()
|
|
start_body = await raw(
|
|
http, api_url, sid,
|
|
api="SYNO.FileStation.MD5", version="2", method="start",
|
|
file_path=json.dumps(MD5_PATH),
|
|
)
|
|
pp("MD5::start", start_body, (time.perf_counter() - t0) * 1000)
|
|
|
|
taskid = (start_body.get("data") or {}).get("taskid")
|
|
if not taskid:
|
|
print("[!] No taskid")
|
|
return
|
|
|
|
t1 = time.perf_counter()
|
|
r = await raw(
|
|
http, api_url, sid,
|
|
api="SYNO.FileStation.MD5", version="1", method="status",
|
|
taskid=taskid,
|
|
)
|
|
pp("MD5::status v1 [0ms]", r, (t1 - t0) * 1000)
|
|
data = (r.get("data") or {})
|
|
if data.get("finished"):
|
|
print(f" => OK: md5={data.get('md5')}")
|
|
else:
|
|
print(f" => FEHLER: {r}")
|
|
|
|
|
|
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
|
|
|
|
for api_name in ["SYNO.FileStation.DirSize", "SYNO.FileStation.MD5"]:
|
|
info = client._api_cache.get(api_name) # noqa: SLF001
|
|
if info:
|
|
print(f"[*] {api_name}: path={info['path']} "
|
|
f"v{info['minVersion']}-v{info['maxVersion']}")
|
|
else:
|
|
print(f"[!] {api_name}: NOT in API cache!")
|
|
|
|
dirsize_info = client._api_cache.get("SYNO.FileStation.DirSize", {}) # noqa: SLF001
|
|
md5_info = client._api_cache.get("SYNO.FileStation.MD5", {}) # noqa: SLF001
|
|
dirsize_url = f"{base}/webapi/{dirsize_info.get('path', 'entry.cgi')}"
|
|
md5_url = f"{base}/webapi/{md5_info.get('path', 'entry.cgi')}"
|
|
|
|
async with httpx.AsyncClient(verify=config.connection.verify_ssl, timeout=30.0) as http:
|
|
await probe_dirsize_path_variants(http, sid, dirsize_url)
|
|
await probe_md5(http, sid, md5_url)
|
|
|
|
await auth.logout(client)
|
|
print("\n[*] Logout OK.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(main())
|