[FIX] web_editor: move _getNewPtp out of a closure
In a subsequent commit, we need to change the content of the method `_getNewPtp` and to patch it in tests. To make that commit more readable by understanding which lines changed, this commit moves the creation _getNewPtp to the Wysiwyg prototype rather in a closure. task-3217965 Part-of: odoo/odoo#136277
This commit is contained in:
@@ -657,149 +657,6 @@ export class Wysiwyg extends Component {
|
||||
this.busService.deleteChannel(this._collaborationChannelName);
|
||||
}
|
||||
|
||||
// Check wether clientA is before clientB.
|
||||
const isClientFirst = (clientA, clientB) => {
|
||||
if (clientA.startTime === clientB.startTime) {
|
||||
return clientA.id.localeCompare(clientB.id) < 1;
|
||||
} else {
|
||||
return clientA.startTime < clientB.startTime;
|
||||
}
|
||||
};
|
||||
const rpcMutex = new Mutex();
|
||||
|
||||
this._getNewPtp = () => {
|
||||
// Wether or not the history has been sent or received at least once.
|
||||
let historySyncAtLeastOnce = false;
|
||||
let historySyncFinished = false;
|
||||
let historyStepsBuffer = [];
|
||||
|
||||
return new PeerToPeer({
|
||||
peerConnectionConfig: { iceServers: this._iceServers },
|
||||
currentClientId: this._currentClientId,
|
||||
broadcastAll: (rpcData) => {
|
||||
return rpcMutex.exec(async () => {
|
||||
return this._serviceRpc(
|
||||
'/web_editor/bus_broadcast',
|
||||
{
|
||||
model_name: modelName,
|
||||
field_name: fieldName,
|
||||
res_id: resId,
|
||||
bus_data: rpcData,
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
onRequest: {
|
||||
get_start_time: () => this._startCollaborationTime,
|
||||
get_client_name: async () => {
|
||||
if (!this._userName) {
|
||||
const [user] = await this.orm.read(
|
||||
'res.users',
|
||||
[session.uid],
|
||||
['name'],
|
||||
);
|
||||
this._userName = user.name;
|
||||
}
|
||||
return this._userName;
|
||||
},
|
||||
get_client_avatar: () => `${browser.location.origin}/web/image?model=res.users&field=avatar_128&id=${encodeURIComponent(session.uid)}`,
|
||||
get_missing_steps: (params) => this.odooEditor.historyGetMissingSteps(params.requestPayload),
|
||||
get_history_from_snapshot: () => this.odooEditor.historyGetSnapshotSteps(),
|
||||
get_collaborative_selection: () => this.odooEditor.getCurrentCollaborativeSelection(),
|
||||
},
|
||||
onNotification: async ({ fromClientId, notificationName, notificationPayload }) => {
|
||||
switch (notificationName) {
|
||||
case 'ptp_remove':
|
||||
this.odooEditor.multiselectionRemove(notificationPayload);
|
||||
break;
|
||||
case 'rtc_signal_description':
|
||||
const pc = this.ptp.clientsInfos[fromClientId].peerConnection;
|
||||
if (this._couldBeDisconnected && this._navigatorCheckOnlineWorking && (!pc || pc.connectionState === 'closed')) {
|
||||
this._signalOnline();
|
||||
}
|
||||
break;
|
||||
case 'ptp_disconnect':
|
||||
this.ptp.removeClient(fromClientId);
|
||||
this.odooEditor.multiselectionRemove(fromClientId);
|
||||
break;
|
||||
case 'rtc_data_channel_open': {
|
||||
fromClientId = notificationPayload.connectionClientId;
|
||||
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;
|
||||
});
|
||||
this.ptp.requestClient(fromClientId, 'get_client_avatar', undefined, { transport: 'rtc' }).then(clientAvatarUrl => {
|
||||
this.ptp.clientsInfos[fromClientId].clientAvatarUrl = clientAvatarUrl;
|
||||
});
|
||||
|
||||
if (!historySyncAtLeastOnce) {
|
||||
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);
|
||||
}
|
||||
this.options.onHistoryResetFromSteps();
|
||||
}
|
||||
// In case there are steps received in the meantime, process them.
|
||||
if (historyStepsBuffer.length) {
|
||||
this.odooEditor.onExternalHistorySteps(historyStepsBuffer);
|
||||
historyStepsBuffer = [];
|
||||
}
|
||||
historySyncFinished = true;
|
||||
} else {
|
||||
const currentStep = this.odooEditor._historySteps[this.odooEditor._historySteps.length - 1];
|
||||
const remoteSelection = await this.ptp.requestClient(fromClientId, 'get_collaborative_selection', undefined, { transport: 'rtc' });
|
||||
if (remoteSelection) {
|
||||
this.odooEditor.onExternalMultiselectionUpdate(remoteSelection);
|
||||
}
|
||||
this.ptp.notifyClient(fromClientId, 'oe_history_step', currentStep, { transport: 'rtc' });
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'oe_history_step':
|
||||
// Avoid race condition where the step is received
|
||||
// before the history has synced at least once.
|
||||
if (historySyncFinished) {
|
||||
this.odooEditor.onExternalHistorySteps([notificationPayload]);
|
||||
} else {
|
||||
historyStepsBuffer.push(notificationPayload);
|
||||
}
|
||||
break;
|
||||
case 'oe_history_set_selection': {
|
||||
const client = this.ptp.clientsInfos[fromClientId];
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
const selection = notificationPayload;
|
||||
selection.clientName = client.clientName;
|
||||
selection.clientAvatarUrl = client.clientAvatarUrl;
|
||||
this.odooEditor.onExternalMultiselectionUpdate(selection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this._currentClientId = this._generateClientId();
|
||||
this._startCollaborationTime = new Date().getTime();
|
||||
|
||||
@@ -2864,6 +2721,140 @@ export class Wysiwyg extends Component {
|
||||
// No need for secure random number.
|
||||
return Math.floor(Math.random() * Math.pow(2, 52)).toString();
|
||||
}
|
||||
_getNewPtp() {
|
||||
const rpcMutex = new Mutex();
|
||||
const {collaborationChannel} = this.options;
|
||||
const modelName = collaborationChannel.collaborationModelName;
|
||||
const fieldName = collaborationChannel.collaborationFieldName;
|
||||
const resId = collaborationChannel.collaborationResId;
|
||||
|
||||
// Wether or not the history has been sent or received at least
|
||||
// once.
|
||||
this._historySyncAtLeastOnce = false;
|
||||
this._historySyncFinished = false;
|
||||
this._historyStepsBuffer = [];
|
||||
|
||||
return new PeerToPeer({
|
||||
peerConnectionConfig: { iceServers: this._iceServers },
|
||||
currentClientId: this._currentClientId,
|
||||
broadcastAll: (rpcData) => {
|
||||
return rpcMutex.exec(async () => {
|
||||
return this._serviceRpc('/web_editor/bus_broadcast', {
|
||||
model_name: modelName,
|
||||
field_name: fieldName,
|
||||
res_id: resId,
|
||||
bus_data: rpcData,
|
||||
});
|
||||
});
|
||||
},
|
||||
onRequest: {
|
||||
get_start_time: () => this._startCollaborationTime,
|
||||
get_client_name: async () => {
|
||||
if (!this._userName) {
|
||||
const [user] = await this.orm.read(
|
||||
'res.users',
|
||||
[session.uid],
|
||||
['name'],
|
||||
);
|
||||
this._userName = user.name;
|
||||
}
|
||||
return this._userName;
|
||||
},
|
||||
get_client_avatar: () => `${browser.location.origin}/web/image?model=res.users&field=avatar_128&id=${encodeURIComponent(session.uid)}`,
|
||||
get_missing_steps: (params) => this.odooEditor.historyGetMissingSteps(params.requestPayload),
|
||||
get_history_from_snapshot: () => this.odooEditor.historyGetSnapshotSteps(),
|
||||
get_collaborative_selection: () => this.odooEditor.getCurrentCollaborativeSelection(),
|
||||
},
|
||||
onNotification: async ({ fromClientId, notificationName, notificationPayload }) => {
|
||||
switch (notificationName) {
|
||||
case 'ptp_remove':
|
||||
this.odooEditor.multiselectionRemove(notificationPayload);
|
||||
break;
|
||||
case 'rtc_signal_description':
|
||||
const pc = this.ptp.clientsInfos[fromClientId].peerConnection;
|
||||
if (this._couldBeDisconnected && this._navigatorCheckOnlineWorking && (!pc || pc.connectionState === 'closed')) {
|
||||
this._signalOnline();
|
||||
}
|
||||
break;
|
||||
case 'ptp_disconnect':
|
||||
this.ptp.removeClient(fromClientId);
|
||||
this.odooEditor.multiselectionRemove(fromClientId);
|
||||
break;
|
||||
case 'rtc_data_channel_open': {
|
||||
fromClientId = notificationPayload.connectionClientId;
|
||||
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;
|
||||
});
|
||||
this.ptp.requestClient(fromClientId, 'get_client_avatar', undefined, { transport: 'rtc' }).then(clientAvatarUrl => {
|
||||
this.ptp.clientsInfos[fromClientId].clientAvatarUrl = clientAvatarUrl;
|
||||
});
|
||||
|
||||
if (!this._historySyncAtLeastOnce) {
|
||||
const localClient = { id: this._currentClientId, startTime: this._startCollaborationTime };
|
||||
const remoteClient = { id: fromClientId, startTime: remoteStartTime };
|
||||
if (isClientFirst(localClient, remoteClient)) {
|
||||
this._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 (this._historySyncAtLeastOnce) {
|
||||
return;
|
||||
}
|
||||
const firstStepId = this.odooEditor.historyGetBranchIds()[0];
|
||||
const staleDocument = !historyIds.includes(firstStepId);
|
||||
if (staleDocument) {
|
||||
return false;
|
||||
}
|
||||
this._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);
|
||||
}
|
||||
this.options.onHistoryResetFromSteps();
|
||||
}
|
||||
// In case there are steps received in the meantime, process them.
|
||||
if (this._historyStepsBuffer.length) {
|
||||
this.odooEditor.onExternalHistorySteps(this._historyStepsBuffer);
|
||||
this._historyStepsBuffer = [];
|
||||
}
|
||||
this._historySyncFinished = true;
|
||||
} else {
|
||||
const currentStep = this.odooEditor._historySteps[this.odooEditor._historySteps.length - 1];
|
||||
const remoteSelection = await this.ptp.requestClient(fromClientId, 'get_collaborative_selection', undefined, { transport: 'rtc' });
|
||||
if (remoteSelection) {
|
||||
this.odooEditor.onExternalMultiselectionUpdate(remoteSelection);
|
||||
}
|
||||
this.ptp.notifyClient(fromClientId, 'oe_history_step', currentStep, { transport: 'rtc' });
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'oe_history_step':
|
||||
if (this._historySyncFinished) {
|
||||
this.odooEditor.onExternalHistorySteps([notificationPayload]);
|
||||
} else {
|
||||
this._historyStepsBuffer.push(notificationPayload);
|
||||
}
|
||||
break;
|
||||
case 'oe_history_set_selection': {
|
||||
const client = this.ptp.clientsInfos[fromClientId];
|
||||
if (!client) {
|
||||
return;
|
||||
}
|
||||
const selection = notificationPayload;
|
||||
selection.clientName = client.clientName;
|
||||
selection.clientAvatarUrl = client.clientAvatarUrl;
|
||||
this.odooEditor.onExternalMultiselectionUpdate(selection);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
_stopPeerToPeer() {
|
||||
this.ptp && this.ptp.stop();
|
||||
this._collaborationStopBus && this._collaborationStopBus();
|
||||
@@ -3129,6 +3120,15 @@ Wysiwyg.setRange = function (startNode, startOffset = 0, endNode = startNode, en
|
||||
selection.addRange(range);
|
||||
};
|
||||
|
||||
// Check wether clientA is before clientB.
|
||||
function isClientFirst(clientA, clientB) {
|
||||
if (clientA.startTime === clientB.startTime) {
|
||||
return clientA.id.localeCompare(clientB.id) < 1;
|
||||
} else {
|
||||
return clientA.startTime < clientB.startTime;
|
||||
}
|
||||
};
|
||||
|
||||
export function stripHistoryIds(value) {
|
||||
return value && value.replace(/\sdata-last-history-steps="[^"]*?"/, '') || value;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user