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

Handle Django compatibility #3835

Merged
merged 2 commits into from
Sep 14, 2022
Merged
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
5 changes: 4 additions & 1 deletion panel/io/django.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
from contextlib import contextmanager
from urllib.parse import urljoin, urlparse

from bokeh.server.django.consumers import AutoloadJsConsumer, DocConsumer
try:
from bokeh_django.consumers import AutoloadJsConsumer, DocConsumer
except Exception:
from bokeh.server.django.consumers import AutoloadJsConsumer, DocConsumer

from ..util import edit_readonly
from .resources import Resources
Expand Down
57 changes: 41 additions & 16 deletions panel/io/document.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,40 @@ def wrapper(*args, **kw):
wrapper.lock = True # type: ignore
return wrapper

def dispatch_tornado(conn, event):
from tornado.websocket import WebSocketHandler
socket = conn._socket
ws_conn = socket.ws_connection
if not ws_conn or ws_conn.is_closing(): # type: ignore
return
msg = conn.protocol.create('PATCH-DOC', [event])
futures = [
WebSocketHandler.write_message(socket, msg.header_json),
WebSocketHandler.write_message(socket, msg.metadata_json),
WebSocketHandler.write_message(socket, msg.content_json)
]
for header, payload in msg._buffers:
futures.extend([
WebSocketHandler.write_message(socket, header),
WebSocketHandler.write_message(socket, payload, binary=True)
])
return futures

def dispatch_django(conn, event):
socket = conn._socket
msg = conn.protocol.create('PATCH-DOC', [event])
futures = [
socket.send(text_data=msg.header_json),
socket.send(text_data=msg.metadata_json),
socket.send(text_data=msg.content_json)
]
for header, payload in msg._buffers:
futures.extend([
socket.send(text_data=header),
socket.send(binary_data=payload)
])
return futures

@contextmanager
def unlocked() -> Iterator:
"""
Expand Down Expand Up @@ -160,22 +194,10 @@ def unlocked() -> Iterator:
remaining_events.append(event)
continue
for conn in connections:
socket = conn._socket
ws_conn = getattr(socket, 'ws_connection', False)
if (not hasattr(socket, 'write_message') or
ws_conn is None or (ws_conn and ws_conn.is_closing())): # type: ignore
continue
msg = conn.protocol.create('PATCH-DOC', [event])
futures.extend([
WebSocketHandler.write_message(socket, msg.header_json),
WebSocketHandler.write_message(socket, msg.metadata_json),
WebSocketHandler.write_message(socket, msg.content_json)
])
for header, payload in msg._buffers:
futures.extend([
WebSocketHandler.write_message(socket, header),
WebSocketHandler.write_message(socket, payload, binary=True)
])
if isinstance(conn._socket, WebSocketHandler):
futures += dispatch_tornado(conn, event)
else:
futures += dispatch_django(conn, event)

# Ensure that all write_message calls are awaited and handled
async def handle_write_errors():
Expand All @@ -184,6 +206,9 @@ async def handle_write_errors():
await future
except WebSocketClosedError:
logger.warning("Failed sending message as connection was closed")
except Exception as e:
logger.warning(f"Failed sending message due to following error: {e}")

asyncio.ensure_future(handle_write_errors())

curdoc.callbacks._held_events = remaining_events
Expand Down