Skip to content

Commit 9f6dffb

Browse files
committed
Set env & mappath via CLI, add Args for Unix Sockets
1 parent 6b7214a commit 9f6dffb

File tree

2 files changed

+102
-41
lines changed

2 files changed

+102
-41
lines changed

jupyter_server_proxy/standalone/__init__.py

Lines changed: 80 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,37 +23,45 @@ def _use_jupyterhub(overwrite):
2323

2424

2525
def run(
26-
command,
27-
port,
28-
destport,
29-
ip,
30-
debug,
31-
# logs,
32-
overwrite_authentication,
33-
timeout,
34-
activity_interval,
35-
# progressive,
36-
websocket_max_message_size,
26+
command: list[str],
27+
port: int,
28+
address: str,
29+
server_port: int,
30+
socket_path: str | None,
31+
socket_auto: bool,
32+
environment: list[tuple[str, str]] | None,
33+
mappath: list[tuple[str, str]] | None,
34+
debug: bool,
35+
# logs: bool,
36+
overwrite_authentication: bool | None,
37+
timeout: int,
38+
activity_interval: int,
39+
# progressive: bool,
40+
websocket_max_message_size: int,
3741
):
38-
if port is None:
39-
port = get_port_from_env()
40-
42+
# Setup Logging
4143
enable_pretty_logging(logger=log)
4244
if debug:
4345
log.setLevel(logging.DEBUG)
4446

47+
if not port:
48+
port = get_port_from_env()
49+
4550
use_jupyterhub = _use_jupyterhub(overwrite_authentication)
4651
if use_jupyterhub:
4752
log.info("Enabling Authentication with JupyterHub")
4853

4954
prefix = os.environ.get("JUPYTERHUB_SERVICE_PREFIX", "/")
5055

5156
app = make_proxy_app(
52-
destport,
57+
command,
5358
prefix.removesuffix("/"),
54-
list(command),
55-
use_jupyterhub,
59+
server_port,
60+
socket_path or socket_auto,
61+
dict(environment),
62+
dict(mappath),
5663
timeout,
64+
use_jupyterhub,
5765
debug,
5866
# progressive,
5967
websocket_max_message_size,
@@ -66,11 +74,11 @@ def run(
6674
ssl_options = configure_ssl()
6775

6876
http_server = HTTPServer(app, ssl_options=ssl_options, xheaders=True)
69-
http_server.listen(port, ip)
77+
http_server.listen(port, address)
7078

71-
log.info(f"Starting standaloneproxy on {ip}:{port}")
79+
log.info(f"Starting standaloneproxy on '{address}:{port}'")
7280
log.info(f"URL Prefix: {prefix!r}")
73-
log.info(f"Command: {command}")
81+
log.info(f"Command: {' '.join(command)!r}")
7482

7583
# Periodically send JupyterHub Notifications, that we are still running
7684
if use_jupyterhub and activity_interval > 0:
@@ -84,26 +92,70 @@ def run(
8492

8593
def main():
8694
parser = argparse.ArgumentParser(
87-
"jupyter-native-proxy",
88-
description="Wrap an arbitrary WebApp so it can be used in place of 'singleuser' in a JupyterHub setting",
95+
"jupyter-standalone-proxy",
96+
description="Wrap an arbitrary WebApp so it can be used in place of 'jupyterhub-singleuser' in a JupyterHub setting.",
8997
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
9098
)
9199

92100
parser.add_argument(
101+
"-p",
93102
"--port",
94-
default=None,
103+
default=0,
95104
type=int,
96-
help="Port for the proxy server to listen on. Defaults to JupyterHub default.",
105+
dest="port",
106+
help="Port for the proxy server to listen on (0 for JupyterHub default).",
107+
)
108+
parser.add_argument(
109+
"-a",
110+
"--address",
111+
default="localhost",
112+
type=str,
113+
dest="address",
114+
help="Address for the proxy server to listen on.",
97115
)
98116
parser.add_argument(
99-
"--destport",
117+
"-s",
118+
"--server-port",
100119
default=0,
101120
type=int,
102-
help="Port for the WebApp should end up running on. Leave at 0 for a random open port.",
121+
dest="server_port",
122+
help="Port for the WebApp should end up running on (0 for random open port).",
123+
)
124+
parser.add_argument(
125+
"--socket-path",
126+
type=str,
127+
default=None,
128+
help="Path to the Unix Socket to use for proxying. Takes precedence over '-s/--server_port' and '--socket-auto'.",
129+
)
130+
parser.add_argument(
131+
"--socket-auto",
132+
action="store_true",
133+
help="Use Unix Socket for proxying, but let Jupyter Server Proxy automatically create one.",
134+
)
135+
parser.add_argument(
136+
"--env",
137+
"--environment",
138+
type=lambda v: tuple(v.split(":")[:2]),
139+
default=[],
140+
action="append",
141+
dest="environment",
142+
help="Add an environment variable to the server process. Must be of the form <Name>:<Value>, e.g. --env=MY_VAR:42",
143+
)
144+
parser.add_argument(
145+
"--mappath",
146+
type=lambda v: tuple(v.split(":")[:2]),
147+
default=[],
148+
action="append",
149+
help="Add an path mapping to the proxy. Any requests received under <Source> will be redirected to <Target>. "
150+
"Must be of the form <Source>:<Target>, e.g. --mappath=/:/index.html",
103151
)
104-
parser.add_argument("--ip", default="localhost", help="Address to listen on.")
105152
parser.add_argument(
106-
"--debug", action="store_true", default=False, help="Display debug level logs."
153+
"-d",
154+
"--debug",
155+
action="store_true",
156+
default=False,
157+
dest="debug",
158+
help="Display debug level logs.",
107159
)
108160
# ToDo: Split Server and Application Logger
109161
# parser.add_argument(

jupyter_server_proxy/standalone/proxy.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,17 @@ def get_timeout(self):
3939

4040

4141
def make_proxy_app(
42-
destport,
43-
prefix,
44-
command,
45-
use_jupyterhub,
46-
timeout,
47-
debug,
48-
# progressive,
49-
websocket_max_message_size,
42+
command: list[str],
43+
prefix: str,
44+
port: int,
45+
unix_socket: bool | str,
46+
environment: dict[str, str],
47+
mappath: dict[str, str],
48+
timeout: int,
49+
use_jupyterhub: bool,
50+
debug: bool,
51+
# progressive: bool,
52+
websocket_max_message_size: int,
5053
):
5154
# Determine base class, whether or not to authenticate with JupyterHub
5255
if use_jupyterhub:
@@ -56,16 +59,21 @@ def make_proxy_app(
5659
else:
5760
proxy_base = StandaloneProxyHandler
5861

59-
# ToDo: environment & mappath
62+
app_log.debug(f"Process will use {port = }")
63+
app_log.debug(f"Process will use {unix_socket = }")
64+
app_log.debug(f"Process environment: {environment}")
65+
app_log.debug(f"Proxy mappath: {mappath}")
66+
6067
class Proxy(proxy_base):
6168
def __init__(self, *args, **kwargs):
6269
super().__init__(*args, **kwargs)
63-
self.name = command[0]
70+
self.name = f"{command[0]!r} Process"
6471
self.proxy_base = command[0]
65-
self.requested_port = destport
66-
self.mappath = {}
72+
self.requested_port = port
73+
self.requested_unix_socket = unix_socket
74+
self.mappath = mappath
6775
self.command = command
68-
self.environment = {}
76+
self.environment = environment
6977
self.timeout = timeout
7078

7179
settings = dict(
@@ -77,6 +85,7 @@ def __init__(self, *args, **kwargs):
7785
)
7886

7987
if websocket_max_message_size:
88+
app_log.debug(f"Restricting WebSocket Messages to {websocket_max_message_size}")
8089
settings["websocket_max_message_size"] = websocket_max_message_size
8190

8291
app = Application(

0 commit comments

Comments
 (0)