merge consecutive updates into a single request
This commit is contained in:
parent
bac6305cb7
commit
bf301ad79a
|
|
@ -426,16 +426,6 @@ $(function (){
|
||||||
return name.slice(0, 20) + '…';
|
return name.slice(0, 20) + '…';
|
||||||
}
|
}
|
||||||
|
|
||||||
const PacoSakoUUID = 'b425b812-6bdb-11ea-9414-6f946662bac3'; /* V2 & V3 releases */
|
|
||||||
|
|
||||||
function putState() {
|
|
||||||
const boardElem = $('#cb_board');
|
|
||||||
const gameId = boardElem.data('gameId');
|
|
||||||
const moves = { past: currentGame.moves, future: currentGame.redoMoves };
|
|
||||||
boardElem.data('last_state', currentGame.moves);
|
|
||||||
putMeta({ board: moves });
|
|
||||||
}
|
|
||||||
|
|
||||||
let noticeBox = null;
|
let noticeBox = null;
|
||||||
|
|
||||||
function openNoticeBox(content) {
|
function openNoticeBox(content) {
|
||||||
|
|
@ -465,16 +455,13 @@ $(function (){
|
||||||
const updateQueue = {
|
const updateQueue = {
|
||||||
head: 0, /* next item to be sent */
|
head: 0, /* next item to be sent */
|
||||||
tail: 0, /* ID to assign to the next update added to the queue */
|
tail: 0, /* ID to assign to the next update added to the queue */
|
||||||
lastGameId: null,
|
|
||||||
lastModified: null,
|
|
||||||
newModified: 0,
|
|
||||||
sending: false,
|
sending: false,
|
||||||
|
|
||||||
add(gameId, data, modified) {
|
add(gameId, data, modified) {
|
||||||
const wasEmpty = this.head === this.tail;
|
const wasEmpty = this.isEmpty();
|
||||||
data = Object.assign({}, data, { modified });
|
data = Object.assign({}, data, { modified });
|
||||||
|
|
||||||
this[this.tail] = { gameId, data, modified };
|
this[this.tail] = { gameId, data };
|
||||||
this.tail += 1;
|
this.tail += 1;
|
||||||
|
|
||||||
if (!this.sending) {
|
if (!this.sending) {
|
||||||
|
|
@ -484,37 +471,70 @@ $(function (){
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isEmpty() {
|
||||||
|
return this.head === this.tail;
|
||||||
|
},
|
||||||
|
|
||||||
|
peek() {
|
||||||
|
if (!this.isEmpty()) {
|
||||||
|
return this[this.head];
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
if (!this.isEmpty()) {
|
||||||
|
const first = this[this.head];
|
||||||
|
delete this[this.head];
|
||||||
|
this.head += 1;
|
||||||
|
return first;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
sendNext() {
|
sendNext() {
|
||||||
const queue = this;
|
const queue = this;
|
||||||
|
const update = queue.remove();
|
||||||
|
|
||||||
if (queue.head === queue.tail) {
|
if (update === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const update = queue[queue.head];
|
/* merge updates for the same game with the same baseline into a single request */
|
||||||
delete queue[queue.head];
|
let peek;
|
||||||
queue.head += 1;
|
while ((peek = queue.peek()) !== undefined && peek.gameId === update.gameId
|
||||||
|
&& peek.data.modified === update.data.modified) {
|
||||||
if (update.gameId === queue.lastGameId && update.modified === queue.lastModified) {
|
Object.assign(update.data, peek.data);
|
||||||
update.data.modified = queue.newModified;
|
queue.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
IO.sendUpdate(update.gameId, update.data).then((response) => {
|
IO.sendUpdate(update.gameId, update.data).then((response) => {
|
||||||
queue.lastGameId = update.gameId;
|
|
||||||
if (response && response.data && 'modified' in response.data) {
|
if (response && response.data && 'modified' in response.data) {
|
||||||
/*
|
/*
|
||||||
* If we queued two or more updates with the same .modified (thus
|
* If we queued two or more updates with the same .modified (thus
|
||||||
* based on the same server data), send the next update with the
|
* based on the same server data), send the later update(s) with the
|
||||||
* new .modified assigned by the server as a result of this update.
|
* new .modified assigned by the server as a result of this update.
|
||||||
*/
|
*/
|
||||||
queue.lastModified = update.modified; /* original, not adjusted */
|
for (let i = queue.head; i !== queue.tail; i += 1) {
|
||||||
queue.newModified = response.data.modified;
|
if (queue[i].gameId === update.gameId && queue[i].data.modified === update.data.modified) {
|
||||||
} else {
|
queue[i].data.modified = response.data.modified;
|
||||||
queue.lastModified = null;
|
}
|
||||||
queue.newModified = 0;
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Send future updates with the new modified time, and prevent loading
|
||||||
|
* older data from the server in case the connection is lagging.
|
||||||
|
*/
|
||||||
|
const cbBoard = $('#cb_board');
|
||||||
|
if (cbBoard.data('gameId') === update.gameId
|
||||||
|
&& cbBoard.data('modified') === update.data.modified) {
|
||||||
|
cbBoard.data('modified', response.data.modified);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queue.head === queue.tail) {
|
if (queue.isEmpty()) {
|
||||||
queue.sending = false;
|
queue.sending = false;
|
||||||
/* close the Saving... notice*/
|
/* close the Saving... notice*/
|
||||||
noticeBox.close({ ignoreDelay: true });
|
noticeBox.close({ ignoreDelay: true });
|
||||||
|
|
@ -527,9 +547,8 @@ $(function (){
|
||||||
debug('update error', err);
|
debug('update error', err);
|
||||||
|
|
||||||
/* additional updates are unlikely to succeed, so empty the queue */
|
/* additional updates are unlikely to succeed, so empty the queue */
|
||||||
while (queue.head < queue.tail) {
|
while (!queue.isEmpty()) {
|
||||||
delete queue[queue.head];
|
queue.remove();
|
||||||
queue.head += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.sending = false;
|
queue.sending = false;
|
||||||
|
|
@ -542,6 +561,14 @@ $(function (){
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function putState() {
|
||||||
|
const boardElem = $('#cb_board');
|
||||||
|
const gameId = boardElem.data('gameId');
|
||||||
|
const moves = { past: currentGame.moves, future: currentGame.redoMoves };
|
||||||
|
boardElem.data('last_state', currentGame.moves);
|
||||||
|
putMeta({ board: moves });
|
||||||
|
}
|
||||||
|
|
||||||
function putMeta(extra) {
|
function putMeta(extra) {
|
||||||
const gameId = $('#cb_board').data('gameId');
|
const gameId = $('#cb_board').data('gameId');
|
||||||
const lightName = $('#cb_light_name').val();
|
const lightName = $('#cb_light_name').val();
|
||||||
|
|
@ -606,53 +633,55 @@ $(function (){
|
||||||
$('#cb_dark_name').val('');
|
$('#cb_dark_name').val('');
|
||||||
|
|
||||||
cancelGameCallback = IO.onGameUpdate(newId, function(data, gameId) {
|
cancelGameCallback = IO.onGameUpdate(newId, function(data, gameId) {
|
||||||
const board = data.board || { past: [], future: [] };
|
if (data.modified > $('#cb_board').data('modified')) {
|
||||||
|
const board = data.board || { past: [], future: [] };
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const moves = { past: [...board.past], future: [...board.future] };
|
const moves = { past: [...board.past], future: [...board.future] };
|
||||||
const oldState = { past: currentGame.moves, future: currentGame.redoMoves };
|
const oldState = { past: currentGame.moves, future: currentGame.redoMoves };
|
||||||
|
|
||||||
if (!deepEqual(moves, oldState)) {
|
if (!deepEqual(moves, oldState)) {
|
||||||
debug('got board', moves);
|
debug('got board', moves);
|
||||||
|
|
||||||
const newGame = new PS.Game();
|
const newGame = new PS.Game();
|
||||||
|
|
||||||
try {
|
|
||||||
for (const move of moves.past) {
|
|
||||||
newGame.replayMove(move);
|
|
||||||
}
|
|
||||||
|
|
||||||
let n = 0;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (const move of moves.future.slice().reverse()) {
|
for (const move of moves.past) {
|
||||||
newGame.replayMove(move);
|
newGame.replayMove(move);
|
||||||
n += 1;
|
}
|
||||||
|
|
||||||
|
let n = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (const move of moves.future.slice().reverse()) {
|
||||||
|
newGame.replayMove(move);
|
||||||
|
n += 1;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
debug('Error replaying board redo state', err);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < n; ++i) {
|
||||||
|
newGame.undo();
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug('Error replaying board redo state', err);
|
debug('Error replaying board state', err);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < n; ++i) {
|
setCurrentGame(newGame, newGame.moves.length > currentGame.moves.length);
|
||||||
newGame.undo();
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
debug('Error replaying board state', err);
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
setCurrentGame(newGame, newGame.moves.length > currentGame.moves.length);
|
debug('Error parsing board data', err);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
debug('Error parsing board data', err);
|
const d = data || {};
|
||||||
|
$('#cb_board').data('lightName', shortenName(String(d.lightName || 'Light')));
|
||||||
|
$('#cb_board').data('darkName', shortenName(String(d.darkName || 'Dark')));
|
||||||
|
$('#cb_light_name').val(String(d.lightName || ''));
|
||||||
|
$('#cb_dark_name').val(String(d.darkName || ''));
|
||||||
|
|
||||||
|
$('#cb_board').data('modified', data.modified);
|
||||||
}
|
}
|
||||||
|
|
||||||
const d = data || {};
|
|
||||||
$('#cb_board').data('lightName', shortenName(String(d.lightName || 'Light')));
|
|
||||||
$('#cb_board').data('darkName', shortenName(String(d.darkName || 'Dark')));
|
|
||||||
$('#cb_light_name').val(String(d.lightName || ''));
|
|
||||||
$('#cb_dark_name').val(String(d.darkName || ''));
|
|
||||||
|
|
||||||
$('#cb_board').data('modified', data.modified);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let selOpt = $('#cb_game_' + newId);
|
let selOpt = $('#cb_game_' + newId);
|
||||||
|
|
@ -1104,7 +1133,6 @@ $(function (){
|
||||||
renderBoard,
|
renderBoard,
|
||||||
putState,
|
putState,
|
||||||
putMeta,
|
putMeta,
|
||||||
PacoSakoUUID,
|
|
||||||
IO,
|
IO,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue