diff --git a/webui-src/app/main.js b/webui-src/app/main.js index 22bed62..12e7247 100644 --- a/webui-src/app/main.js +++ b/webui-src/app/main.js @@ -114,7 +114,7 @@ const navbar = () => { ? 'Connected to RetroShare Core' : 'Connection Lost', }), - m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v149'), + m('span.webui-version', { style: { fontSize: '0.7em' } }, 'v150'), m('i.fas.fa-sync-alt.refresh-icon', { style: { cursor: 'pointer', fontSize: '0.8em' }, onclick: () => window.location.reload(true), @@ -236,7 +236,7 @@ const MobileStatus = () => { m('small', statusbar.formatBytes(state.totalOut)), ]), ]), - m('.mobile-status-sheet__version', 'WebUI v149'), + m('.mobile-status-sheet__version', 'WebUI v150'), ])), ]; }, diff --git a/webui-src/app/people/people_chat_tab.js b/webui-src/app/people/people_chat_tab.js index 7896f35..d5a7f01 100644 --- a/webui-src/app/people/people_chat_tab.js +++ b/webui-src/app/people/people_chat_tab.js @@ -7,7 +7,7 @@ const { getStatusTooltip, initializeDistantChat, sendDistantChatMessage, - stopStatusPolling, + leaveDistantChat, loadAllHistoryForSelectedPeer, } = require('people/people_state'); const { renderChatMessage } = require('chat/chat_state'); @@ -112,7 +112,9 @@ const ChatTab = () => { return m('.chat-warning', [ m('i.fas.fa-unlink', { style: 'font-size: 2rem; color: #ef4444; margin-bottom: 1rem;' }), m('h4', 'Conversation Ended'), - m('p', 'You have closed the distant chat tunnel. Click below to reconnect.'), + 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.'), 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(), @@ -191,17 +193,11 @@ const ChatTab = () => { pid: State.chatPid, }, (data, success) => { - if (success) { - if (State.selectedId && State.activeDistantChats[State.selectedId]) { - delete State.activeDistantChats[State.selectedId]; - } - State.chatPid = null; - State.chatMessages = []; - State.distantChatStatus = null; - State.chatDisconnected = true; - stopStatusPolling(); - m.redraw(); - } + // `success` is the HTTP status, not the answer: the core + // says in retval whether it had anything to close. Taking + // 200 for a closed tunnel is how this button could report + // a conversation as ended while the tunnel lived on. + leaveDistantChat(Boolean(success && data && data.retval)); } ); } diff --git a/webui-src/app/people/people_state.js b/webui-src/app/people/people_state.js index 418960b..efdd795 100644 --- a/webui-src/app/people/people_state.js +++ b/webui-src/app/people/people_state.js @@ -29,6 +29,8 @@ const State = { fullHistoryMessages: [], isHistoryLoading: false, pendingChatOpen: null, // gxsId a chat was explicitly asked for from another page + chatCloseFoundNothing: false, // the core had no connection left to close + statusPollFailures: 0, // consecutive getDistantChatStatus answers of false }; function getDistantChatSession(gxsId) { @@ -315,22 +317,42 @@ function pollDistantChatStatus() { pid: State.chatPid, }, (detail, success) => { - if (success && detail.retval) { - State.distantChatStatus = detail.info; - if (session) session.status = detail.info; - - if (session) { - if (detail.info.status === 2) { - addSessionSystemMessage(session, 'Tunnel is secured. You can talk!'); - // The tunnel just went up: anything the peer sent while it was - // still pending is waiting in the event buffer. - drainBufferedChatMessages(session); - } else if (detail.info.status === 3) { - addSessionSystemMessage(session, 'Your partner closed the conversation.'); + // 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 + // conversation kept its green dot and its "You can talk", and the Leave + // button then had nothing left to close. + if (!success || !detail || !detail.retval) { + State.statusPollFailures += 1; + if (State.statusPollFailures >= 2) { + if (session) { + addSessionSystemMessage(session, 'The distant chat tunnel is gone.'); + session.disconnected = true; } + State.distantChatStatus = null; + State.chatDisconnected = true; + State.chatCloseFoundNothing = false; + stopStatusPolling(); + m.redraw(); } - m.redraw(); + return; } + + State.statusPollFailures = 0; + State.distantChatStatus = detail.info; + if (session) { + session.status = detail.info; + + if (detail.info.status === 2) { + addSessionSystemMessage(session, 'Tunnel is secured. You can talk!'); + // The tunnel just went up: anything the peer sent while it was still + // pending is waiting in the event buffer. + drainBufferedChatMessages(session); + } else if (detail.info.status === 3) { + addSessionSystemMessage(session, 'Your partner closed the conversation.'); + } + } + m.redraw(); } ); } @@ -396,6 +418,8 @@ function initializeDistantChat(force = false) { State.chatMessages = session.messages; State.distantChatStatus = null; State.chatDisconnected = false; + State.chatCloseFoundNothing = false; + State.statusPollFailures = 0; m.redraw(); rs.rsJsonApiRequest( @@ -524,6 +548,23 @@ function sendDistantChatMessage() { ); } +// Ending the conversation on our side. `closed` is what the core answered: +// false means it had no connection left for that tunnel id, which the card +// then says rather than claiming the user just closed something. +function leaveDistantChat(closed) { + if (State.selectedId && State.activeDistantChats[State.selectedId]) { + delete State.activeDistantChats[State.selectedId]; + } + State.chatPid = null; + State.chatMessages = []; + State.distantChatStatus = null; + State.chatDisconnected = true; + State.chatCloseFoundNothing = !closed; + State.statusPollFailures = 0; + stopStatusPolling(); + m.redraw(); +} + // Live incoming distant chat message, coming from the rsEvents stream. function receiveDistantChatMessage(chatMessage) { const msgCid = chatMessage && chatMessage.chat_id; @@ -830,5 +871,6 @@ module.exports = { initializeDistantChat, loadChatMessages, sendDistantChatMessage, + leaveDistantChat, };