66from traitlets .config import Configurable
77from tornado import httpclient
88from warnings import warn
9- from .handlers import SuperviseAndProxyHandler , AddSlashHandler , RewritableResponse
9+ from .handlers import (
10+ NamedLocalProxyHandler , SuperviseAndProxyHandler , AddSlashHandler ,
11+ )
1012import pkg_resources
1113from collections import namedtuple
1214from .utils import call_with_asked_args
1719except ImportError :
1820 from .utils import Callable
1921
20- def _make_serverproxy_handler (name , command , environment , timeout , absolute_url , port , mappath , request_headers_override , rewrite_response ):
22+
23+ LauncherEntry = namedtuple ('LauncherEntry' , ['enabled' , 'icon_path' , 'title' , 'path_info' ])
24+ ServerProcess = namedtuple ('ServerProcess' , [
25+ 'name' , 'command' , 'environment' , 'timeout' , 'absolute_url' , 'port' , 'unix_socket' ,
26+ 'mappath' , 'launcher_entry' , 'new_browser_tab' , 'request_headers_override' , 'rewrite_response' ,
27+ ])
28+
29+
30+ def _make_namedproxy_handler (sp : ServerProcess ):
31+ class _Proxy (NamedLocalProxyHandler ):
32+ def __init__ (self , * args , ** kwargs ):
33+ super ().__init__ (* args , ** kwargs )
34+ self .name = sp .name
35+ self .proxy_base = sp .name
36+ self .absolute_url = sp .absolute_url
37+ self .port = sp .port
38+ self .unix_socket = sp .unix_socket
39+ self .mappath = sp .mappath
40+ self .rewrite_response = sp .rewrite_response
41+
42+ def get_request_headers_override (self ):
43+ return self ._realize_rendered_template (sp .request_headers_override )
44+
45+ return _Proxy
46+
47+ def _make_supervisedproxy_handler (sp : ServerProcess ):
2148 """
2249 Create a SuperviseAndProxyHandler subclass with given parameters
2350 """
2451 # FIXME: Set 'name' properly
2552 class _Proxy (SuperviseAndProxyHandler ):
2653 def __init__ (self , * args , ** kwargs ):
2754 super ().__init__ (* args , ** kwargs )
28- self .name = name
29- self .command = command
30- self .proxy_base = name
31- self .absolute_url = absolute_url
32- self .requested_port = port
33- self .mappath = mappath
34- self .rewrite_response = rewrite_response
35-
36- @property
37- def process_args (self ):
38- return {
39- 'port' : self .port ,
40- 'base_url' : self .base_url ,
41- }
42-
43- def _render_template (self , value ):
44- args = self .process_args
45- if type (value ) is str :
46- return value .format (** args )
47- elif type (value ) is list :
48- return [self ._render_template (v ) for v in value ]
49- elif type (value ) is dict :
50- return {
51- self ._render_template (k ): self ._render_template (v )
52- for k , v in value .items ()
53- }
54- else :
55- raise ValueError ('Value of unrecognized type {}' .format (type (value )))
56-
57- def _realize_rendered_template (self , attribute ):
58- '''Call any callables, then render any templated values.'''
59- if callable (attribute ):
60- attribute = self ._render_template (
61- call_with_asked_args (attribute , self .process_args )
62- )
63- return self ._render_template (attribute )
64-
65- def get_cmd (self ):
66- return self ._realize_rendered_template (self .command )
55+ self .name = sp .name
56+ self .command = sp .command
57+ self .proxy_base = sp .name
58+ self .absolute_url = sp .absolute_url
59+ self .requested_port = sp .port
60+ self .requested_unix_socket = sp .unix_socket
61+ self .mappath = sp .mappath
62+ self .rewrite_response = sp .rewrite_response
6763
6864 def get_env (self ):
69- return self ._realize_rendered_template (environment )
65+ return self ._realize_rendered_template (sp . environment )
7066
7167 def get_request_headers_override (self ):
72- return self ._realize_rendered_template (request_headers_override )
68+ return self ._realize_rendered_template (sp . request_headers_override )
7369
7470 def get_timeout (self ):
75- return timeout
71+ return sp . timeout
7672
7773 return _Proxy
7874
@@ -93,30 +89,25 @@ def make_handlers(base_url, server_processes):
9389 """
9490 handlers = []
9591 for sp in server_processes :
96- handler = _make_serverproxy_handler (
97- sp . name ,
98- sp . command ,
99- sp . environment ,
100- sp .timeout ,
101- sp .absolute_url ,
102- sp . port ,
103- sp . mappath ,
104- sp . request_headers_override ,
105- sp . rewrite_response ,
106- )
92+ if sp . command :
93+ handler = _make_supervisedproxy_handler ( sp )
94+ kwargs = dict ( state = {})
95+ else :
96+ if not ( sp .port or isinstance ( sp . unix_socket , str )):
97+ warn ( f"Server proxy { sp .name } does not have a command, port "
98+ f"number or unix_socket path. At least one of these is "
99+ f"required." )
100+ continue
101+ handler = _make_namedproxy_handler ( sp )
102+ kwargs = {}
107103 handlers .append ((
108- ujoin (base_url , sp .name , r'(.*)' ), handler , dict ( state = {}) ,
104+ ujoin (base_url , sp .name , r'(.*)' ), handler , kwargs ,
109105 ))
110106 handlers .append ((
111107 ujoin (base_url , sp .name ), AddSlashHandler
112108 ))
113109 return handlers
114110
115- LauncherEntry = namedtuple ('LauncherEntry' , ['enabled' , 'icon_path' , 'title' , 'path_info' ])
116- ServerProcess = namedtuple ('ServerProcess' , [
117- 'name' , 'command' , 'environment' , 'timeout' , 'absolute_url' , 'port' ,
118- 'mappath' , 'launcher_entry' , 'new_browser_tab' , 'request_headers_override' , 'rewrite_response' ,
119- ])
120111
121112def make_server_process (name , server_process_config , serverproxy_config ):
122113 le = server_process_config .get ('launcher_entry' , {})
@@ -127,6 +118,7 @@ def make_server_process(name, server_process_config, serverproxy_config):
127118 timeout = server_process_config .get ('timeout' , 5 ),
128119 absolute_url = server_process_config .get ('absolute_url' , False ),
129120 port = server_process_config .get ('port' , 0 ),
121+ unix_socket = server_process_config .get ('unix_socket' , None ),
130122 mappath = server_process_config .get ('mappath' , {}),
131123 launcher_entry = LauncherEntry (
132124 enabled = le .get ('enabled' , True ),
@@ -154,8 +146,9 @@ class ServerProxy(Configurable):
154146 Value should be a dictionary with the following keys:
155147 command
156148 An optional list of strings that should be the full command to be executed.
157- The optional template arguments {{port}} and {{base_url}} will be substituted with the
158- port the process should listen on and the base-url of the notebook.
149+ The optional template arguments {{port}}, {{unix_socket}} and {{base_url}}
150+ will be substituted with the port or Unix socket path the process should
151+ listen on and the base-url of the notebook.
159152
160153 Could also be a callable. It should return a list.
161154
@@ -165,7 +158,7 @@ class ServerProxy(Configurable):
165158
166159 environment
167160 A dictionary of environment variable mappings. As with the command
168- traitlet, {{port}} and {{base_url}} will be substituted.
161+ traitlet, {{port}}, {{unix_socket}} and {{base_url}} will be substituted.
169162
170163 Could also be a callable. It should return a dictionary.
171164
@@ -179,6 +172,13 @@ class ServerProxy(Configurable):
179172 port
180173 Set the port that the service will listen on. The default is to automatically select an unused port.
181174
175+ unix_socket
176+ If set, the service will listen on a Unix socket instead of a TCP port.
177+ Set to True to use a socket in a new temporary folder, or a string
178+ path to a socket. This overrides port.
179+
180+ Proxying websockets over a Unix socket requires Tornado >= 6.3.
181+
182182 mappath
183183 Map request paths to proxied paths.
184184 Either a dictionary of request paths to proxied paths,
@@ -210,7 +210,7 @@ class ServerProxy(Configurable):
210210
211211 request_headers_override
212212 A dictionary of additional HTTP headers for the proxy request. As with
213- the command traitlet, {{port}} and {{base_url}} will be substituted.
213+ the command traitlet, {{port}}, {{unix_socket}} and {{base_url}} will be substituted.
214214
215215 rewrite_response
216216 An optional function to rewrite the response for the given service.
0 commit comments