Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support suggestions #239

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion jupyter_collaboration/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pycrdt_websocket.ystore import BaseYStore
from traitlets import Bool, Float, Type

from .handlers import DocSessionHandler, YDocWebSocketHandler
from .handlers import DocForkHandler, DocDeleteHandler, DocMergeHandler, DocSessionHandler, YDocWebSocketHandler
from .loaders import FileLoaderMapping
from .stores import SQLiteYStore
from .utils import AWARENESS_EVENTS_SCHEMA_PATH, EVENTS_SCHEMA_PATH
Expand Down Expand Up @@ -109,6 +109,27 @@ def initialize_handlers(self):
},
),
(r"/api/collaboration/session/(.*)", DocSessionHandler),
(
r"/api/collaboration/fork_room/(.*)",
DocForkHandler,
{
"ywebsocket_server": self.ywebsocket_server,
}
),
(
r"/api/collaboration/merge_room",
DocMergeHandler,
{
"ywebsocket_server": self.ywebsocket_server,
}
),
(
r"/api/collaboration/delete_room",
DocDeleteHandler,
{
"ywebsocket_server": self.ywebsocket_server,
}
),
]
)

Expand Down
123 changes: 120 additions & 3 deletions jupyter_collaboration/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@
import asyncio
import json
import time
import uuid
from uuid import uuid4
from typing import Any

from jupyter_server.auth import authorized
from jupyter_server.base.handlers import APIHandler, JupyterHandler
from jupyter_ydoc import ydocs as YDOCS
from pycrdt_websocket.websocket_server import YRoom
from pycrdt import Doc, Map
from pycrdt_websocket.yroom import YRoom
from pycrdt_websocket.ystore import BaseYStore
from pycrdt_websocket.yutils import YMessageType, write_var_uint
from tornado import web
Expand All @@ -31,7 +32,7 @@

YFILE = YDOCS["file"]

SERVER_SESSION = str(uuid.uuid4())
SERVER_SESSION = str(uuid4())


class YDocWebSocketHandler(WebSocketHandler, JupyterHandler):
Expand Down Expand Up @@ -404,3 +405,119 @@ async def put(self, path):
)
self.set_status(201)
return self.finish(data)


class DocForkHandler(APIHandler):
"""
Jupyter Server's handler to fork a document.
"""

auth_resource = "contents"

def initialize(
self,
ywebsocket_server: JupyterWebsocketServer,
) -> None:
self._websocket_server = ywebsocket_server

@web.authenticated
@authorized
async def put(self, room_id):
"""
Creates a fork of a root document and returns its ID.
"""
idx = uuid4().hex

root_room = await self._websocket_server.get_room(room_id)
update = root_room.ydoc.get_update()
fork_ydoc = Doc()
fork_ydoc.apply_update(update)
fork_room = YRoom(ydoc=fork_ydoc)
self._websocket_server.add_room(idx, fork_room)
root_room.fork_ydocs.add(fork_ydoc)
data = json.dumps({
"sessionId": SERVER_SESSION,
"roomId": idx,
})
self.set_status(201)
return self.finish(data)


class DocMergeHandler(APIHandler):
"""
Jupyter Server's handler to merge a document.
"""

auth_resource = "contents"

def initialize(
self,
ywebsocket_server: JupyterWebsocketServer,
) -> None:
self._websocket_server = ywebsocket_server

@web.authenticated
@authorized
async def put(self):
"""
Merges back a fork into a root document.
"""
model = self.get_json_body()
fork_roomid = model["fork_roomid"]
root_room = await self._websocket_server.get_room(model["root_roomid"])
root_ydoc = root_room.ydoc
idx = f"fork_{fork_roomid}"
root_state = root_ydoc.get("state", type=Map)
if idx in root_state:
del root_state[idx]
else:
self.set_status(404)
raise RuntimeError(f"Could not find root document fork with ID: {fork_roomid}")
fork_room = await self._websocket_server.get_room(fork_roomid)
fork_ydoc = fork_room.ydoc
fork_update = fork_ydoc.get_update()
root_ydoc.apply_update(fork_update)
root_room.fork_ydocs.remove(fork_ydoc)
fork_state = fork_ydoc.get("state", type=Map)
fork_state["merge"] = fork_roomid
#self._websocket_server.delete_room(name=fork_roomid)
self.set_status(200)


class DocDeleteHandler(APIHandler):
"""
Jupyter Server's handler to delete a document.
"""

auth_resource = "contents"

def initialize(
self,
ywebsocket_server: JupyterWebsocketServer,
) -> None:
self._websocket_server = ywebsocket_server

@web.authenticated
@authorized
async def delete(self):
"""
Deletes a forked document.
"""
model = self.get_json_body()
fork_roomid = model["fork_roomid"]
root_room = await self._websocket_server.get_room(model["root_roomid"])
root_ydoc = root_room.ydoc
idx = f"fork_{fork_roomid}"
root_state = root_ydoc.get("state", type=Map)
if idx in root_state:
del root_state[idx]
else:
self.set_status(404)
raise RuntimeError(f"Could not find root document fork with ID: {fork_roomid}")
fork_room = await self._websocket_server.get_room(fork_roomid)
fork_ydoc = fork_room.ydoc
root_room.fork_ydocs.remove(fork_ydoc)
fork_state = fork_ydoc.get("state", type=Map)
fork_state["delete"] = fork_roomid
#self._websocket_server.delete_room(name=fork_roomid)
self.set_status(200)
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,8 @@
"stylelint-prettier": "^3.0.0",
"typedoc": "~0.23.28",
"typescript": "~5.0.4"
},
"resolutions": {
"@jupyter/ydoc": "file:.yalc/@jupyter/ydoc"
}
}
2 changes: 1 addition & 1 deletion packages/collaboration-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"dependencies": {
"@jupyter/collaboration": "^2.0.11",
"@jupyter/docprovider": "^2.0.11",
"@jupyter/ydoc": "^1.1.0-a0",
"@jupyter/ydoc": "file:.yalc/@jupyter/ydoc",
"@jupyterlab/application": "^4.0.5",
"@jupyterlab/apputils": "^4.0.5",
"@jupyterlab/codemirror": "^4.0.5",
Expand Down
Loading
Loading