diff --git a/src/frontend/stmclient.cc b/src/frontend/stmclient.cc index 02e0463..18633b0 100644 --- a/src/frontend/stmclient.cc +++ b/src/frontend/stmclient.cc @@ -201,6 +201,7 @@ bool STMClient::process_network_input( void ) /* Now give hints to the overlays */ overlays.get_notification_engine().server_heard( network->get_latest_remote_state().timestamp ); + overlays.get_notification_engine().server_acked( network->get_sent_state_acked_timestamp() ); overlays.get_prediction_engine().set_local_frame_acked( network->get_sent_state_acked() ); overlays.get_prediction_engine().set_send_interval( network->send_interval() ); diff --git a/src/frontend/terminaloverlay.cc b/src/frontend/terminaloverlay.cc index a6e066b..b52695c 100644 --- a/src/frontend/terminaloverlay.cc +++ b/src/frontend/terminaloverlay.cc @@ -153,6 +153,7 @@ void ConditionalCursorMove::apply( Framebuffer &fb, uint64_t confirmed_epoch ) c NotificationEngine::NotificationEngine() : last_word_from_server( timestamp() ), + last_acked_state( timestamp() ), message(), message_expiration( -1 ) {} @@ -188,15 +189,32 @@ void NotificationEngine::apply( Framebuffer &fb ) const /* write message */ wchar_t tmp[ 128 ]; + /* We want to prefer the "last contact" message if we simply haven't + heard from the server in a while, but print the "last reply" message + if the problem is uplink-only. */ + + double since_heard = (double)(now - last_word_from_server) / 1000.0; + double since_ack = (double)(now - last_acked_state) / 1000.0; + const char server_message[] = "contact"; + const char reply_message[] = "reply"; + + double time_elapsed = since_heard; + const char *explanation = server_message; + + if ( reply_late( now ) && (!server_late( now )) ) { + time_elapsed = since_ack; + explanation = reply_message; + } + if ( message.empty() && (!time_expired) ) { return; } else if ( message.empty() && time_expired ) { - swprintf( tmp, 128, L"mosh: Last contact %.0f seconds ago. [To quit: Ctrl-^ .]", (double)(now - last_word_from_server) / 1000.0 ); + swprintf( tmp, 128, L"mosh: Last %s %.0f seconds ago. [To quit: Ctrl-^ .]", explanation, time_elapsed ); } else if ( (!message.empty()) && (!time_expired) ) { swprintf( tmp, 128, L"mosh: %ls [To quit: Ctrl-^ .]", message.c_str() ); } else { - swprintf( tmp, 128, L"mosh: %ls (%.0f s without contact.) [To quit: Ctrl-^ .]", message.c_str(), - (double)(now - last_word_from_server) / 1000.0 ); + swprintf( tmp, 128, L"mosh: %ls (%.0f s without %s.) [To quit: Ctrl-^ .]", message.c_str(), + time_elapsed, explanation ); } wstring string_to_draw( tmp ); diff --git a/src/frontend/terminaloverlay.h b/src/frontend/terminaloverlay.h index 67ccd04..876a141 100644 --- a/src/frontend/terminaloverlay.h +++ b/src/frontend/terminaloverlay.h @@ -127,16 +127,20 @@ namespace Overlay { class NotificationEngine { private: uint64_t last_word_from_server; + uint64_t last_acked_state; wstring message; uint64_t message_expiration; public: - bool need_countup( uint64_t ts ) const { return ts - last_word_from_server > 6500; } + bool server_late( uint64_t ts ) const { return (ts - last_word_from_server) > 6500; } + bool reply_late( uint64_t ts ) const { return (ts - last_acked_state) > 10000; } + bool need_countup( uint64_t ts ) const { return server_late( ts ) || reply_late( ts ); } void adjust_message( void ); void apply( Framebuffer &fb ) const; void set_notification_string( const wstring &s_message, bool permanent = false ) { message = s_message; if ( permanent ) { message_expiration = -1; } else { message_expiration = timestamp() + 1000; } } const wstring &get_notification_string( void ) const { return message; } void server_heard( uint64_t s_last_word ) { last_word_from_server = s_last_word; } + void server_acked( uint64_t s_last_acked ) { last_acked_state = s_last_acked; } uint64_t get_message_expiration( void ) const { return message_expiration; } NotificationEngine(); diff --git a/src/network/networktransport.h b/src/network/networktransport.h index c5f118c..167f5c0 100644 --- a/src/network/networktransport.h +++ b/src/network/networktransport.h @@ -95,6 +95,7 @@ namespace Network { void set_send_delay( int new_delay ) { sender.set_send_delay( new_delay ); } + uint64_t get_sent_state_acked_timestamp( void ) const { return sender.get_sent_state_acked_timestamp(); } uint64_t get_sent_state_acked( void ) const { return sender.get_sent_state_acked(); } uint64_t get_sent_state_last( void ) const { return sender.get_sent_state_last(); } diff --git a/src/network/transportsender.h b/src/network/transportsender.h index 3de5fa2..0738f65 100644 --- a/src/network/transportsender.h +++ b/src/network/transportsender.h @@ -126,6 +126,7 @@ namespace Network { bool get_shutdown_in_progress( void ) const { return shutdown_in_progress; } bool get_shutdown_acknowledged( void ) const { return sent_states.front().num == uint64_t(-1); } bool get_counterparty_shutdown_acknowledged( void ) const { return fragmenter.last_ack_sent() == uint64_t(-1); } + uint64_t get_sent_state_acked_timestamp( void ) const { return sent_states.front().timestamp; } uint64_t get_sent_state_acked( void ) const { return sent_states.front().num; } uint64_t get_sent_state_last( void ) const { return sent_states.back().num; }