@ -22,9 +22,12 @@
# include <QShortcut>
# include <QShortcut>
# include <QtConcurrent>
# include <QtConcurrent>
# include <mtx/responses.hpp>
# include "AvatarProvider.h"
# include "AvatarProvider.h"
# include "Cache.h"
# include "Cache.h"
# include "Cache_p.h"
# include "Cache_p.h"
# include "CallManager.h"
# include "ChatPage.h"
# include "ChatPage.h"
# include "DeviceVerificationFlow.h"
# include "DeviceVerificationFlow.h"
# include "EventAccessors.h"
# include "EventAccessors.h"
@ -69,7 +72,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
, isConnected_ ( true )
, isConnected_ ( true )
, userSettings_ { userSettings }
, userSettings_ { userSettings }
, notificationsManager ( this )
, notificationsManager ( this )
, callManager_ ( userSettings )
, callManager_ ( new CallManager ( userSettings , this ) )
{
{
setObjectName ( " chatPage " ) ;
setObjectName ( " chatPage " ) ;
@ -126,7 +129,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
contentLayout_ - > setSpacing ( 0 ) ;
contentLayout_ - > setSpacing ( 0 ) ;
contentLayout_ - > setMargin ( 0 ) ;
contentLayout_ - > setMargin ( 0 ) ;
view_manager_ = new TimelineViewManager ( & callManager_ , this ) ;
view_manager_ = new TimelineViewManager ( callManager_ , this ) ;
contentLayout_ - > addWidget ( view_manager_ - > getWidget ( ) ) ;
contentLayout_ - > addWidget ( view_manager_ - > getWidget ( ) ) ;
@ -434,8 +437,8 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
} ) ;
} ) ;
connect ( text_input_ , & TextInputWidget : : callButtonPress , this , [ this ] ( ) {
connect ( text_input_ , & TextInputWidget : : callButtonPress , this , [ this ] ( ) {
if ( callManager_ . onActiveCall ( ) ) {
if ( callManager_ - > onActiveCall ( ) ) {
callManager_ . hangUp ( ) ;
callManager_ - > hangUp ( ) ;
} else {
} else {
if ( auto roomInfo = cache : : singleRoomInfo ( current_room_ . toStdString ( ) ) ;
if ( auto roomInfo = cache : : singleRoomInfo ( current_room_ . toStdString ( ) ) ;
roomInfo . member_count ! = 2 ) {
roomInfo . member_count ! = 2 ) {
@ -454,7 +457,7 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
userSettings_ ,
userSettings_ ,
MainWindow : : instance ( ) ) ;
MainWindow : : instance ( ) ) ;
connect ( dialog , & dialogs : : PlaceCall : : voice , this , [ this ] ( ) {
connect ( dialog , & dialogs : : PlaceCall : : voice , this , [ this ] ( ) {
callManager_ . sendInvite ( current_room_ ) ;
callManager_ - > sendInvite ( current_room_ ) ;
} ) ;
} ) ;
utils : : centerWidget ( dialog , MainWindow : : instance ( ) ) ;
utils : : centerWidget ( dialog , MainWindow : : instance ( ) ) ;
dialog - > show ( ) ;
dialog - > show ( ) ;
@ -692,7 +695,7 @@ ChatPage::bootstrap(QString userid, QString homeserver, QString token)
const bool isInitialized = cache : : isInitialized ( ) ;
const bool isInitialized = cache : : isInitialized ( ) ;
const auto cacheVersion = cache : : formatVersion ( ) ;
const auto cacheVersion = cache : : formatVersion ( ) ;
callManager_ . refreshTurnServer ( ) ;
callManager_ - > refreshTurnServer ( ) ;
if ( ! isInitialized ) {
if ( ! isInitialized ) {
cache : : setCurrentFormat ( ) ;
cache : : setCurrentFormat ( ) ;
@ -762,7 +765,7 @@ ChatPage::loadStateFromCache()
cache : : restoreSessions ( ) ;
cache : : restoreSessions ( ) ;
olm : : client ( ) - > load ( cache : : restoreOlmAccount ( ) , STORAGE_SECRET_KEY ) ;
olm : : client ( ) - > load ( cache : : restoreOlmAccount ( ) , STORAGE_SECRET_KEY ) ;
emit initializeEmptyViews ( cache : : roomMessages ( ) ) ;
emit initializeEmptyViews ( cache : : client ( ) - > roomMessages ( ) ) ;
emit initializeRoomList ( cache : : roomInfo ( ) ) ;
emit initializeRoomList ( cache : : roomInfo ( ) ) ;
emit initializeMentions ( cache : : getTimelineMentions ( ) ) ;
emit initializeMentions ( cache : : getTimelineMentions ( ) ) ;
emit syncTags ( cache : : roomInfo ( ) . toStdMap ( ) ) ;
emit syncTags ( cache : : roomInfo ( ) . toStdMap ( ) ) ;
@ -969,13 +972,64 @@ ChatPage::startInitialSync()
opts . set_presence = currentPresence ( ) ;
opts . set_presence = currentPresence ( ) ;
http : : client ( ) - > sync (
http : : client ( ) - > sync (
opts ,
opts , [ this ] ( const mtx : : responses : : Sync & res , mtx : : http : : RequestErr err ) {
std : : bind (
// TODO: Initial Sync should include mentions as well...
& ChatPage : : initialSyncHandler , this , std : : placeholders : : _1 , std : : placeholders : : _2 ) ) ;
if ( err ) {
const auto error = QString : : fromStdString ( err - > matrix_error . error ) ;
const auto msg = tr ( " Please try to login again: %1 " ) . arg ( error ) ;
const auto err_code = mtx : : errors : : to_string ( err - > matrix_error . errcode ) ;
const int status_code = static_cast < int > ( err - > status_code ) ;
nhlog : : net ( ) - > error ( " initial sync error: {} {} " , status_code , err_code ) ;
// non http related errors
if ( status_code < = 0 | | status_code > = 600 ) {
startInitialSync ( ) ;
return ;
}
switch ( status_code ) {
case 502 :
case 504 :
case 524 : {
startInitialSync ( ) ;
return ;
}
default : {
emit dropToLoginPageCb ( msg ) ;
return ;
}
}
}
nhlog : : net ( ) - > info ( " initial sync completed " ) ;
try {
cache : : client ( ) - > saveState ( res ) ;
olm : : handle_to_device_messages ( res . to_device . events ) ;
emit initializeViews ( std : : move ( res . rooms ) ) ;
emit initializeRoomList ( cache : : roomInfo ( ) ) ;
emit initializeMentions ( cache : : getTimelineMentions ( ) ) ;
cache : : calculateRoomReadStatus ( ) ;
emit syncTags ( cache : : roomInfo ( ) . toStdMap ( ) ) ;
} catch ( const lmdb : : error & e ) {
nhlog : : db ( ) - > error ( " failed to save state after initial sync: {} " ,
e . what ( ) ) ;
startInitialSync ( ) ;
return ;
}
emit trySyncCb ( ) ;
emit contentLoaded ( ) ;
} ) ;
}
}
void
void
ChatPage : : handleSyncResponse ( mtx : : responses : : Sync res )
ChatPage : : handleSyncResponse ( const mtx : : responses : : Sync & res )
{
{
nhlog : : net ( ) - > debug ( " sync completed: {} " , res . next_batch ) ;
nhlog : : net ( ) - > debug ( " sync completed: {} " , res . next_batch ) ;
@ -984,16 +1038,16 @@ ChatPage::handleSyncResponse(mtx::responses::Sync res)
// TODO: fine grained error handling
// TODO: fine grained error handling
try {
try {
cache : : saveState ( res ) ;
cache : : client ( ) - > saveState ( res ) ;
olm : : handle_to_device_messages ( res . to_device . events ) ;
olm : : handle_to_device_messages ( res . to_device . events ) ;
auto updates = cache : : roomUpdates ( res ) ;
auto updates = cache : : getRoomInfo ( cache : : client ( ) - > roomsWithState Updates ( res ) ) ;
emit syncRoomlist ( updates ) ;
emit syncRoomlist ( updates ) ;
emit syncUI ( res . rooms ) ;
emit syncUI ( res . rooms ) ;
emit syncTags ( cache : : roomTagUpdates ( res ) ) ;
emit syncTags ( cache : : getRoomInfo ( cache : : client ( ) - > roomsWith TagUpdates ( res ) ) ) ;
// if we process a lot of syncs (1 every 200ms), this means we clean the
// if we process a lot of syncs (1 every 200ms), this means we clean the
// db every 100s
// db every 100s
@ -1068,7 +1122,7 @@ ChatPage::joinRoom(const QString &room)
const auto room_id = room . toStdString ( ) ;
const auto room_id = room . toStdString ( ) ;
http : : client ( ) - > join_room (
http : : client ( ) - > join_room (
room_id , [ this , room_id ] ( const nlohmann : : json & , mtx : : http : : RequestErr err ) {
room_id , [ this , room_id ] ( const mtx : : responses : : RoomId & , mtx : : http : : RequestErr err ) {
if ( err ) {
if ( err ) {
emit showNotification (
emit showNotification (
tr ( " Failed to join room: %1 " )
tr ( " Failed to join room: %1 " )
@ -1114,7 +1168,8 @@ void
ChatPage : : leaveRoom ( const QString & room_id )
ChatPage : : leaveRoom ( const QString & room_id )
{
{
http : : client ( ) - > leave_room (
http : : client ( ) - > leave_room (
room_id . toStdString ( ) , [ this , room_id ] ( const json & , mtx : : http : : RequestErr err ) {
room_id . toStdString ( ) ,
[ this , room_id ] ( const mtx : : responses : : RoomId & , mtx : : http : : RequestErr err ) {
if ( err ) {
if ( err ) {
emit showNotification (
emit showNotification (
tr ( " Failed to leave room: %1 " )
tr ( " Failed to leave room: %1 " )
@ -1289,62 +1344,6 @@ ChatPage::currentPresence() const
}
}
}
}
void
ChatPage : : initialSyncHandler ( const mtx : : responses : : Sync & res , mtx : : http : : RequestErr err )
{
// TODO: Initial Sync should include mentions as well...
if ( err ) {
const auto error = QString : : fromStdString ( err - > matrix_error . error ) ;
const auto msg = tr ( " Please try to login again: %1 " ) . arg ( error ) ;
const auto err_code = mtx : : errors : : to_string ( err - > matrix_error . errcode ) ;
const int status_code = static_cast < int > ( err - > status_code ) ;
nhlog : : net ( ) - > error ( " initial sync error: {} {} " , status_code , err_code ) ;
// non http related errors
if ( status_code < = 0 | | status_code > = 600 ) {
startInitialSync ( ) ;
return ;
}
switch ( status_code ) {
case 502 :
case 504 :
case 524 : {
startInitialSync ( ) ;
return ;
}
default : {
emit dropToLoginPageCb ( msg ) ;
return ;
}
}
}
nhlog : : net ( ) - > info ( " initial sync completed " ) ;
try {
cache : : saveState ( res ) ;
olm : : handle_to_device_messages ( res . to_device . events ) ;
emit initializeViews ( std : : move ( res . rooms ) ) ;
emit initializeRoomList ( cache : : roomInfo ( ) ) ;
emit initializeMentions ( cache : : getTimelineMentions ( ) ) ;
cache : : calculateRoomReadStatus ( ) ;
emit syncTags ( cache : : roomInfo ( ) . toStdMap ( ) ) ;
} catch ( const lmdb : : error & e ) {
nhlog : : db ( ) - > error ( " failed to save state after initial sync: {} " , e . what ( ) ) ;
startInitialSync ( ) ;
return ;
}
emit trySyncCb ( ) ;
emit contentLoaded ( ) ;
}
void
void
ChatPage : : ensureOneTimeKeyCount ( const std : : map < std : : string , uint16_t > & counts )
ChatPage : : ensureOneTimeKeyCount ( const std : : map < std : : string , uint16_t > & counts )
{
{
@ -1453,51 +1452,11 @@ ChatPage::initiateLogout()
emit showOverlayProgressBar ( ) ;
emit showOverlayProgressBar ( ) ;
}
}
void
ChatPage : : query_keys ( const std : : string & user_id ,
std : : function < void ( const UserKeyCache & , mtx : : http : : RequestErr ) > cb )
{
auto cache_ = cache : : userKeys ( user_id ) ;
if ( cache_ . has_value ( ) ) {
if ( ! cache_ - > updated_at . empty ( ) & & cache_ - > updated_at = = cache_ - > last_changed ) {
cb ( cache_ . value ( ) , { } ) ;
return ;
}
}
mtx : : requests : : QueryKeys req ;
req . device_keys [ user_id ] = { } ;
std : : string last_changed ;
if ( cache_ )
last_changed = cache_ - > last_changed ;
req . token = last_changed ;
http : : client ( ) - > query_keys ( req ,
[ cb , user_id , last_changed ] ( const mtx : : responses : : QueryKeys & res ,
mtx : : http : : RequestErr err ) {
if ( err ) {
nhlog : : net ( ) - > warn (
" failed to query device keys: {},{} " ,
err - > matrix_error . errcode ,
static_cast < int > ( err - > status_code ) ) ;
cb ( { } , err ) ;
return ;
}
cache : : updateUserKeys ( last_changed , res ) ;
auto keys = cache : : userKeys ( user_id ) ;
cb ( keys . value_or ( UserKeyCache { } ) , err ) ;
} ) ;
}
template < typename T >
template < typename T >
void
void
ChatPage : : connectCallMessage ( )
ChatPage : : connectCallMessage ( )
{
{
connect ( & callManager_ ,
connect ( callManager_ ,
qOverload < const QString & , const T & > ( & CallManager : : newMessage ) ,
qOverload < const QString & , const T & > ( & CallManager : : newMessage ) ,
view_manager_ ,
view_manager_ ,
qOverload < const QString & , const T & > ( & TimelineViewManager : : queueCallMessage ) ) ;
qOverload < const QString & , const T & > ( & TimelineViewManager : : queueCallMessage ) ) ;