[FIX] web_editor: prevent corruption from stale document
When a peer "A" connect to the peer to peer network, if he receive a stale document from a peer "B", peer "A" will never be able to save. This situation can make impossible for any new peer to receive a converging document and block the ability to save until every peer disconnect from the network. task-3196778 closes odoo/odoo#114268 X-original-commit: 537f34f764fae3967496d466c420d72d172b241d Signed-off-by: David Monjoie (dmo) <dmo@odoo.com>
This commit is contained in:
@@ -519,7 +519,8 @@ const Wysiwyg = Widget.extend({
|
||||
break;
|
||||
case 'rtc_data_channel_open': {
|
||||
fromClientId = notificationPayload.connectionClientId;
|
||||
this.ptp.clientsInfos[fromClientId].startTime = await this.ptp.requestClient(fromClientId, 'get_start_time', undefined, { transport: 'rtc' });
|
||||
const remoteStartTime = await this.ptp.requestClient(fromClientId, 'get_start_time', undefined, { transport: 'rtc' });
|
||||
this.ptp.clientsInfos[fromClientId].startTime = remoteStartTime;
|
||||
this.ptp.requestClient(fromClientId, 'get_client_name', undefined, { transport: 'rtc' }).then((clientName) => {
|
||||
this.ptp.clientsInfos[fromClientId].clientName = clientName;
|
||||
});
|
||||
@@ -528,8 +529,30 @@ const Wysiwyg = Widget.extend({
|
||||
});
|
||||
|
||||
if (!historySyncAtLeastOnce) {
|
||||
historySyncAtLeastOnce = true;
|
||||
await editorCollaborationOptions.onHistoryNeedSync();
|
||||
const localClient = { id: this._currentClientId, startTime: this._startCollaborationTime };
|
||||
const remoteClient = { id: fromClientId, startTime: remoteStartTime };
|
||||
if (isClientFirst(localClient, remoteClient)) {
|
||||
historySyncAtLeastOnce = true;
|
||||
} else {
|
||||
const { steps, historyIds } = await this.ptp.requestClient(fromClientId, 'get_history_from_snapshot', undefined, { transport: 'rtc' });
|
||||
// Ensure that the history hasn't been
|
||||
// synced by another client before this
|
||||
// `get_history_from_snapshot` finished.
|
||||
if (historySyncAtLeastOnce) {
|
||||
return;
|
||||
}
|
||||
const firstStepId = this.odooEditor.historyGetBranchIds()[0];
|
||||
const staleDocument = !historyIds.includes(firstStepId);
|
||||
if (staleDocument) {
|
||||
return false;
|
||||
}
|
||||
historySyncAtLeastOnce = true;
|
||||
this.odooEditor.historyResetFromSteps(steps, historyIds);
|
||||
const remoteSelection = await this.ptp.requestClient(fromClientId, 'get_collaborative_selection', undefined, { transport: 'rtc' });
|
||||
if (remoteSelection) {
|
||||
this.odooEditor.onExternalMultiselectionUpdate(remoteSelection);
|
||||
}
|
||||
}
|
||||
historySyncFinished = true;
|
||||
} else {
|
||||
const remoteSelection = await this.ptp.requestClient(fromClientId, 'get_collaborative_selection', undefined, { transport: 'rtc' });
|
||||
@@ -646,44 +669,6 @@ const Wysiwyg = Widget.extend({
|
||||
}
|
||||
this.ptp && this.odooEditor.onExternalHistorySteps(missingSteps.concat([step]));
|
||||
},
|
||||
onHistoryNeedSync: async () => {
|
||||
if (!this.ptp) return;
|
||||
let firstClientId = this._currentClientId;
|
||||
let firstClientStartTime = this._startCollaborationTime;
|
||||
const connectedClientIds = this.ptp.getConnectedClientIds();
|
||||
for (const clientId of connectedClientIds) {
|
||||
const clientInfo = this.ptp.clientsInfos[clientId];
|
||||
// Ensure we already retreived remote client starting time.
|
||||
if (!clientInfo.startTime) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const isCurrentClientFirst = isClientFirst(
|
||||
{
|
||||
startTime: clientInfo.startTime,
|
||||
id: clientId,
|
||||
},
|
||||
{
|
||||
startTime: firstClientStartTime,
|
||||
id: firstClientId,
|
||||
}
|
||||
);
|
||||
|
||||
if (isCurrentClientFirst) {
|
||||
firstClientStartTime = clientInfo.startTime;
|
||||
firstClientId = clientId;
|
||||
}
|
||||
}
|
||||
|
||||
if (firstClientId !== this._currentClientId) {
|
||||
const { steps, historyIds } = await this.ptp.requestClient(firstClientId, 'get_history_from_snapshot', undefined, { transport: 'rtc' });
|
||||
this.odooEditor.historyResetFromSteps(steps, historyIds);
|
||||
const remoteSelection = await this.ptp.requestClient(firstClientId, 'get_collaborative_selection', undefined, { transport: 'rtc' });
|
||||
if (remoteSelection) {
|
||||
this.odooEditor.onExternalMultiselectionUpdate(remoteSelection);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
return editorCollaborationOptions;
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user