Skip to content

Commit 5499476

Browse files
committed
Add TermSocket back from nbclassic
#313 removed too much to nbclassic. Reverting part of it allows JupyterLab to work with the standalone jupyter server (and JupyterLab examples to work without loading other extensions like nbclassic).
1 parent 3b16335 commit 5499476

File tree

3 files changed

+70
-0
lines changed

3 files changed

+70
-0
lines changed

jupyter_server/terminal/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from tornado.log import app_log
1212
from jupyter_server.utils import url_path_join as ujoin
1313
from . import api_handlers
14+
from .handlers import TermSocket
1415

1516

1617
def initialize(webapp, root_dir, connection_url, settings):
@@ -33,6 +34,8 @@ def initialize(webapp, root_dir, connection_url, settings):
3334
terminal_manager.log = app_log
3435
base_url = webapp.settings['base_url']
3536
handlers = [
37+
(ujoin(base_url, r"/terminals/websocket/(\w+)"), TermSocket,
38+
{'term_manager': terminal_manager}),
3639
(ujoin(base_url, r"/api/terminals"), api_handlers.TerminalRootHandler),
3740
(ujoin(base_url, r"/api/terminals/(\w+)"), api_handlers.TerminalHandler),
3841
]

jupyter_server/terminal/handlers.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#encoding: utf-8
2+
"""Tornado handlers for the terminal emulator."""
3+
4+
# Copyright (c) Jupyter Development Team.
5+
# Distributed under the terms of the Modified BSD License.
6+
7+
from tornado import web
8+
import terminado
9+
from jupyter_server._tz import utcnow
10+
from ..base.handlers import JupyterHandler
11+
from ..base.zmqhandlers import WebSocketMixin
12+
13+
14+
class TermSocket(WebSocketMixin, JupyterHandler, terminado.TermSocket):
15+
16+
def origin_check(self):
17+
"""Terminado adds redundant origin_check
18+
Tornado already calls check_origin, so don't do anything here.
19+
"""
20+
return True
21+
22+
def get(self, *args, **kwargs):
23+
if not self.get_current_user():
24+
raise web.HTTPError(403)
25+
return super(TermSocket, self).get(*args, **kwargs)
26+
27+
def on_message(self, message):
28+
super(TermSocket, self).on_message(message)
29+
self.application.settings['terminal_last_activity'] = utcnow()
30+
31+
def write_message(self, message, binary=False):
32+
super(TermSocket, self).write_message(message, binary=binary)
33+
self.application.settings['terminal_last_activity'] = utcnow()

tests/test_terminal.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,37 @@ async def test_terminal_create_with_kwargs(fetch, ws_fetch, terminal_path, kill_
7070

7171
assert data['name'] == term_name
7272
await kill_all()
73+
74+
75+
async def test_terminal_create_with_cwd(fetch, ws_fetch, terminal_path):
76+
resp = await fetch(
77+
'api', 'terminals',
78+
method='POST',
79+
body=json.dumps({'cwd': str(terminal_path)}),
80+
allow_nonstandard_methods=True,
81+
)
82+
83+
data = json.loads(resp.body.decode())
84+
term_name = data['name']
85+
86+
ws = await ws_fetch(
87+
'terminals', 'websocket', term_name
88+
)
89+
90+
ws.write_message(json.dumps(['stdin', 'pwd\r\n']))
91+
92+
message_stdout = ''
93+
while True:
94+
try:
95+
message = await asyncio.wait_for(ws.read_message(), timeout=1.0)
96+
except asyncio.TimeoutError:
97+
break
98+
99+
message = json.loads(message)
100+
101+
if message[0] == 'stdout':
102+
message_stdout += message[1]
103+
104+
ws.close()
105+
106+
assert str(terminal_path) in message_stdout

0 commit comments

Comments
 (0)