From 3580c3b5b9a33b4f0dece17411cc343d4ce3ca88 Mon Sep 17 00:00:00 2001 From: Brent Yi Date: Thu, 3 Aug 2023 00:38:05 -0700 Subject: [PATCH 1/4] Add `share: bool` flag for tunneling --- examples/00_coordinate_frames.py | 2 +- pyproject.toml | 1 + viser/_viser.py | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/00_coordinate_frames.py b/examples/00_coordinate_frames.py index a24daef0c..10bd58e06 100644 --- a/examples/00_coordinate_frames.py +++ b/examples/00_coordinate_frames.py @@ -11,7 +11,7 @@ import viser -server = viser.ViserServer() +server = viser.ViserServer(share=True) while True: # Add some coordinate frames to the scene. These will be visualized in the viewer. diff --git a/pyproject.toml b/pyproject.toml index f4aa36b64..90b145ba2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,6 +32,7 @@ dependencies = [ "rich>=13.3.3", "trimesh>=3.21.7", "nodeenv>=1.8.0", + "rustenv>=0.0.6", ] [project.optional-dependencies] diff --git a/viser/_viser.py b/viser/_viser.py index 300a12644..f7e76e2fe 100644 --- a/viser/_viser.py +++ b/viser/_viser.py @@ -16,6 +16,7 @@ from ._gui_api import GuiApi from ._message_api import MessageApi, cast_vector from ._scene_handles import FrameHandle, _SceneNodeHandleState +from ._tunnel import start_tunnel @dataclasses.dataclass @@ -229,7 +230,10 @@ class ViserServer(MessageApi, GuiApi): """Handle for manipulating the world frame axes (/WorldAxes), which is instantiated and then hidden by default.""" - def __init__(self, host: str = "0.0.0.0", port: int = 8080): + def __init__(self, host: str = "0.0.0.0", port: int = 8080, share: bool = False): + if share: + print(start_tunnel(port, connection_timeout=10.0)) + server = infra.Server( host=host, port=port, From 26fc2e917d4a07cf22456a9585e8e2bca407fa90 Mon Sep 17 00:00:00 2001 From: Brent Yi Date: Thu, 3 Aug 2023 00:38:55 -0700 Subject: [PATCH 2/4] Cleanup --- viser/_viser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/viser/_viser.py b/viser/_viser.py index f7e76e2fe..685decad0 100644 --- a/viser/_viser.py +++ b/viser/_viser.py @@ -232,7 +232,7 @@ class ViserServer(MessageApi, GuiApi): def __init__(self, host: str = "0.0.0.0", port: int = 8080, share: bool = False): if share: - print(start_tunnel(port, connection_timeout=10.0)) + start_tunnel(port) server = infra.Server( host=host, From a38ddd50fd9ce029c031a67a96cd6b1fac31a01b Mon Sep 17 00:00:00 2001 From: Brent Yi Date: Thu, 3 Aug 2023 00:39:15 -0700 Subject: [PATCH 3/4] Add _tunnel.py --- viser/_tunnel.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 viser/_tunnel.py diff --git a/viser/_tunnel.py b/viser/_tunnel.py new file mode 100644 index 000000000..58794b6d5 --- /dev/null +++ b/viser/_tunnel.py @@ -0,0 +1,61 @@ +"""Helper for creating shareable viser links using `bore`. + +https://github.com/ekzhang/bore +""" + +import atexit +import os +import signal +import subprocess +import sys +import threading +from pathlib import Path + +BORE_SERVER = "chalupa.eecs.berkeley.edu" + + +def start_tunnel(port: int) -> None: + env_dir = Path(__file__).absolute().parent / ".rustenv" + bore_path = env_dir / "rust" / "bin" / "bore" + + if not env_dir.exists(): + print("[viser] Tunneling: setting up Rust environment") + subprocess.run(args=[sys.executable, "-m", "rustenv", str(env_dir)]) + + if not bore_path.exists(): + print("[viser] Tunneling: installing bore") + subprocess.run(args=[str(env_dir / "bin" / "cargo"), "install", "bore-cli"]) + + process = subprocess.Popen( + [f"{bore_path}", "local", str(port), "--to", BORE_SERVER], + stdout=subprocess.PIPE, + ) + + # Handle normal exists. + @atexit.register + def _(): + process.terminate() + process.wait() + + # Handle SIGTERM. + script_pid = os.getpid() + + def handle_termination_signal(signum, frame): + process.kill() + os.kill(script_pid, signum) + + signal.signal(signal.SIGTERM, handle_termination_signal) + + def _bore_watcher() -> None: + while True: + assert process.stdout is not None + line = process.stdout.readline().decode().strip() + if "Error:" in line: + print(line) + break + if "listening at " in line: + print("[viser] Tunnel created at", line.partition("listening at ")[2]) + + threading.Thread(target=_bore_watcher).start() + + return None From 8ca020c0a31b717cffd78d3b985d3475d16714b8 Mon Sep 17 00:00:00 2001 From: Brent Yi Date: Thu, 3 Aug 2023 16:27:26 -0700 Subject: [PATCH 4/4] Add share to SMPL-X example --- examples/08_smplx_visualizer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/08_smplx_visualizer.py b/examples/08_smplx_visualizer.py index cce06a480..e165fb2a5 100644 --- a/examples/08_smplx_visualizer.py +++ b/examples/08_smplx_visualizer.py @@ -35,7 +35,7 @@ def main( num_expression_coeffs: int = 10, ext: Literal["npz", "pkl"] = "npz", ) -> None: - server = viser.ViserServer() + server = viser.ViserServer(share=True) model = smplx.create( model_path=str(model_path), model_type=model_type,