mirror of
https://github.com/RetroShare/RSNewWebUI.git
synced 2026-09-12 19:50:04 +05:00
webui v167: a stale tunnel poll ended the next conversation
Selecting a contact from a chat room (setSelectedId) changed the selected identity but left the page-wide chat fields -- chatPid, status, messages -- pointing at the previous contact's tunnel. The People page then started its status poll on that pid at mount; the core no longer knew it, two "false" answers later the poll wrote "tunnel is gone" into the NEW contact's session and flagged the conversation as ended, while the real tunnel was still coming up in the desktop window. On a slow link the poll answers land late enough to overwrite the state of the conversation opened meanwhile. setSelectedId now resets the page chat state to the selected contact's own session; the mount-time poll only starts on a pid that belongs to the selected contact; and every poll answer is dropped unless it is about the pid and the contact it was asked for. The "ended" card also says what happened when the tunnel went away by itself, instead of "you closed it".
This commit is contained in:
parent
1111019861
commit
efdc5edd39
@ -1,7 +1,7 @@
|
||||
const m = require('mithril');
|
||||
|
||||
// Bumped at every change of the web UI (two places used to carry it).
|
||||
const WEBUI_VERSION = 'v166';
|
||||
const WEBUI_VERSION = 'v167';
|
||||
|
||||
const login = require('login');
|
||||
const rs = require('rswebui');
|
||||
|
||||
@ -13,6 +13,7 @@ const {
|
||||
startStatusPolling,
|
||||
stopStatusPolling,
|
||||
initializeDistantChat,
|
||||
selectChatContact,
|
||||
getDistantChatSession,
|
||||
drainBufferedChatMessages,
|
||||
markDistantChatRead,
|
||||
@ -67,12 +68,13 @@ const PeopleLayout = () => {
|
||||
});
|
||||
window.addEventListener('click', dismissMenu);
|
||||
|
||||
if (State.chatPid && !State.chatDisconnected) {
|
||||
// Only poll a tunnel that is the selected contact's own; anything
|
||||
// else is left over from a previous selection.
|
||||
const selectedSession = State.selectedId ? getDistantChatSession(State.selectedId) : null;
|
||||
if (State.chatPid && !State.chatDisconnected && selectedSession && selectedSession.pid === State.chatPid) {
|
||||
// Messages received while the tab was unmounted sit in the event
|
||||
// queue buffer: pick them up before the first redraw.
|
||||
if (State.selectedId) {
|
||||
drainBufferedChatMessages(getDistantChatSession(State.selectedId));
|
||||
}
|
||||
drainBufferedChatMessages(selectedSession);
|
||||
startStatusPolling();
|
||||
}
|
||||
},
|
||||
@ -190,6 +192,7 @@ PeopleLayout.setSelectedId = (id, activeTab = 'details', showCompose = false) =>
|
||||
|
||||
State.activeFilter = filter;
|
||||
State.selectedId = id;
|
||||
selectChatContact(id);
|
||||
State.activeTab = activeTab;
|
||||
State.pendingChatOpen = activeTab === 'chat' ? id : null;
|
||||
State.mobilePane = 'detail';
|
||||
|
||||
@ -121,7 +121,9 @@ const ChatTab = () => {
|
||||
m('h4', 'Conversation Ended'),
|
||||
m('p', State.chatCloseFoundNothing
|
||||
? 'The tunnel was already gone: the core had no connection left to close. Click below to open a new one.'
|
||||
: 'You have closed the distant chat tunnel. Click below to reconnect.'),
|
||||
: State.chatEndedByPoll
|
||||
? 'The tunnel went away: closed by your contact, or dropped by the core. Click below to open a new one.'
|
||||
: 'You have closed the distant chat tunnel. Click below to reconnect.'),
|
||||
m('button.blue', {
|
||||
style: 'margin-top: 1rem; padding: 0.5rem 1.5rem; border-radius: 0.375rem; border: none; font-weight: 600; cursor: pointer;',
|
||||
onclick: () => initializeDistantChat(),
|
||||
|
||||
@ -31,6 +31,7 @@ const State = {
|
||||
isHistoryLoading: false,
|
||||
pendingChatOpen: null, // gxsId a chat was explicitly asked for from another page
|
||||
chatCloseFoundNothing: false, // the core had no connection left to close
|
||||
chatEndedByPoll: false, // the status poll saw the tunnel go, we did not close it
|
||||
statusPollFailures: 0, // consecutive getDistantChatStatus answers of false
|
||||
showEmojiPicker: false,
|
||||
attachPath: '', // file being hashed for a retroshare:// link
|
||||
@ -365,14 +366,20 @@ function getStatusTooltip(status) {
|
||||
|
||||
function pollDistantChatStatus() {
|
||||
if (!State.chatPid) return;
|
||||
const session = State.selectedId ? getDistantChatSession(State.selectedId) : null;
|
||||
// Captured now: the answer lands seconds later on a slow link, and by then
|
||||
// the user may be on another contact, or the page on another tunnel. An
|
||||
// answer about a stale pid used to mark the new conversation as ended.
|
||||
const pid = State.chatPid;
|
||||
const askedFor = State.selectedId;
|
||||
const session = askedFor ? getDistantChatSession(askedFor) : null;
|
||||
|
||||
rs.rsJsonApiRequest(
|
||||
'/rsChats/getDistantChatStatus',
|
||||
{
|
||||
pid: State.chatPid,
|
||||
pid,
|
||||
},
|
||||
(detail, success) => {
|
||||
if (State.chatPid !== pid || State.selectedId !== askedFor) return;
|
||||
// getDistantChatStatus answers false once the tunnel is gone from the
|
||||
// core -- died of inaction, closed by the peer, closed by us. Ignoring
|
||||
// that answer left the last known status on screen for good: a dead
|
||||
@ -388,6 +395,7 @@ function pollDistantChatStatus() {
|
||||
State.distantChatStatus = null;
|
||||
State.chatDisconnected = true;
|
||||
State.chatCloseFoundNothing = false;
|
||||
State.chatEndedByPoll = true;
|
||||
stopStatusPolling();
|
||||
m.redraw();
|
||||
}
|
||||
@ -530,6 +538,7 @@ function openDistantChat(session) {
|
||||
State.distantChatStatus = null;
|
||||
State.chatDisconnected = false;
|
||||
State.chatCloseFoundNothing = false;
|
||||
State.chatEndedByPoll = false;
|
||||
State.statusPollFailures = 0;
|
||||
State.chatInputMsg = session.inputMsg || '';
|
||||
m.redraw();
|
||||
@ -695,6 +704,7 @@ function leaveDistantChat(closed) {
|
||||
State.distantChatStatus = null;
|
||||
State.chatDisconnected = true;
|
||||
State.chatCloseFoundNothing = !closed;
|
||||
State.chatEndedByPoll = false;
|
||||
State.statusPollFailures = 0;
|
||||
stopStatusPolling();
|
||||
m.redraw();
|
||||
@ -721,6 +731,23 @@ function findDistantChatSession(msgPid) {
|
||||
return { session, targetGxsId };
|
||||
}
|
||||
|
||||
// The page-wide chat fields (pid, status, messages) belong to one contact at
|
||||
// a time. Selecting another one must not leave them pointing at the previous
|
||||
// tunnel: the mount-time poll then asked about a pid the core may have
|
||||
// dropped, and its "gone" answer ended the new conversation before it began.
|
||||
function selectChatContact(gxsId) {
|
||||
stopStatusPolling();
|
||||
const session = gxsId ? getDistantChatSession(gxsId) : null;
|
||||
State.chatPid = session ? session.pid : null;
|
||||
State.chatMessages = session ? session.messages : [];
|
||||
State.distantChatStatus = session ? session.status : null;
|
||||
State.chatDisconnected = session ? Boolean(session.disconnected) : false;
|
||||
State.chatCloseFoundNothing = false;
|
||||
State.chatEndedByPoll = false;
|
||||
State.statusPollFailures = 0;
|
||||
State.chatInputMsg = session ? (session.inputMsg || '') : '';
|
||||
}
|
||||
|
||||
function isDistantChatActive(gxsId) {
|
||||
const session = gxsId && State.activeDistantChats[gxsId];
|
||||
return Boolean(
|
||||
@ -1078,6 +1105,7 @@ module.exports = {
|
||||
loadChatMessages,
|
||||
sendDistantChatMessage,
|
||||
leaveDistantChat,
|
||||
selectChatContact,
|
||||
setChatDraft,
|
||||
switchChatIdentity,
|
||||
refreshSelectedIdDetails,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user