Skip to content

Commit

Permalink
Merge branch 'task/cht-1325-connect-nse-for-single-chat' into 'develop'
Browse files Browse the repository at this point in the history
CHT-1325. Allow NSE to connect just to 1 chat instead all of them (Refactor)

See merge request megachat/MEGAchat!1976
  • Loading branch information
jgandres committed Sep 3, 2024
2 parents cb11717 + 6540447 commit 6582b0e
Show file tree
Hide file tree
Showing 7 changed files with 260 additions and 45 deletions.
90 changes: 75 additions & 15 deletions src/chatClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1196,13 +1196,41 @@ void Client::saveDb()
}
}

void Client::connectLeanMode(Id chatId)
{
assert(chatId.isValid());
if (!mChatdClient->isChatLoggedIn(chatId) && mConnState != kDisconnected)
{
disconnectLeanMode();
}

// enable chatId and disable the rest of chats
mChatdClient->enableChats(true /*enable*/, chatId);
notifyUserStatus(true);

// is mandatory to call connect() as we are in lean mode
connect(false /*connectPresenced*/);
}

bool Client::isPendingPush()
{
return mSyncTimer;
}

void Client::enableAllChats()
{
mChatdClient->enableChats(true /*enable*/);
}

promise::Promise<void> Client::pushReceived(Id chatid)
{
const bool iosPushReceived = chatid.isValid();
promise::Promise<void> pms;
ChatRoomList::const_iterator it = chats->find(chatid);
ChatRoom *room = (it != chats->end()) ? it->second : NULL;
if (!room || room->isArchived())
{
assert(!iosPushReceived);
// room unknown or archived --> need to catchup wiht API to receive pending
// actionpackets that may notify about a new chat or an existing chat being
// unarchived (don't want notifications for archived)
Expand All @@ -1221,8 +1249,9 @@ promise::Promise<void> Client::pushReceived(Id chatid)
return promise::Error("Up to date with API, but instance was removed");

// if already sent SYNCs or we are not logged in right now...
if (mSyncTimer)
if (isPendingPush())
{
assert(!chatid.isValid()); // NSE should not have previous push in flight
KR_LOG_WARNING("%spushReceived: a previous PUSH is being processed. Both will finish "
"at the same time",
getLoggingName());
Expand All @@ -1244,6 +1273,9 @@ promise::Promise<void> Client::pushReceived(Id chatid)
return mSyncPromise;
}

// we are connected to all chats, sync with push received chatid or all (Android)
// mSyncPromise is resolved when we are connected to all chats or when we receive sync from
// chatd for chatid or all (Android)
mSyncCount = 0;
mSyncTimer = karere::setTimeout([this, wptr]()
{
Expand All @@ -1260,9 +1292,26 @@ promise::Promise<void> Client::pushReceived(Id chatid)

if (chatid.isValid())
{
ChatRoom *chat = chats->at(chatid);
mSyncCount++;
chat->sendSync();
ChatRoom* chat = chats->at(chatid);
if (!chat->chat().isDisabled())
{
mSyncCount++;
if (mSyncCount != 1)
{
KR_LOG_ERROR("%spushReceived (iOS): mSyncCount: %d (it should be 1)",
getLoggingName(),
mSyncCount);
assert(false);
}
chat->sendSync();
}
else
{
KR_LOG_ERROR("%spushReceived (iOS): chatid should be enabled %s",
getLoggingName(),
chatid.toString().c_str());
assert(false);
}
}
else
{
Expand Down Expand Up @@ -1550,15 +1599,7 @@ Client::InitState Client::init(const char* sid, bool waitForFetchnodesToConnect)
return kInitErrGeneric;
}

mInitStats.onCanceled(); // do not collect stats for this initialization mode

// connect() should be done in main thread, not app's thread, since LWS is single threaded
// and the `wsi` context must be created by the main thread, where it runs the event's loop
marshallCall([this]()
{
notifyUserStatus(true);
connect();
}, appCtx);
mInitStats.onCanceled(); // do not collect stats for this initialization mode
}

mInitStats.stageEnd(InitStats::kStatsInit);
Expand Down Expand Up @@ -1946,7 +1987,23 @@ void Client::dumpContactList(::mega::MegaUserList& clist)
KR_LOG_DEBUG("%s== Contactlist end ==", getLoggingName());
}

void Client::connect()
void Client::disconnectLeanMode()
{
assert(mConnState != kDisconnected);
mInitStats.onCanceled();
setConnState(kDisconnected);

// stop heartbeats
if (mHeartbeatTimer)
{
karere::cancelInterval(mHeartbeatTimer, appCtx);
mHeartbeatTimer = 0;
}

mChatdClient->disconnect(true);
}

void Client::connect(const bool connectPresenced)
{
// cancel stats if connection is done in background (not reliable times)
if (mIsInBackground && !mInitStats.isCompleted())
Expand Down Expand Up @@ -2006,7 +2063,10 @@ void Client::connect()
KR_LOG_DEBUG("%sOwn screen name is: '%s'", loggingName, name.c_str() + 1);
});

mPresencedClient.connect();
if (connectPresenced)
{
mPresencedClient.connect();
}
setConnState(kConnected);
}

Expand Down
27 changes: 26 additions & 1 deletion src/chatClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,24 @@ class Client: public ::mega::MegaGlobalListener,
/** @brief There is a call in state in-progress in the chatroom and the client is participating*/
bool isCallInProgress(const karere::Id& chatid = karere::Id::inval()) const;

/**
* @brief Disables all chatrooms except chatid, and perform Client connect (chatd)
* This method allows NSE to connect just to chatid for which it received push notification
* @param chatId The chat handle that identifies chatroom
*/
void connectLeanMode(Id chatId);

/**
* @brief Checks if there's a pending push notification being proccessed at this moment
* @return true if there's a push notification in flight, otherwise returns false
*/
bool isPendingPush();

/**
* @brief Enables all chatrooms
*/
void enableAllChats();

/** @brief Catch up with API for pending actionpackets*/
promise::Promise<void> pushReceived(Id chatid);
void onSyncReceived(const karere::Id& chatid); // called upon SYNC reception
Expand Down Expand Up @@ -1346,6 +1364,11 @@ class Client: public ::mega::MegaGlobalListener,
bool checkSyncWithSdkDb(const std::string& scsn, ::mega::MegaUserList& aContactList, ::mega::MegaTextChatList& chats, bool forceReload);
void commit(const std::string& scsn);

/**
* @brief Performs full karere client disconnection (without reconnect)
*/
void disconnectLeanMode();

/** @brief Does the actual connection to chatd and presenced. Assumes the
* Mega SDK is already logged in. This must be called after
* \c initWithNewSession() or \c checkSyncWithDb() completes
Expand All @@ -1354,8 +1377,10 @@ class Client: public ::mega::MegaGlobalListener,
* background, it should not send KEEPALIVE, but KEEPALIVEAWAY to chatd. Hence, it will
* avoid to tell chatd that the client is active. Also, the presenced client will
* prevent to send USERACTIVE 1 in background, since the user is not active.
*
* @param connectPresenced if false it avoids connect to presenced (i.e for NSE)
*/
void connect();
void connect(const bool connectPresenced = true);
void setConnState(ConnState newState);

// mega::MegaGlobalListener interface, called by worker thread
Expand Down
73 changes: 54 additions & 19 deletions src/chatd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,16 @@ void Client::setRetentionTimer()
}, static_cast<unsigned int> (retentionPeriod * 1000) , mKarereClient->appCtx);
}

void Client::enableChats(const bool enable, const karere::Id& chatId)
{
const auto allChats = !chatId.isValid();
for (const auto& [id, chat]: mChatForChatId)
{
const auto disable = (allChats || id == chatId) ? !enable : enable;
chat->disable(disable);
}
}

uint8_t Client::richLinkState() const
{
return mRichLinkState;
Expand Down Expand Up @@ -478,6 +488,16 @@ bool Client::areAllChatsLoggedIn(int shard)
return allConnected;
}

bool Client::isChatLoggedIn(const karere::Id& chatId)
{
if (const auto it = mChatForChatId.find(chatId); it != mChatForChatId.end())
{
return it->second->isLoggedIn();
}

return false;
}

void Chat::connect()
{
if ((mConnection.state() == Connection::kStateNew))
Expand Down Expand Up @@ -755,7 +775,7 @@ void Connection::resetConnSuceededAttempts(const time_t &t)
mConnSuceeded = 0;
}

void Connection::setState(State state)
void Connection::setState(State state, const bool avoidReconnect)
{
State oldState = mState;
if (mState == state)
Expand Down Expand Up @@ -807,25 +827,34 @@ void Connection::setState(State state)
mConnectTimer = 0;
}

if (!mChatdClient.mKarereClient->isTerminated())
if (!mChatdClient.mKarereClient->isTerminated() && !avoidReconnect)
{
// start a timer to ensure the connection is established after kConnectTimeout. Otherwise, reconnect
// start a timer to ensure the connection is established after kConnectTimeout.
// Otherwise, reconnect
auto wptr = weakHandle();
mConnectTimer = setTimeout([this, wptr]()
{
if (wptr.deleted())
return;

mConnectTimer = 0;
mConnectTimer = setTimeout(
[this, wptr]()
{
if (wptr.deleted())
return;

CHATDS_LOG_DEBUG("%sReconnection attempt has not succeed after %d. Reconnecting...",
mChatdClient.getLoggingName(),
kConnectTimeout);
mChatdClient.mKarereClient->api.callIgnoreResult(&::mega::MegaApi::sendEvent, 99004, "Reconnection timed out", false, static_cast<const char*>(nullptr));
mConnectTimer = 0;

retryPendingConnection(true);
CHATDS_LOG_DEBUG(
"%sReconnection attempt has not succeed after %d. Reconnecting...",
mChatdClient.getLoggingName(),
kConnectTimeout);
mChatdClient.mKarereClient->api.callIgnoreResult(
&::mega::MegaApi::sendEvent,
99004,
"Reconnection timed out",
false,
static_cast<const char*>(nullptr));

}, kConnectTimeout * 1000, mChatdClient.mKarereClient->appCtx);
retryPendingConnection(true);
},
kConnectTimeout * 1000,
mChatdClient.mKarereClient->appCtx);
}

// notify chatrooms that connection is down
Expand Down Expand Up @@ -1158,9 +1187,14 @@ void Connection::abortRetryController()
mRetryCtrl.reset();
}

void Connection::disconnect()
void Connection::disconnect(const bool avoidReconnect)
{
setState(kStateDisconnected);
setState(kStateDisconnected, avoidReconnect);
if (avoidReconnect)
{
abortRetryController();
setState(kStateNew);
}
}

void Connection::doConnect()
Expand Down Expand Up @@ -1394,11 +1428,11 @@ promise::Promise<void> Connection::fetchUrl()
});
}

void Client::disconnect()
void Client::disconnect(const bool avoidReconnect)
{
for (auto& conn: mConnections)
{
conn.second->disconnect();
conn.second->disconnect(avoidReconnect);
}
}

Expand Down Expand Up @@ -1763,6 +1797,7 @@ string KeyCommand::toString() const
tmpString.append(to_string(mLocalKeyid));
return tmpString;
}

// rejoin all open chats after reconnection (this is mandatory)
bool Connection::rejoinExistingChats()
{
Expand Down
Loading

0 comments on commit 6582b0e

Please sign in to comment.