Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions clipsync/pairing.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from collections.abc import Callable

import qrcode
import requests
from PIL import Image

from . import config
Expand Down Expand Up @@ -174,6 +175,8 @@ def _run(self) -> None:
while not self._stop.is_set():
try:
self._tick()
except requests.RequestException as exc:
log.warning("Pending device watcher: Syncthing not responding (%s)", exc)
except Exception:
log.exception("Error in pending device watcher")
if self._stop.wait(self._interval):
Expand Down
13 changes: 10 additions & 3 deletions clipsync/syncthing.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ def __init__(self, api_key: str, base_url: str = config.SYNCTHING_API_URL) -> No
self._base = base_url.rstrip("/")
self._session = requests.Session()
self._session.headers["X-API-Key"] = api_key
self._cached_device_id: str | None = None

def _url(self, path: str) -> str:
return f"{self._base}{path}"
Expand Down Expand Up @@ -557,8 +558,10 @@ def wait_until_ready(self, timeout: float = _STARTUP_WAIT) -> bool:
return False

def get_device_id(self) -> str:
status = self._get("/rest/system/status")
return status["myID"]
if self._cached_device_id is None:
status = self._get("/rest/system/status")
self._cached_device_id = status["myID"]
return self._cached_device_id

def get_config(self) -> dict[str, Any]:
return self._get("/rest/config")
Expand Down Expand Up @@ -646,7 +649,11 @@ def connected_devices(self) -> list[dict[str, Any]]:
"""Return a list of {deviceID, name, connected, address} for paired devices."""
devices = self.get_devices()
my_id = self.get_device_id()
connections = self.get_connections().get("connections") or {}
try:
connections = self.get_connections().get("connections") or {}
except requests.RequestException:
# Connection status is best-effort; don't fail the whole call.
connections = {}
out: list[dict[str, Any]] = []
for d in devices:
did = d.get("deviceID")
Expand Down
18 changes: 16 additions & 2 deletions clipsync/ui.py
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,7 @@ def __init__(
) -> None:
self._win = window
self._app = app
self._refreshing = False

ctk.CTkLabel(container, text="Connected devices", font=ctk.CTkFont(size=18, weight="bold")).pack(pady=(0, 10))

Expand All @@ -578,7 +579,7 @@ def _exists(self) -> bool:
def _schedule_refresh(self) -> None:
if not self._exists():
return
self._win.after(3000, self._auto_refresh)
self._win.after(10_000, self._auto_refresh)

def _auto_refresh(self) -> None:
if not self._exists():
Expand All @@ -587,6 +588,9 @@ def _auto_refresh(self) -> None:
self._schedule_refresh()

def _refresh(self) -> None:
if self._refreshing:
return
self._refreshing = True
for child in self._list_frame.winfo_children():
child.destroy()
ctk.CTkLabel(self._list_frame, text="Loading…", text_color=("gray50", "gray60")).pack(pady=20)
Expand All @@ -604,8 +608,11 @@ def _do_refresh(self) -> None:
error = str(exc)
if self._exists():
self._win.after(0, self._apply_refresh, devices, error)
else:
self._refreshing = False

def _apply_refresh(self, devices: list[dict], error: str | None) -> None:
self._refreshing = False
for child in self._list_frame.winfo_children():
child.destroy()
if error:
Expand Down Expand Up @@ -1195,6 +1202,7 @@ def __init__(self, parent: ctk.CTk, app: AppContext, on_close: Callable[[], None
super().__init__(parent, f"{config.APP_NAME} — Incoming Requests", (440, 360), on_close)
self._app = app
self._handled: set[str] = set()
self._refreshing = False

container = ctk.CTkFrame(self.window, fg_color="transparent")
container.pack(fill="both", expand=True, padx=20, pady=20)
Expand All @@ -1221,7 +1229,7 @@ def __init__(self, parent: ctk.CTk, app: AppContext, on_close: Callable[[], None
def _schedule_refresh(self) -> None:
if not self.exists():
return
self.window.after(3000, self._auto_refresh)
self.window.after(10_000, self._auto_refresh)

def _auto_refresh(self) -> None:
if not self.exists():
Expand All @@ -1230,6 +1238,9 @@ def _auto_refresh(self) -> None:
self._schedule_refresh()

def _refresh(self) -> None:
if self._refreshing:
return
self._refreshing = True
for child in self._list_frame.winfo_children():
child.destroy()
ctk.CTkLabel(self._list_frame, text="Loading…", text_color=("gray50", "gray60")).pack(pady=20)
Expand All @@ -1247,8 +1258,11 @@ def _do_refresh(self) -> None:
error = str(exc)
if self.exists():
self.window.after(0, self._apply_refresh, pending, error)
else:
self._refreshing = False

def _apply_refresh(self, pending: dict, error: str | None) -> None:
self._refreshing = False
for child in self._list_frame.winfo_children():
child.destroy()
if error:
Expand Down
Loading