Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proxy support #351

Merged
merged 13 commits into from
May 23, 2024
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ Import the modules you need and launch the server.
from ephys_link.server import Server

server = Server()
server.launch("sensapex", 8081)
server.launch("sensapex", args.proxy_address, 8081)
```

## Install for Development
Expand Down
9 changes: 9 additions & 0 deletions ephys_link.spec
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

from ephys_link.__about__ import __version__ as version

from argparse import ArgumentParser

parser = ArgumentParser()
parser.add_argument("-d", "--dir", action="store_true", help="Outputs a directory")
options = parser.parse_args()

a = Analysis(
['src\\ephys_link\\__main__.py'],
pathex=[],
Expand Down Expand Up @@ -37,3 +43,6 @@ exe = EXE(
entitlements_file=None,
icon='assets\\icon.ico',
)

if options.dir:
coll = COLLECT(exe, a.binaries, name=f"EphysLink-v{version}")
10 changes: 5 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name = "ephys-link"
dynamic = ["version"]
description = "A Python Socket.IO server that allows any Socket.IO-compliant application to communicate with manipulators used in electrophysiology experiments."
readme = "README.md"
requires-python = ">=3.8, <3.13"
requires-python = ">=3.10, <3.13"
license = "GPL-3.0-only"
keywords = ["socket-io", "manipulator", "electrophysiology", "ephys", "sensapex", "neuroscience", "neurotech", "virtualbrainlab", "new-scale"]
authors = [{ name = "Kenneth Yang", email = "[email protected]" }]
Expand Down Expand Up @@ -35,7 +35,6 @@ dependencies = [
"pyserial==3.5",
"python-socketio==5.11.2",
"pythonnet==3.0.3",
"requests==2.32.0",
"sensapex==1.400.0",
"vbl-aquarium==0.0.14"
]
Expand All @@ -61,7 +60,7 @@ python = "3.12"
dependencies = [
"coverage[toml]>=6.5",
"pytest",
"python-socketio[client]==5.11.2",
"python-socketio[asyncio_client]==5.11.2",
]
[tool.hatch.envs.default.scripts]
test = "pytest {args:tests}"
Expand All @@ -88,10 +87,11 @@ check = "mypy --install-types --non-interactive {args:src/ephys_link tests}"
[tool.hatch.envs.exe]
python = "3.12"
dependencies = [
"pyinstaller==6.3.0",
"pyinstaller",
]
[tool.hatch.envs.exe.scripts]
build = "pyinstaller.exe ephys_link.spec -y"
build = "pyinstaller.exe ephys_link.spec -y -- -d"
build_onefile = "pyinstaller.exe ephys_link.spec -y"
build_clean = "pyinstaller.exe ephys_link.spec -y --clean"

[tool.coverage.run]
Expand Down
24 changes: 24 additions & 0 deletions scripts/proxy_dev.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from __future__ import annotations

from asyncio import run

from socketio import AsyncClient

pinpoint_id = "4158ebf3"
is_requester = True

sio = AsyncClient()


async def main():
await sio.connect("http://localhost:3000")
# await sio.emit("get_manipulators", lambda m: print(m))
await sio.wait()


@sio.event
async def get_pinpoint_id() -> tuple[str, bool]:
return pinpoint_id, is_requester


run(main())
2 changes: 1 addition & 1 deletion src/ephys_link/__about__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.3.0"
__version__ = "1.3.1"
12 changes: 10 additions & 2 deletions src/ephys_link/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from argparse import ArgumentParser
from asyncio import run
from sys import argv

from ephys_link import common as com
Expand Down Expand Up @@ -26,13 +27,15 @@
help='Manipulator type (i.e. "sensapex", "new_scale", or "new_scale_pathfinder"). Default: "sensapex".',
)
parser.add_argument("-d", "--debug", dest="debug", action="store_true", help="Enable debug mode.")
parser.add_argument("-x", "--use-proxy", dest="use_proxy", action="store_true", help="Enable proxy mode.")
parser.add_argument("-a", "--proxy-address", type=str, dest="proxy_address", help="Proxy IP address.")
parser.add_argument(
"-p",
"--port",
type=int,
default=8081,
dest="port",
help="Port to serve on. Default: 8081 (avoids conflict with other HTTP servers).",
help="TCP/IP port to use. Default: 8081 (avoids conflict with other HTTP servers).",
)
parser.add_argument(
"--pathfinder_port",
Expand Down Expand Up @@ -83,7 +86,12 @@ def main() -> None:
e_stop.watch()

# Launch with parsed arguments on main thread.
server.launch(args.type, args.port, args.pathfinder_port, args.ignore_updates)
if args.use_proxy:
run(
server.launch_for_proxy(args.proxy_address, args.port, args.type, args.pathfinder_port, args.ignore_updates)
)
else:
server.launch(args.type, args.port, args.pathfinder_port, args.ignore_updates)


if __name__ == "__main__":
Expand Down
6 changes: 3 additions & 3 deletions src/ephys_link/platform_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
from ephys_link import common as com

if TYPE_CHECKING:
import socketio
from socketio import AsyncClient, AsyncServer


class PlatformHandler(ABC):
Expand Down Expand Up @@ -309,7 +309,7 @@ def set_inside_brain(self, request: InsideBrainRequest) -> BooleanStateResponse:
print(f"{e}\n")
return BooleanStateResponse(error="Error setting inside brain")

async def calibrate(self, manipulator_id: str, sio: socketio.AsyncServer) -> str:
async def calibrate(self, manipulator_id: str, sio: AsyncClient | AsyncServer) -> str:
"""Calibrate manipulator

:param manipulator_id: ID of manipulator to calibrate
Expand Down Expand Up @@ -423,7 +423,7 @@ def _set_inside_brain(self, request: InsideBrainRequest) -> BooleanStateResponse
raise NotImplementedError

@abstractmethod
async def _calibrate(self, manipulator_id: str, sio: socketio.AsyncServer) -> str:
async def _calibrate(self, manipulator_id: str, sio: AsyncClient | AsyncServer) -> str:
"""Calibrate manipulator

:param manipulator_id: ID of manipulator to calibrate
Expand Down
2 changes: 1 addition & 1 deletion src/ephys_link/platforms/sensapex_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ async def _calibrate(self, manipulator_id: str, sio: socketio.AsyncServer) -> st
cur_pos = self.manipulators[manipulator_id].get_pos()["position"]

# Check difference between current and target position
for prev, cur in zip([10000, 10000, 10000, 10000], cur_pos):
for prev, cur in zip([10000, 10000, 10000, 10000], cur_pos, strict=False):
if abs(prev - cur) > 1:
still_working = True
break
Expand Down
8 changes: 7 additions & 1 deletion src/ephys_link/platforms/sensapex_manipulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,13 @@ def get_pos(self) -> PositionalResponse:
# com.dprint(f"[SUCCESS]\t Got position of manipulator {self._id}\n")
return PositionalResponse(
position=Vector4(
**dict(zip(Vector4.model_fields.keys(), [axis / MM_TO_UM for axis in self._device.get_pos(1)]))
**dict(
zip(
Vector4.model_fields.keys(),
[axis / MM_TO_UM for axis in self._device.get_pos(1)],
strict=False,
)
)
)
)
except Exception as e:
Expand Down
4 changes: 3 additions & 1 deletion src/ephys_link/platforms/ump3_manipulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,9 @@ def get_pos(self) -> PositionalResponse:
position.append(position[0])

# com.dprint(f"[SUCCESS]\t Got position of manipulator {self._id}\n")
return PositionalResponse(position=Vector4(**dict(zip(Vector4.model_fields.keys(), position))))
return PositionalResponse(
position=Vector4(**dict(zip(Vector4.model_fields.keys(), position, strict=False)))
)
except Exception as e:
print(f"[ERROR]\t\t Getting position of manipulator {self._id}")
print(f"{e}\n")
Expand Down
Loading