Skip to content

Commit

Permalink
Cache HTTP data at 60 FPS (#424)
Browse files Browse the repository at this point in the history
  • Loading branch information
kjy5 authored Jan 10, 2025
1 parent fa186c3 commit e737215
Showing 1 changed file with 15 additions and 5 deletions.
20 changes: 15 additions & 5 deletions src/ephys_link/bindings/mpm_binding.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
"""Bindings for New Scale Pathfinder MPM HTTP server platform.
MPM works slightly differently than the other platforms since it operates in stereotactic coordinates.
This means exceptions need to be made for its API.
Usage: Instantiate MPMBindings to interact with the New Scale Pathfinder MPM HTTP server platform.
"""

Expand Down Expand Up @@ -65,6 +62,9 @@ class MPMBinding(BaseBinding):
"AN",
)

# Server cache lifetime (60 FPS).
CACHE_LIFETIME = 1 / 60

# Movement polling preferences.
UNCHANGED_COUNTER_LIMIT = 10
POLL_INTERVAL = 0.1
Expand All @@ -82,6 +82,10 @@ def __init__(self, port: int = 8080) -> None:
self._url = f"http://localhost:{port}"
self._movement_stopped = False

# Data cache.
self.cache = {}
self.cache_time = 0

@staticmethod
@override
def get_display_name() -> str:
Expand Down Expand Up @@ -279,14 +283,20 @@ def unified_space_to_platform_space(self, unified_space: Vector4) -> Vector4:
# Helper functions.
async def _query_data(self) -> dict[str, Any]: # pyright: ignore [reportExplicitAny]
try:
# noinspection PyTypeChecker
return (await get_running_loop().run_in_executor(None, get, self._url)).json() # pyright: ignore [reportAny]
# Update cache if it's expired.
if get_running_loop().time() - self.cache_time > self.CACHE_LIFETIME:
# noinspection PyTypeChecker
self.cache = (await get_running_loop().run_in_executor(None, get, self._url)).json() # pyright: ignore [reportAny]
self.cache_time = get_running_loop().time()
except ConnectionError as connectionError:
error_message = f"Unable to connect to MPM HTTP server: {connectionError}"
raise RuntimeError(error_message) from connectionError
except JSONDecodeError as jsonDecodeError:
error_message = f"Unable to decode JSON response from MPM HTTP server: {jsonDecodeError}"
raise ValueError(error_message) from jsonDecodeError
else:
# Return cached data.
return self.cache

async def _manipulator_data(self, manipulator_id: str) -> dict[str, Any]: # pyright: ignore [reportExplicitAny]
probe_data: list[dict[str, Any]] = (await self._query_data())["ProbeArray"] # pyright: ignore [reportExplicitAny]
Expand Down

0 comments on commit e737215

Please sign in to comment.