From 2340149b1a9bbb1748c0bd450da2c0c05cff624d Mon Sep 17 00:00:00 2001 From: Justin Mitchell Date: Mon, 6 Apr 2026 01:01:19 -0400 Subject: [PATCH] Fixes delete endpoint and ws discovery --- crosspoint_reader/driver.py | 27 ++++++++++++++++++++------- crosspoint_reader/ws_client.py | 1 + 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/crosspoint_reader/driver.py b/crosspoint_reader/driver.py index 053a391..a90ad90 100644 --- a/crosspoint_reader/driver.py +++ b/crosspoint_reader/driver.py @@ -136,7 +136,8 @@ class CrossPointDevice(DeviceConfig, DevicePlugin): def _http_post_form(self, path, data, timeout=5): url = self._http_base() + path body = urllib.parse.urlencode(data).encode('utf-8') - req = urllib.request.Request(url, data=body, method='POST') + req = urllib.request.Request(url, data=body, method='POST', + headers={'Content-Type': 'application/x-www-form-urlencoded'}) try: with urllib.request.urlopen(req, timeout=timeout) as resp: return resp.status, resp.read().decode('utf-8', 'ignore') @@ -250,7 +251,8 @@ class CrossPointDevice(DeviceConfig, DevicePlugin): """ url = self._http_base() + '/mkdir' body = urllib.parse.urlencode({'name': name, 'path': path}).encode('utf-8') - req = urllib.request.Request(url, data=body, method='POST') + req = urllib.request.Request(url, data=body, method='POST', + headers={'Content-Type': 'application/x-www-form-urlencoded'}) try: with urllib.request.urlopen(req, timeout=5) as resp: resp.read() @@ -353,11 +355,22 @@ class CrossPointDevice(DeviceConfig, DevicePlugin): def delete_books(self, paths, end_session=True): - for path in paths: - status, body = self._http_post_form('/delete', {'path': path, 'type': 'file'}) - if status != 200: - raise ControlError(desc=f'Delete failed for {path}: {body}') - self._log(f'[CrossPoint] deleted {path}') + import json as _json + self._log(f'[CrossPoint] deleting {len(paths)} books: {paths}') + url = self._http_base() + '/delete' + # Server expects form field 'paths' containing a JSON array string + body = urllib.parse.urlencode({'paths': _json.dumps(list(paths))}).encode('utf-8') + req = urllib.request.Request(url, data=body, method='POST', + headers={'Content-Type': 'application/x-www-form-urlencoded'}) + try: + with urllib.request.urlopen(req, timeout=10) as resp: + self._log(f'[CrossPoint] delete OK: {resp.status}') + except urllib.error.HTTPError as exc: + err_body = exc.read().decode('utf-8', 'ignore') if exc.fp else '' + self._log(f'[CrossPoint] delete error {exc.code}: {err_body}') + raise ControlError(desc=f'Delete failed: {exc.code} {err_body}') + except Exception as exc: + raise ControlError(desc=f'Delete failed: {exc}') def remove_books_from_metadata(self, paths, booklists): def norm(p): diff --git a/crosspoint_reader/ws_client.py b/crosspoint_reader/ws_client.py index c095ae6..d07e25b 100644 --- a/crosspoint_reader/ws_client.py +++ b/crosspoint_reader/ws_client.py @@ -229,6 +229,7 @@ def discover_device(timeout=2.0, debug=False, logger=None, extra_hosts=None): _log(logger, debug, f'[CrossPoint WS] discovery subnet broadcast {bcast}') for port in ports: targets.append((bcast, port)) + # 255.255.255.255 as fallback — works on Linux/Windows, silently fails on macOS for port in ports: targets.append(('255.255.255.255', port)) for host in extra_hosts or []: