diff --git a/pyproject.toml b/pyproject.toml index 457931f..a8a9b8f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,17 +11,17 @@ requires = [ name = "yjs-widgets" readme = "README.md" license = { file = "LICENSE" } -requires-python = ">=3.7" +requires-python = ">=3.9" dependencies = [] classifiers = [ "License :: OSI Approved :: BSD License", "Programming Language :: Python", "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", "Framework :: Jupyter", "Framework :: Jupyter :: JupyterLab", "Framework :: Jupyter :: JupyterLab :: 3", diff --git a/src/model.ts b/src/model.ts index 52455da..12e85ef 100644 --- a/src/model.ts +++ b/src/model.ts @@ -3,6 +3,7 @@ import { JSONExt, JSONObject, PromiseDelegate } from '@lumino/coreutils'; import { ISignal, Signal } from '@lumino/signaling'; import * as Y from 'yjs'; +import { YCommProvider } from './notebookrenderer/yCommProvider'; import { IJupyterYDoc, IJupyterYModel } from './types'; export class JupyterYModel implements IJupyterYModel { @@ -13,6 +14,14 @@ export class JupyterYModel implements IJupyterYModel { }); } + onReceive(callback: (message: Uint8Array) => void) { + this.yCommProvider.onReceive(callback); + } + + send(message: Uint8Array) { + this.yCommProvider.send(message); + } + get yModelName(): string { return this._yModelName; } @@ -76,6 +85,7 @@ export class JupyterYModel implements IJupyterYModel { this.sharedModel.removeAttr(key); } + yCommProvider: YCommProvider; private _ydoc: Y.Doc; private _yModelName: string; diff --git a/src/notebookrenderer/widgetManager.ts b/src/notebookrenderer/widgetManager.ts index ad2d219..47474f3 100644 --- a/src/notebookrenderer/widgetManager.ts +++ b/src/notebookrenderer/widgetManager.ts @@ -71,11 +71,12 @@ export class WidgetModelRegistry implements IJupyterYWidgetModelRegistry { await yModel.ready; - new YCommProvider({ + const yCommProvider = new YCommProvider({ comm, ydoc: yModel.sharedModel.ydoc }); this._yModels.set(comm.commId, yModel); + yModel.yCommProvider = yCommProvider; }; private _yModels: Map = new Map(); diff --git a/src/notebookrenderer/yCommProvider.ts b/src/notebookrenderer/yCommProvider.ts index 9d221cd..99a9e82 100644 --- a/src/notebookrenderer/yCommProvider.ts +++ b/src/notebookrenderer/yCommProvider.ts @@ -17,6 +17,16 @@ export class YCommProvider implements IDisposable { this._connect(); } + onReceive(callback: (message: Uint8Array) => void) { + this._onReceive = callback; + } + + send(message: Uint8Array) { + const messageType = new Uint8Array([2]); + const msg = new Uint8Array([...messageType, ...message]); + this._sendOverComm(msg); + } + get doc(): Y.Doc { return this._ydoc; } @@ -47,9 +57,15 @@ export class YCommProvider implements IDisposable { const buffer_uint8 = new Uint8Array( ArrayBuffer.isView(buffer) ? buffer.buffer : buffer ); - const encoder = Private.readMessage(this, buffer_uint8, true); - if (encoding.length(encoder) > 1) { - this._sendOverComm(encoding.toUint8Array(encoder)); + if (buffer_uint8.slice(0, 1)[0] === 2) { + if (this._onReceive !== null) { + this._onReceive(buffer_uint8.slice(1)); + } + } else { + const encoder = Private.readMessage(this, buffer_uint8, true); + if (encoding.length(encoder) > 1) { + this._sendOverComm(encoding.toUint8Array(encoder)); + } } } }; @@ -81,6 +97,7 @@ export class YCommProvider implements IDisposable { private _ydoc: Y.Doc; private _synced: boolean; private _isDisposed = false; + private _onReceive: ((message: Uint8Array) => void) | null = null; } namespace Private { diff --git a/src/types.ts b/src/types.ts index 1fbd7c4..0442c92 100644 --- a/src/types.ts +++ b/src/types.ts @@ -3,6 +3,7 @@ import * as Y from 'yjs'; import { ISignal } from '@lumino/signaling'; import { JSONObject } from '@lumino/coreutils'; import { IDisposable } from '@lumino/disposable'; +import { YCommProvider } from './notebookrenderer/yCommProvider'; export interface IJupyterYDocChange { attrsChange?: MapChange; @@ -26,10 +27,14 @@ export interface IJupyterYModel extends IDisposable { yModelName: string; isDisposed: boolean; sharedModel: IJupyterYDoc; + yCommProvider: YCommProvider; sharedAttrsChanged: ISignal; disposed: ISignal; ready: Promise; + + send(message: Uint8Array); + onReceive(callback: (message: Uint8Array) => void); }