mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 11:30:55 +01:00
After Aphlict reconnects, ask the server to replay recent messages
Summary: Fixes T12563. If we've ever seen an "open", mark all future connections as reconnects. When we reconnect, replay recent history. (Until duplicate messages (T12564) are handled better this may cause some notification duplication.) Also emit a reconnect event (for T12566) but don't use it yet. Test Plan: {F4912044} Reviewers: chad Reviewed By: chad Maniphest Tasks: T12563 Differential Revision: https://secure.phabricator.com/D17708
This commit is contained in:
parent
88157a9442
commit
02194f0fc8
7 changed files with 130 additions and 29 deletions
|
@ -10,8 +10,8 @@ return array(
|
||||||
'conpherence.pkg.css' => 'a34d59bd',
|
'conpherence.pkg.css' => 'a34d59bd',
|
||||||
'conpherence.pkg.js' => '5f86c17d',
|
'conpherence.pkg.js' => '5f86c17d',
|
||||||
'core.pkg.css' => '959330a2',
|
'core.pkg.css' => '959330a2',
|
||||||
'core.pkg.js' => 'cb50c410',
|
'core.pkg.js' => '1cedf416',
|
||||||
'darkconsole.pkg.js' => 'a2faee86',
|
'darkconsole.pkg.js' => '31272f61',
|
||||||
'differential.pkg.css' => '90b30783',
|
'differential.pkg.css' => '90b30783',
|
||||||
'differential.pkg.js' => 'ddfeb49b',
|
'differential.pkg.js' => 'ddfeb49b',
|
||||||
'diffusion.pkg.css' => '91c5d3a6',
|
'diffusion.pkg.css' => '91c5d3a6',
|
||||||
|
@ -20,7 +20,7 @@ return array(
|
||||||
'maniphest.pkg.css' => '4845691a',
|
'maniphest.pkg.css' => '4845691a',
|
||||||
'maniphest.pkg.js' => '5ab2753f',
|
'maniphest.pkg.js' => '5ab2753f',
|
||||||
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
|
'rsrc/css/aphront/aphront-bars.css' => '231ac33c',
|
||||||
'rsrc/css/aphront/dark-console.css' => 'e7c6e44d',
|
'rsrc/css/aphront/dark-console.css' => '53798a6d',
|
||||||
'rsrc/css/aphront/dialog-view.css' => '685c7e2d',
|
'rsrc/css/aphront/dialog-view.css' => '685c7e2d',
|
||||||
'rsrc/css/aphront/list-filter-view.css' => '5d6f0526',
|
'rsrc/css/aphront/list-filter-view.css' => '5d6f0526',
|
||||||
'rsrc/css/aphront/multi-column.css' => '84cc6640',
|
'rsrc/css/aphront/multi-column.css' => '84cc6640',
|
||||||
|
@ -361,7 +361,7 @@ return array(
|
||||||
'rsrc/image/texture/table_header.png' => '5c433037',
|
'rsrc/image/texture/table_header.png' => '5c433037',
|
||||||
'rsrc/image/texture/table_header_hover.png' => '038ec3b9',
|
'rsrc/image/texture/table_header_hover.png' => '038ec3b9',
|
||||||
'rsrc/image/texture/table_header_tall.png' => 'd56b434f',
|
'rsrc/image/texture/table_header_tall.png' => 'd56b434f',
|
||||||
'rsrc/js/application/aphlict/Aphlict.js' => 'ce5f793f',
|
'rsrc/js/application/aphlict/Aphlict.js' => '7cacce98',
|
||||||
'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2',
|
'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'caade6f2',
|
||||||
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'd82b1ff9',
|
'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'd82b1ff9',
|
||||||
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9',
|
'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '5e2634b9',
|
||||||
|
@ -522,7 +522,7 @@ return array(
|
||||||
'rsrc/js/core/behavior-workflow.js' => '0a3f3021',
|
'rsrc/js/core/behavior-workflow.js' => '0a3f3021',
|
||||||
'rsrc/js/core/darkconsole/DarkLog.js' => 'c8e1ffe3',
|
'rsrc/js/core/darkconsole/DarkLog.js' => 'c8e1ffe3',
|
||||||
'rsrc/js/core/darkconsole/DarkMessage.js' => 'c48cccdd',
|
'rsrc/js/core/darkconsole/DarkMessage.js' => 'c48cccdd',
|
||||||
'rsrc/js/core/darkconsole/behavior-dark-console.js' => '698614f9',
|
'rsrc/js/core/darkconsole/behavior-dark-console.js' => '2a228a94',
|
||||||
'rsrc/js/core/phtize.js' => 'd254d646',
|
'rsrc/js/core/phtize.js' => 'd254d646',
|
||||||
'rsrc/js/phui/behavior-phui-dropdown-menu.js' => 'b95d6f7d',
|
'rsrc/js/phui/behavior-phui-dropdown-menu.js' => 'b95d6f7d',
|
||||||
'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb',
|
'rsrc/js/phui/behavior-phui-file-upload.js' => 'b003d4fb',
|
||||||
|
@ -538,7 +538,7 @@ return array(
|
||||||
'symbols' => array(
|
'symbols' => array(
|
||||||
'almanac-css' => 'dbb9b3af',
|
'almanac-css' => 'dbb9b3af',
|
||||||
'aphront-bars' => '231ac33c',
|
'aphront-bars' => '231ac33c',
|
||||||
'aphront-dark-console-css' => 'e7c6e44d',
|
'aphront-dark-console-css' => '53798a6d',
|
||||||
'aphront-dialog-view-css' => '685c7e2d',
|
'aphront-dialog-view-css' => '685c7e2d',
|
||||||
'aphront-list-filter-view-css' => '5d6f0526',
|
'aphront-list-filter-view-css' => '5d6f0526',
|
||||||
'aphront-multi-column-view-css' => '84cc6640',
|
'aphront-multi-column-view-css' => '84cc6640',
|
||||||
|
@ -583,7 +583,7 @@ return array(
|
||||||
'herald-rule-editor' => 'd6a7e717',
|
'herald-rule-editor' => 'd6a7e717',
|
||||||
'herald-test-css' => 'a52e323e',
|
'herald-test-css' => 'a52e323e',
|
||||||
'inline-comment-summary-css' => '51efda3a',
|
'inline-comment-summary-css' => '51efda3a',
|
||||||
'javelin-aphlict' => 'ce5f793f',
|
'javelin-aphlict' => '7cacce98',
|
||||||
'javelin-behavior' => '61cbc29a',
|
'javelin-behavior' => '61cbc29a',
|
||||||
'javelin-behavior-aphlict-dropdown' => 'caade6f2',
|
'javelin-behavior-aphlict-dropdown' => 'caade6f2',
|
||||||
'javelin-behavior-aphlict-listen' => 'd82b1ff9',
|
'javelin-behavior-aphlict-listen' => 'd82b1ff9',
|
||||||
|
@ -605,7 +605,7 @@ return array(
|
||||||
'javelin-behavior-conpherence-pontificate' => '55616e04',
|
'javelin-behavior-conpherence-pontificate' => '55616e04',
|
||||||
'javelin-behavior-conpherence-search' => '9bbf3762',
|
'javelin-behavior-conpherence-search' => '9bbf3762',
|
||||||
'javelin-behavior-countdown-timer' => 'e4cc26b3',
|
'javelin-behavior-countdown-timer' => 'e4cc26b3',
|
||||||
'javelin-behavior-dark-console' => '698614f9',
|
'javelin-behavior-dark-console' => '2a228a94',
|
||||||
'javelin-behavior-dashboard-async-panel' => '469c0d9e',
|
'javelin-behavior-dashboard-async-panel' => '469c0d9e',
|
||||||
'javelin-behavior-dashboard-move-panels' => '408bf173',
|
'javelin-behavior-dashboard-move-panels' => '408bf173',
|
||||||
'javelin-behavior-dashboard-query-panel-select' => '453c5375',
|
'javelin-behavior-dashboard-query-panel-select' => '453c5375',
|
||||||
|
@ -1089,6 +1089,16 @@ return array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
),
|
),
|
||||||
|
'2a228a94' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-util',
|
||||||
|
'javelin-dom',
|
||||||
|
'javelin-request',
|
||||||
|
'phabricator-keyboard-shortcut',
|
||||||
|
'phabricator-darklog',
|
||||||
|
'phabricator-darkmessage',
|
||||||
|
),
|
||||||
'2b8de964' => array(
|
'2b8de964' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
|
@ -1381,16 +1391,6 @@ return array(
|
||||||
'6882e80a' => array(
|
'6882e80a' => array(
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
),
|
),
|
||||||
'698614f9' => array(
|
|
||||||
'javelin-behavior',
|
|
||||||
'javelin-stratcom',
|
|
||||||
'javelin-util',
|
|
||||||
'javelin-dom',
|
|
||||||
'javelin-request',
|
|
||||||
'phabricator-keyboard-shortcut',
|
|
||||||
'phabricator-darklog',
|
|
||||||
'phabricator-darkmessage',
|
|
||||||
),
|
|
||||||
'69adf288' => array(
|
'69adf288' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
),
|
),
|
||||||
|
@ -1468,6 +1468,13 @@ return array(
|
||||||
'owners-path-editor',
|
'owners-path-editor',
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
),
|
),
|
||||||
|
'7cacce98' => array(
|
||||||
|
'javelin-install',
|
||||||
|
'javelin-util',
|
||||||
|
'javelin-websocket',
|
||||||
|
'javelin-leader',
|
||||||
|
'javelin-json',
|
||||||
|
),
|
||||||
'7cbe244b' => array(
|
'7cbe244b' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
|
@ -2014,13 +2021,6 @@ return array(
|
||||||
'cd2b9b77' => array(
|
'cd2b9b77' => array(
|
||||||
'phui-oi-list-view-css',
|
'phui-oi-list-view-css',
|
||||||
),
|
),
|
||||||
'ce5f793f' => array(
|
|
||||||
'javelin-install',
|
|
||||||
'javelin-util',
|
|
||||||
'javelin-websocket',
|
|
||||||
'javelin-leader',
|
|
||||||
'javelin-json',
|
|
||||||
),
|
|
||||||
'd0c516d5' => array(
|
'd0c516d5' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
|
|
|
@ -23,6 +23,7 @@ final class DarkConsoleRealtimePlugin extends DarkConsolePlugin {
|
||||||
));
|
));
|
||||||
|
|
||||||
$reconnect_label = pht('Reconnect');
|
$reconnect_label = pht('Reconnect');
|
||||||
|
$replay_label = pht('Replay');
|
||||||
|
|
||||||
$buttons = phutil_tag(
|
$buttons = phutil_tag(
|
||||||
'div',
|
'div',
|
||||||
|
@ -40,11 +41,22 @@ final class DarkConsoleRealtimePlugin extends DarkConsolePlugin {
|
||||||
'action' => 'reconnect',
|
'action' => 'reconnect',
|
||||||
'label' => $reconnect_label,
|
'label' => $reconnect_label,
|
||||||
)),
|
)),
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setIcon('fa-backward')
|
||||||
|
->setColor(PHUIButtonView::GREY)
|
||||||
|
->setText($replay_label)
|
||||||
|
->addSigil('dark-console-realtime-action')
|
||||||
|
->setMetadata(
|
||||||
|
array(
|
||||||
|
'action' => 'replay',
|
||||||
|
'label' => $replay_label,
|
||||||
|
)),
|
||||||
));
|
));
|
||||||
|
|
||||||
return phutil_tag(
|
return phutil_tag(
|
||||||
'div',
|
'div',
|
||||||
array(
|
array(
|
||||||
|
'class' => 'dark-console-realtime',
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
$buttons,
|
$buttons,
|
||||||
|
|
|
@ -197,3 +197,8 @@ for (ii = 0; ii < aphlict_admins.length; ii++) {
|
||||||
admin_server.setClientServers(aphlict_clients);
|
admin_server.setClientServers(aphlict_clients);
|
||||||
admin_server.setPeerList(peer_list);
|
admin_server.setPeerList(peer_list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (ii = 0; ii < aphlict_clients.length; ii++) {
|
||||||
|
var client_server = aphlict_clients[ii];
|
||||||
|
client_server.setAdminServers(aphlict_admins);
|
||||||
|
}
|
||||||
|
|
|
@ -16,10 +16,12 @@ JX.install('AphlictClientServer', {
|
||||||
|
|
||||||
this._server = server;
|
this._server = server;
|
||||||
this._lists = {};
|
this._lists = {};
|
||||||
|
this._adminServers = [];
|
||||||
},
|
},
|
||||||
|
|
||||||
properties: {
|
properties: {
|
||||||
logger: null,
|
logger: null,
|
||||||
|
adminServers: null
|
||||||
},
|
},
|
||||||
|
|
||||||
members: {
|
members: {
|
||||||
|
@ -33,6 +35,20 @@ JX.install('AphlictClientServer', {
|
||||||
return this._lists[instance];
|
return this._lists[instance];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
getHistory: function(age) {
|
||||||
|
var results = [];
|
||||||
|
|
||||||
|
var servers = this.getAdminServers();
|
||||||
|
for (var ii = 0; ii < servers.length; ii++) {
|
||||||
|
var messages = servers[ii].getHistory(age);
|
||||||
|
for (var jj = 0; jj < messages.length; jj++) {
|
||||||
|
results.push(messages[jj]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
},
|
||||||
|
|
||||||
log: function() {
|
log: function() {
|
||||||
var logger = this.getLogger();
|
var logger = this.getLogger();
|
||||||
if (!logger) {
|
if (!logger) {
|
||||||
|
@ -117,6 +133,26 @@ JX.install('AphlictClientServer', {
|
||||||
listener.unsubscribe(message.data);
|
listener.unsubscribe(message.data);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'replay':
|
||||||
|
var age = message.data.age || 60000;
|
||||||
|
var min_age = (new Date().getTime() - age);
|
||||||
|
|
||||||
|
var old_messages = self.getHistory(min_age);
|
||||||
|
for (var ii = 0; ii < old_messages.length; ii++) {
|
||||||
|
var old_message = old_messages[ii];
|
||||||
|
|
||||||
|
if (!listener.isSubscribedToAny(old_message.subscribers)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
listener.writeMessage(old_message);
|
||||||
|
} catch (error) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log(
|
log(
|
||||||
'Unrecognized command "%s".',
|
'Unrecognized command "%s".',
|
||||||
|
|
|
@ -231,3 +231,7 @@
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark-console-realtime .button {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ JX.install('Aphlict', {
|
||||||
_socket: null,
|
_socket: null,
|
||||||
_subscriptions: null,
|
_subscriptions: null,
|
||||||
_status: null,
|
_status: null,
|
||||||
|
_isReconnect: false,
|
||||||
|
|
||||||
start: function() {
|
start: function() {
|
||||||
JX.Leader.listen('onBecomeLeader', JX.bind(this, this._lead));
|
JX.Leader.listen('onBecomeLeader', JX.bind(this, this._lead));
|
||||||
|
@ -94,10 +95,31 @@ JX.install('Aphlict', {
|
||||||
},
|
},
|
||||||
|
|
||||||
_open: function() {
|
_open: function() {
|
||||||
|
// If this is a reconnect, ask the server to replay recent messages
|
||||||
|
// after other tabs have had a chance to subscribe. Do this before we
|
||||||
|
// broadcast that the connection status is now open.
|
||||||
|
if (this._isReconnect) {
|
||||||
|
setTimeout(JX.bind(this, this._reconnect), 100);
|
||||||
|
}
|
||||||
|
|
||||||
this._broadcastStatus('open');
|
this._broadcastStatus('open');
|
||||||
JX.Leader.broadcast(null, {type: 'aphlict.getsubscribers'});
|
JX.Leader.broadcast(null, {type: 'aphlict.getsubscribers'});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_reconnect: function() {
|
||||||
|
this.replay();
|
||||||
|
|
||||||
|
JX.Leader.broadcast(null, {type: 'aphlict.reconnect', data: null});
|
||||||
|
},
|
||||||
|
|
||||||
|
replay: function() {
|
||||||
|
var replay = {
|
||||||
|
age: 60000
|
||||||
|
};
|
||||||
|
|
||||||
|
JX.Leader.broadcast(null, {type: 'aphlict.replay', data: replay});
|
||||||
|
},
|
||||||
|
|
||||||
_close: function() {
|
_close: function() {
|
||||||
this._broadcastStatus('closed');
|
this._broadcastStatus('closed');
|
||||||
},
|
},
|
||||||
|
@ -131,10 +153,13 @@ JX.install('Aphlict', {
|
||||||
|
|
||||||
case 'aphlict.subscribe':
|
case 'aphlict.subscribe':
|
||||||
if (is_leader) {
|
if (is_leader) {
|
||||||
this._write({
|
this._writeCommand('subscribe', message.data);
|
||||||
command: 'subscribe',
|
}
|
||||||
data: message.data
|
break;
|
||||||
});
|
|
||||||
|
case 'aphlict.replay':
|
||||||
|
if (is_leader) {
|
||||||
|
this._writeCommand('replay', message.data);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -147,11 +172,27 @@ JX.install('Aphlict', {
|
||||||
|
|
||||||
_setStatus: function(status) {
|
_setStatus: function(status) {
|
||||||
this._status = status;
|
this._status = status;
|
||||||
|
|
||||||
|
// If we've ever seen an open connection, any new connection we make
|
||||||
|
// is a reconnect and should replay history.
|
||||||
|
if (status == 'open') {
|
||||||
|
this._isReconnect = true;
|
||||||
|
}
|
||||||
|
|
||||||
this.invoke('didChangeStatus');
|
this.invoke('didChangeStatus');
|
||||||
},
|
},
|
||||||
|
|
||||||
_write: function(message) {
|
_write: function(message) {
|
||||||
this._socket.send(JX.JSON.stringify(message));
|
this._socket.send(JX.JSON.stringify(message));
|
||||||
|
},
|
||||||
|
|
||||||
|
_writeCommand: function(command, message) {
|
||||||
|
var frame = {
|
||||||
|
command: command,
|
||||||
|
data: message
|
||||||
|
};
|
||||||
|
|
||||||
|
return this._write(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
|
@ -392,6 +392,9 @@ JX.behavior('dark-console', function(config, statics) {
|
||||||
ws.reconnect();
|
ws.reconnect();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'replay':
|
||||||
|
JX.Aphlict.getInstance().replay();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue