Skip to content

Commit e97855f

Browse files
Support ypy-websocket v0.12 (#168)
* Support ypy-websocket v0.12 * Add type * ypy-websocket >=0.12.1
1 parent 6f89b03 commit e97855f

File tree

4 files changed

+41
-35
lines changed

4 files changed

+41
-35
lines changed

binder/environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,4 @@ dependencies:
1717
- pip:
1818
- jupyter_server_fileid >=0.7.0
1919
- jupyter_ydoc >=1.0.0
20-
- ypy-websocket >=0.8.3
20+
- ypy-websocket >=0.12.0

jupyter_collaboration/handlers.py

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,23 @@ class YDocWebSocketHandler(WebSocketHandler, JupyterHandler):
5454
"""
5555

5656
_message_queue: asyncio.Queue[Any]
57+
_background_tasks: set[asyncio.Task]
5758

58-
def initialize(
59-
self,
60-
ywebsocket_server: JupyterWebsocketServer,
61-
file_loaders: FileLoaderMapping,
62-
ystore_class: type[BaseYStore],
63-
document_cleanup_delay: float | None = 60.0,
64-
document_save_delay: float | None = 1.0,
65-
) -> None:
66-
# File ID manager cannot be passed as argument as the extension may load after this one
67-
self._file_id_manager = self.settings["file_id_manager"]
68-
self._file_loaders = file_loaders
69-
self._cleanup_delay = document_cleanup_delay
70-
self._websocket_server = ywebsocket_server
59+
def create_task(self, aw):
60+
task = asyncio.create_task(aw)
61+
self._background_tasks.add(task)
62+
task.add_done_callback(self._background_tasks.discard)
7163

72-
self._message_queue = asyncio.Queue()
64+
async def prepare(self):
65+
if not self._websocket_server.started.is_set():
66+
self.create_task(self._websocket_server.start())
67+
await self._websocket_server.started.wait()
7368

7469
# Get room
7570
self._room_id: str = self.request.path.split("/")[-1]
7671

7772
if self._websocket_server.room_exists(self._room_id):
78-
self.room: YRoom = self._websocket_server.get_room(self._room_id)
73+
self.room: YRoom = await self._websocket_server.get_room(self._room_id)
7974

8075
else:
8176
if self._room_id.count(":") >= 2:
@@ -92,7 +87,7 @@ def initialize(
9287
path = self._file_id_manager.get_path(file_id)
9388
path = Path(path)
9489
updates_file_path = str(path.parent / f".{file_type}:{path.name}.y")
95-
ystore = ystore_class(path=updates_file_path, log=self.log)
90+
ystore = self._ystore_class(path=updates_file_path, log=self.log)
9691
self.room = DocumentRoom(
9792
self._room_id,
9893
file_format,
@@ -101,16 +96,37 @@ def initialize(
10196
self.event_logger,
10297
ystore,
10398
self.log,
104-
document_save_delay,
99+
self._document_save_delay,
105100
)
106101

107102
else:
108103
# TransientRoom
109104
# it is a transient document (e.g. awareness)
110105
self.room = TransientRoom(self._room_id, self.log)
111106

107+
await self._websocket_server.start_room(self.room)
112108
self._websocket_server.add_room(self._room_id, self.room)
113109

110+
return await super().prepare()
111+
112+
def initialize(
113+
self,
114+
ywebsocket_server: JupyterWebsocketServer,
115+
file_loaders: FileLoaderMapping,
116+
ystore_class: type[BaseYStore],
117+
document_cleanup_delay: float | None = 60.0,
118+
document_save_delay: float | None = 1.0,
119+
) -> None:
120+
self._background_tasks = set()
121+
# File ID manager cannot be passed as argument as the extension may load after this one
122+
self._file_id_manager = self.settings["file_id_manager"]
123+
self._file_loaders = file_loaders
124+
self._ystore_class = ystore_class
125+
self._cleanup_delay = document_cleanup_delay
126+
self._document_save_delay = document_save_delay
127+
self._websocket_server = ywebsocket_server
128+
self._message_queue = asyncio.Queue()
129+
114130
@property
115131
def path(self):
116132
"""
@@ -150,9 +166,7 @@ async def open(self, room_id):
150166
"""
151167
On connection open.
152168
"""
153-
task = asyncio.create_task(self._websocket_server.serve(self))
154-
self._websocket_server.background_tasks.add(task)
155-
task.add_done_callback(self._websocket_server.background_tasks.discard)
169+
self.create_task(self._websocket_server.serve(self))
156170

157171
if isinstance(self.room, DocumentRoom):
158172
# Close the connection if the document session expired

jupyter_collaboration/websocketserver.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -58,21 +58,11 @@ async def clean(self):
5858
# self.log.warning(msg)
5959
# self.log.debug("Pending tasks: %r", pending)
6060

61+
self.stop()
6162
tasks = []
62-
for name, room in list(self.rooms.items()):
63-
try:
64-
self.delete_room(name=name)
65-
except Exception as e: # Capture exception as room may be auto clean
66-
msg = f"Failed to delete room {name}"
67-
self.log.debug(msg, exc_info=e)
68-
else:
69-
tasks.append(room._broadcast_task) # FIXME should be upstreamed
7063
if self.monitor_task is not None:
7164
self.monitor_task.cancel()
7265
tasks.append(self.monitor_task)
73-
for task in self.background_tasks:
74-
task.cancel() # FIXME should be upstreamed
75-
tasks.append(task)
7666

7767
if tasks:
7868
_, pending = await asyncio.wait(tasks, timeout=3)
@@ -103,7 +93,7 @@ def add_room(self, path: str, room: YRoom) -> None:
10393
"""
10494
self.rooms[path] = room
10595

106-
def get_room(self, path: str) -> YRoom:
96+
async def get_room(self, path: str) -> YRoom:
10797
"""
10898
Returns the room for the specified room ID or raises a RoomNotFound
10999
error if the room doesn't exist.
@@ -121,7 +111,9 @@ def get_room(self, path: str) -> YRoom:
121111
# Document rooms need a file
122112
raise RoomNotFound
123113

124-
return self.rooms[path]
114+
room = self.rooms[path]
115+
await self.start_room(room)
116+
return room
125117

126118
async def serve(self, websocket: WebSocketHandler) -> None:
127119
# start monitoring here as the event loop is not yet available when initializing the object

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ classifiers = [
2929
dependencies = [
3030
"jupyter_server>=2.0.0,<3.0.0",
3131
"jupyter_ydoc>=1.0.1,<2.0.0",
32-
"ypy-websocket>=0.8.3,<0.9.0",
32+
"ypy-websocket>=0.12.1,<0.13.0",
3333
"jupyter_events",
3434
"jupyter_server_fileid>=0.6.0,<1"
3535
]

0 commit comments

Comments
 (0)