mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-21 07:56:16 -04:00
PadMessageHandler: Accept retransmissions of USER_CHANGES
This commit is contained in:
parent
a370cfa5c6
commit
cff089e54e
3 changed files with 10 additions and 13 deletions
|
@ -615,19 +615,15 @@ const handleUserChanges = async (socket, message) => {
|
||||||
// Update the changeset so that it can be applied to the latest revision.
|
// Update the changeset so that it can be applied to the latest revision.
|
||||||
while (r < pad.getHeadRevisionNumber()) {
|
while (r < pad.getHeadRevisionNumber()) {
|
||||||
r++;
|
r++;
|
||||||
|
const {changeset: c, meta: {author: authorId}} = await pad.getRevision(r);
|
||||||
const c = await pad.getRevisionChangeset(r);
|
if (changeset === c && thisSession.author === authorId) {
|
||||||
|
// Assume this is a retransmission of an already applied changeset.
|
||||||
|
rebasedChangeset = Changeset.identity(Changeset.unpack(changeset).oldLen);
|
||||||
|
}
|
||||||
// At this point, both "c" (from the pad) and "changeset" (from the
|
// At this point, both "c" (from the pad) and "changeset" (from the
|
||||||
// client) are relative to revision r - 1. The follow function
|
// client) are relative to revision r - 1. The follow function
|
||||||
// rebases "changeset" so that it is relative to revision r
|
// rebases "changeset" so that it is relative to revision r
|
||||||
// and can be applied after "c".
|
// and can be applied after "c".
|
||||||
|
|
||||||
// a changeset can be based on an old revision with the same changes in it
|
|
||||||
// prevent eplite from accepting it TODO: better send the client a NEW_CHANGES
|
|
||||||
// of that revision
|
|
||||||
if (baseRev + 1 === r && c === changeset) throw new Error('Changeset already accepted');
|
|
||||||
|
|
||||||
rebasedChangeset = Changeset.follow(c, rebasedChangeset, false, pad.pool);
|
rebasedChangeset = Changeset.follow(c, rebasedChangeset, false, pad.pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -208,8 +208,9 @@ const getCollabClient = (ace2editor, serverVars, initialUserInfo, options, _pad)
|
||||||
} else if (msg.type === 'ACCEPT_COMMIT') {
|
} else if (msg.type === 'ACCEPT_COMMIT') {
|
||||||
serverMessageTaskQueue.enqueue(() => {
|
serverMessageTaskQueue.enqueue(() => {
|
||||||
const {newRev} = msg;
|
const {newRev} = msg;
|
||||||
// newRev will equal rev if the changeset has no net effect (identity changeset, or removing
|
// newRev will equal rev if the changeset has no net effect (identity changeset, removing
|
||||||
// and re-adding the same characters with the same attributes).
|
// and re-adding the same characters with the same attributes, or retransmission of an
|
||||||
|
// already applied changeset).
|
||||||
if (![rev, rev + 1].includes(newRev)) {
|
if (![rev, rev + 1].includes(newRev)) {
|
||||||
window.console.warn(`bad message revision on ACCEPT_COMMIT: ${newRev} not ${rev + 1}`);
|
window.console.warn(`bad message revision on ACCEPT_COMMIT: ${newRev} not ${rev + 1}`);
|
||||||
// setChannelState("DISCONNECTED", "badmessage_acceptcommit");
|
// setChannelState("DISCONNECTED", "badmessage_acceptcommit");
|
||||||
|
|
|
@ -75,12 +75,12 @@ describe(__filename, function () {
|
||||||
await assertRejected();
|
await assertRejected();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('retransmission is rejected', async function () {
|
it('retransmission is accepted, has no effect', async function () {
|
||||||
sendUserChanges('Z:1>5+5$hello');
|
sendUserChanges('Z:1>5+5$hello');
|
||||||
await assertAccepted(rev + 1);
|
await assertAccepted(rev + 1);
|
||||||
--rev;
|
--rev;
|
||||||
sendUserChanges('Z:1>5+5$hello');
|
sendUserChanges('Z:1>5+5$hello');
|
||||||
await assertRejected();
|
await assertAccepted(rev + 1);
|
||||||
assert.equal(pad.text(), 'hello\n');
|
assert.equal(pad.text(), 'hello\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue