Skip to content

Commit 0228e86

Browse files
committed
Switch from argparse to traitlets.Application and use config.ServerProcess
1 parent 941356f commit 0228e86

File tree

3 files changed

+282
-297
lines changed

3 files changed

+282
-297
lines changed

jupyter_server_proxy/standalone/__init__.py

+2-209
Original file line numberDiff line numberDiff line change
@@ -1,215 +1,8 @@
1-
from __future__ import annotations
2-
3-
import argparse
4-
import logging
5-
import os
6-
from urllib.parse import urlparse
7-
8-
from tornado import ioloop
9-
from tornado.httpserver import HTTPServer
10-
from tornado.log import app_log as log
11-
from tornado.log import enable_pretty_logging, gen_log
12-
13-
from .activity import start_activity_update
14-
from .proxy import configure_ssl, make_proxy_app
15-
16-
17-
def _default_address_and_port() -> tuple[str, int]:
18-
"""
19-
Get the Address and Port for the Proxy, either from JUPYTERHUB_SERVICE_URL or default values.
20-
See https://github.com/jupyterhub/jupyterhub/blob/4.x/jupyterhub/singleuser/mixins.py#L266-L284.
21-
"""
22-
address = "127.0.0.1"
23-
port = 8888
24-
25-
if os.environ.get("JUPYTERHUB_SERVICE_URL"):
26-
url = urlparse(os.environ["JUPYTERHUB_SERVICE_URL"])
27-
28-
if url.hostname:
29-
address = url.hostname
30-
31-
if url.port:
32-
port = url.port
33-
elif url.scheme == "http":
34-
port = 80
35-
elif url.scheme == "https":
36-
port = 443
37-
38-
return address, port
39-
40-
41-
def run(
42-
command: list[str],
43-
port: int | None,
44-
address: str | None,
45-
server_port: int,
46-
socket_path: str | None,
47-
socket_auto: bool,
48-
environment: list[tuple[str, str]] | None,
49-
mappath: list[tuple[str, str]] | None,
50-
debug: bool,
51-
# logs: bool,
52-
skip_authentication: bool,
53-
timeout: int,
54-
activity_interval: int,
55-
# progressive: bool,
56-
websocket_max_message_size: int,
57-
):
58-
# Setup Logging
59-
enable_pretty_logging(logger=log)
60-
if debug:
61-
log.setLevel(logging.DEBUG)
62-
gen_log.setLevel(logging.DEBUG)
63-
64-
address_port_default = _default_address_and_port()
65-
address = address or address_port_default[0]
66-
port = port or address_port_default[1]
67-
68-
if skip_authentication:
69-
log.warn("Disabling Authentication with JupyterHub Server!")
70-
71-
prefix = os.environ.get("JUPYTERHUB_SERVICE_PREFIX", "/")
72-
73-
app = make_proxy_app(
74-
command,
75-
prefix.removesuffix("/"),
76-
server_port,
77-
socket_path or socket_auto,
78-
dict(environment),
79-
dict(mappath),
80-
timeout,
81-
skip_authentication,
82-
debug,
83-
# progressive,
84-
websocket_max_message_size,
85-
)
86-
87-
ssl_options = configure_ssl()
88-
http_server = HTTPServer(app, ssl_options=ssl_options, xheaders=True)
89-
http_server.listen(port, address)
90-
91-
log.info(f"Starting standaloneproxy on '{address}:{port}'")
92-
log.info(f"URL Prefix: {prefix!r}")
93-
log.info(f"Command: {' '.join(command)!r}")
94-
95-
# Periodically send JupyterHub Notifications, that we are still running
96-
if activity_interval > 0:
97-
log.info(
98-
f"Sending Activity Notification to JupyterHub with interval={activity_interval}s"
99-
)
100-
start_activity_update(activity_interval)
101-
102-
ioloop.IOLoop.current().start()
1+
from .app import StandaloneProxyServer
1032

1043

1054
def main():
106-
parser = argparse.ArgumentParser(
107-
"jupyter-standalone-proxy",
108-
description="Wrap an arbitrary web service so it can be used in place of 'jupyterhub-singleuser' in a JupyterHub setting.",
109-
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
110-
)
111-
112-
parser.add_argument(
113-
"-p",
114-
"--port",
115-
type=int,
116-
dest="port",
117-
help="Set port for the proxy server to listen on. Will use 'JUPYTERHUB_SERVICE_URL' or '8888' by default.",
118-
)
119-
parser.add_argument(
120-
"-a",
121-
"--address",
122-
type=str,
123-
dest="address",
124-
help="Set address for the proxy server to listen on. Will use 'JUPYTERHUB_SERVICE_URL' or '127.0.0.1' by default.",
125-
)
126-
parser.add_argument(
127-
"-s",
128-
"--server-port",
129-
default=0,
130-
type=int,
131-
dest="server_port",
132-
help="Port for the web service should end up running on (0 for random open port).",
133-
)
134-
parser.add_argument(
135-
"--socket-path",
136-
type=str,
137-
default=None,
138-
help="Path to the Unix Socket to use for proxying. Takes precedence over '-s/--server_port' and '--socket-auto'.",
139-
)
140-
parser.add_argument(
141-
"--socket-auto",
142-
action="store_true",
143-
help="Use Unix Socket for proxying, but let jupyter-server-proxy automatically create one.",
144-
)
145-
parser.add_argument(
146-
"--env",
147-
"--environment",
148-
type=lambda v: tuple(v.split(":")[:2]),
149-
default=[],
150-
action="append",
151-
dest="environment",
152-
help="Add an environment variable to the server process. Must be of the form <Name>:<Value>, e.g. --env=MY_VAR:42",
153-
)
154-
parser.add_argument(
155-
"--mappath",
156-
type=lambda v: tuple(v.split(":")[:2]),
157-
default=[],
158-
action="append",
159-
help="Add an path mapping to the proxy. Any requests received under <Source> will be redirected to <Target>. "
160-
"Must be of the form <Source>:<Target>, e.g. --mappath=/:/index.html",
161-
)
162-
parser.add_argument(
163-
"-d",
164-
"--debug",
165-
action="store_true",
166-
default=False,
167-
dest="debug",
168-
help="Display debug level logs.",
169-
)
170-
# ToDo: Split Server and Application Logger
171-
# parser.add_argument(
172-
# "--logs",
173-
# action="store_true",
174-
# default=True,
175-
# help="Display logs generated by the subprocess.",
176-
# )
177-
parser.add_argument(
178-
"--skip-authentication",
179-
action="store_true",
180-
help="Do not enforce authentication with the JupyterHub Server.",
181-
)
182-
parser.add_argument(
183-
"--timeout",
184-
default=60,
185-
type=int,
186-
help="Timeout to wait until the subprocess has started and can be addressed.",
187-
)
188-
parser.add_argument(
189-
"--activity-interval",
190-
default=300,
191-
type=int,
192-
help="Frequency to notify Hub that the service is still running (In seconds, 0 for never).",
193-
)
194-
# ToDo: Progressive Proxy
195-
# parser.add_argument(
196-
# "--progressive",
197-
# action="store_true",
198-
# default=False,
199-
# help="Progressively flush responses as they arrive (good for Voila).",
200-
# )
201-
parser.add_argument(
202-
"--websocket-max-message-size",
203-
default=0,
204-
type=int,
205-
help="Max size of websocket data (leave at 0 for library defaults).",
206-
)
207-
parser.add_argument(
208-
"command", nargs="+", help="The command executed for starting the web service."
209-
)
210-
211-
args = parser.parse_args()
212-
run(**vars(args))
5+
StandaloneProxyServer.launch_instance()
2136

2147

2158
if __name__ == "__main__":

0 commit comments

Comments
 (0)