Skip to content

Commit 16d0b68

Browse files
committed
Reuse same provider if already exists
1 parent 22d61a5 commit 16d0b68

File tree

2 files changed

+68
-87
lines changed

2 files changed

+68
-87
lines changed

packages/my-shared-docprovider/src/drive.ts

Lines changed: 65 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -153,95 +153,78 @@ export class MySharedDrive extends Drive implements ICollaborativeDrive {
153153

154154
private _onCreate = (
155155
options: Contents.ISharedFactoryOptions,
156-
sharedModel: YDocument<DocumentChange>
157-
) => {
156+
): YDocument<DocumentChange> => {
158157
if (typeof options.format !== 'string') {
159-
return;
158+
const factory = (
159+
this.sharedModelFactory as SharedModelFactory
160+
).documentFactories.get(options.contentType)!;
161+
const sharedModel = factory(options);
162+
return sharedModel;
160163
}
161-
try {
162-
const provider = new MyProvider({
163-
path: options.path,
164-
format: options.format,
165-
contentType: options.contentType,
166-
model: sharedModel,
167-
user: this._user,
168-
translator: this._trans
169-
});
170164

171-
this._app.serviceManager.contents.get(options.path, { content: true }).then(model => {
172-
const content = model.format === 'base64' ? atob(model.content) : model.content;
173-
provider.setSource(content);
174-
});
165+
const key = `${options.format}:${options.contentType}:${options.path}`;
175166

176-
const key = `${options.format}:${options.contentType}:${options.path}`;
177-
this._providers.set(key, provider);
167+
// Check if shared model alread exists.
168+
const _provider = this._providers.get(key);
169+
if (_provider) {
170+
return _provider.model;
171+
}
178172

179-
sharedModel.ydoc.on('update' , (update, origin) => {
180-
if (origin === this) {
181-
return;
182-
}
183-
this._saveLock.promise.then(() => {
184-
this._saveLock.enable();
185-
let content = sharedModel.getSource();
186-
sharedModel.ydoc.transact( () => {
187-
sharedModel.ystate.set('dirty', false);
188-
}, this);
189-
if (options.format === 'text' && typeof content === 'object') {
190-
content = JSON.stringify(content);
191-
}
192-
this._app.serviceManager.contents.save(options.path, {content, format: options.format, type: options.contentType})
193-
.then(() => {
194-
this._saveLock.disable();
195-
});
196-
});
197-
});
173+
const factory = (
174+
this.sharedModelFactory as SharedModelFactory
175+
).documentFactories.get(options.contentType)!;
176+
const sharedModel = factory(options);
177+
sharedModel.changed.connect((_: any, event: any) => {
178+
if (!event.stateChange) {
179+
sharedModel.ystate.set('dirty', false);
180+
}
181+
});
198182

199-
sharedModel.changed.connect(async (_, change) => {
200-
if (!change.stateChange) {
201-
return;
202-
}
203-
const hashChanges = change.stateChange.filter(
204-
change => change.name === 'hash'
205-
);
206-
if (hashChanges.length === 0) {
207-
return;
208-
}
209-
if (hashChanges.length > 1) {
210-
console.error(
211-
'Unexpected multiple changes to hash value in a single transaction'
212-
);
183+
const provider = new MyProvider({
184+
path: options.path,
185+
format: options.format,
186+
contentType: options.contentType,
187+
model: sharedModel,
188+
user: this._user,
189+
translator: this._trans
190+
});
191+
192+
this._providers.set(key, provider);
193+
194+
this._app.serviceManager.contents.get(options.path, { content: true }).then(model => {
195+
const content = model.format === 'base64' ? atob(model.content) : model.content;
196+
provider.setSource(content);
197+
});
198+
199+
sharedModel.ydoc.on('update' , (update, origin) => {
200+
if (origin === this) {
201+
return;
202+
}
203+
this._saveLock.promise.then(() => {
204+
this._saveLock.enable();
205+
let content = sharedModel.getSource();
206+
sharedModel.ydoc.transact( () => {
207+
sharedModel.ystate.set('dirty', false);
208+
}, this);
209+
if (options.format === 'text' && typeof content === 'object') {
210+
content = JSON.stringify(content);
213211
}
214-
const hashChange = hashChanges[0];
215-
216-
// A change in hash signifies that a save occurred on the server-side
217-
// (e.g. a collaborator performed the save) - we want to notify the
218-
// observers about this change so that they can store the new hash value.
219-
const newPath = sharedModel.state.path ?? options.path;
220-
const model = await this.get(newPath as string, { content: false });
221-
222-
this._ydriveFileChanged.emit({
223-
type: 'save',
224-
newValue: { ...model, hash: hashChange.newValue },
225-
// we do not have the old model because it was discarded when server made the change,
226-
// we only have the old hash here (which may be empty if the file was newly created!)
227-
oldValue: { hash: hashChange.oldValue }
212+
this._app.serviceManager.contents.save(options.path, {content, format: options.format, type: options.contentType})
213+
.then(() => {
214+
this._saveLock.disable();
228215
});
229216
});
217+
});
230218

231-
sharedModel.disposed.connect(() => {
232-
const provider = this._providers.get(key);
233-
if (provider) {
234-
provider.dispose();
235-
this._providers.delete(key);
236-
}
237-
});
238-
} catch (error) {
239-
// Falling back to the contents API if opening the websocket failed
240-
// This may happen if the shared document is not a YDocument.
241-
console.error(
242-
`Failed to open connection for ${options.path}.\n:${error}`
243-
);
244-
}
219+
sharedModel.disposed.connect(() => {
220+
const provider = this._providers.get(key);
221+
if (provider) {
222+
provider.dispose();
223+
this._providers.delete(key);
224+
}
225+
});
226+
227+
return sharedModel;
245228
};
246229

247230
private _app: JupyterFrontEnd;
@@ -266,8 +249,7 @@ class SharedModelFactory implements ISharedModelFactory {
266249
constructor(
267250
private _onCreate: (
268251
options: Contents.ISharedFactoryOptions,
269-
sharedModel: YDocument<DocumentChange>
270-
) => void
252+
) => YDocument<DocumentChange>
271253
) {
272254
this.documentFactories = new Map();
273255
}
@@ -311,10 +293,9 @@ class SharedModelFactory implements ISharedModelFactory {
311293
// the `sharedModel` will be the default one.
312294
return;
313295
}
296+
314297
if (this.documentFactories.has(options.contentType)) {
315-
const factory = this.documentFactories.get(options.contentType)!;
316-
const sharedModel = factory(options);
317-
this._onCreate(options, sharedModel);
298+
const sharedModel = this._onCreate(options);
318299
return sharedModel;
319300
}
320301

packages/my-shared-docprovider/src/yprovider.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export class MyProvider implements IDocumentProvider {
2929
this._contentType = options.contentType;
3030
this._format = options.format;
3131
this._awareness = options.model.awareness;
32-
this._model = options.model;
32+
this.model = options.model;
3333

3434
const user = options.user;
3535

@@ -42,7 +42,7 @@ export class MyProvider implements IDocumentProvider {
4242
}
4343

4444
setSource(value: any): void {
45-
this._model.setSource(value);
45+
this.model.setSource(value);
4646
this._ready.resolve();
4747
}
4848

@@ -86,7 +86,7 @@ export class MyProvider implements IDocumentProvider {
8686
private _format: string;
8787
private _isDisposed: boolean;
8888
private _ready = new PromiseDelegate<void>();
89-
private _model: YDocument<DocumentChange>;
89+
model: YDocument<DocumentChange>;
9090
}
9191

9292
/**

0 commit comments

Comments
 (0)