Commit 6dff5ee3 authored by Hugo Lefeuvre's avatar Hugo Lefeuvre Committed by Andreas Traczyk

newaccountmodel: stop using old lrc for accountsChanged signal

Add a CallbackHandler entry for deamon signal accountsChanged.

Add an updateAccounts() function to the NewAccountModel and connect it
to this new signal. This function detects new accounts and account
removals. It calls addToAccounts and removeFromAccounts (formerly
slotAccountRemoved) when appropriate.

Stop using registrationStateChanged signal to detect new accounts.

Fix various race conditions and potential errors during account
creation and removal.

Change-Id: Id774df852e63b69658160473962ec499fc244c53
Reviewed-by: Andreas Traczyk's avatarAndreas Traczyk <andreas.traczyk@savoirfairelinux.com>
parent 489cf2b2
...@@ -93,6 +93,11 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent) ...@@ -93,6 +93,11 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent)
&CallbacksHandler::slotAccountDetailsChanged, &CallbacksHandler::slotAccountDetailsChanged,
Qt::QueuedConnection); Qt::QueuedConnection);
connect(&ConfigurationManager::instance(),
&ConfigurationManagerInterface::accountsChanged,
this,
&CallbacksHandler::slotAccountsChanged);
connect(&ConfigurationManager::instance(), connect(&ConfigurationManager::instance(),
&ConfigurationManagerInterface::registrationStateChanged, &ConfigurationManagerInterface::registrationStateChanged,
this, this,
...@@ -273,6 +278,12 @@ CallbacksHandler::slotAccountDetailsChanged(const QString& accountId, ...@@ -273,6 +278,12 @@ CallbacksHandler::slotAccountDetailsChanged(const QString& accountId,
emit accountDetailsChanged(accountId.toStdString(), convertMap(details)); emit accountDetailsChanged(accountId.toStdString(), convertMap(details));
} }
void
CallbacksHandler::slotAccountsChanged()
{
emit accountsChanged();
}
void void
CallbacksHandler::slotRegistrationStateChanged(const QString& accountId, CallbacksHandler::slotRegistrationStateChanged(const QString& accountId,
const QString& registration_state, const QString& registration_state,
......
...@@ -112,6 +112,10 @@ Q_SIGNALS: ...@@ -112,6 +112,10 @@ Q_SIGNALS:
*/ */
void accountDetailsChanged(const std::string& accountId, void accountDetailsChanged(const std::string& accountId,
const std::map<std::string,std::string>& details); const std::map<std::string,std::string>& details);
/**
* Connect this signal to know when the accounts list changed
*/
void accountsChanged();
/** /**
* Connect this signal to know when the account status changed * Connect this signal to know when the account status changed
* @param accountId the one who changes * @param accountId the one who changes
...@@ -280,6 +284,11 @@ private Q_SLOTS: ...@@ -280,6 +284,11 @@ private Q_SLOTS:
*/ */
void slotAccountDetailsChanged(const QString& accountId, void slotAccountDetailsChanged(const QString& accountId,
const MapStringString& details); const MapStringString& details);
/**
* Emit accountsChanged
*/
void slotAccountsChanged();
/** /**
* Emit accountStatusChanged * Emit accountStatusChanged
* @param accountId * @param accountId
......
...@@ -73,7 +73,8 @@ public: ...@@ -73,7 +73,8 @@ public:
NewAccountModel::AccountInfoMap accounts; NewAccountModel::AccountInfoMap accounts;
const BehaviorController& behaviorController; const BehaviorController& behaviorController;
// Synchronization tools for account removal // Synchronization tools
std::mutex m_mutex_account;
std::mutex m_mutex_account_removal; std::mutex m_mutex_account_removal;
std::condition_variable m_condVar_account_removal; std::condition_variable m_condVar_account_removal;
...@@ -84,13 +85,26 @@ public: ...@@ -84,13 +85,26 @@ public:
*/ */
void addToAccounts(const std::string& accountId); void addToAccounts(const std::string& accountId);
/**
* Remove account from accounts list. Emit accountRemoved.
* @param accountId
*/
void removeFromAccounts(const std::string& accountId);
/**
* Sync changes to the accounts list with the lrc.
*/
void updateAccounts();
public Q_SLOTS: public Q_SLOTS:
/** /**
* Emit accountStatusChanged. * Emit accountStatusChanged.
* @param accountId * @param accountId
* @param status * @param status
*/ */
void slotAccountStatusChanged(const std::string& accountID, const api::account::Status status); void slotAccountStatusChanged(const std::string& accountID, const api::account::Status status);
/** /**
* Emit exportOnRingEnded. * Emit exportOnRingEnded.
* @param accountId * @param accountId
...@@ -98,17 +112,16 @@ public Q_SLOTS: ...@@ -98,17 +112,16 @@ public Q_SLOTS:
* @param pin * @param pin
*/ */
void slotExportOnRingEnded(const std::string& accountID, int status, const std::string& pin); void slotExportOnRingEnded(const std::string& accountID, int status, const std::string& pin);
/** /**
* @param accountId * @param accountId
* @param details * @param details
*/ */
void slotAccountDetailsChanged(const std::string& accountID, const std::map<std::string, std::string>& details); void slotAccountDetailsChanged(const std::string& accountID, const std::map<std::string, std::string>& details);
/** /**
* Emit accountRemoved. * @param profile
* @param account
*/ */
void slotAccountRemoved(Account* account);
void slotProfileUpdated(const Profile* profile); void slotProfileUpdated(const Profile* profile);
/** /**
...@@ -317,6 +330,7 @@ NewAccountModelPimpl::NewAccountModelPimpl(NewAccountModel& linked, ...@@ -317,6 +330,7 @@ NewAccountModelPimpl::NewAccountModelPimpl(NewAccountModel& linked,
for (auto& id : accountIds) for (auto& id : accountIds)
addToAccounts(id.toStdString()); addToAccounts(id.toStdString());
connect(&callbacksHandler, &CallbacksHandler::accountsChanged, this, &NewAccountModelPimpl::updateAccounts);
connect(&callbacksHandler, &CallbacksHandler::accountStatusChanged, this, &NewAccountModelPimpl::slotAccountStatusChanged); connect(&callbacksHandler, &CallbacksHandler::accountStatusChanged, this, &NewAccountModelPimpl::slotAccountStatusChanged);
connect(&callbacksHandler, &CallbacksHandler::accountDetailsChanged, this, &NewAccountModelPimpl::slotAccountDetailsChanged); connect(&callbacksHandler, &CallbacksHandler::accountDetailsChanged, this, &NewAccountModelPimpl::slotAccountDetailsChanged);
connect(&callbacksHandler, &CallbacksHandler::exportOnRingEnded, this, &NewAccountModelPimpl::slotExportOnRingEnded); connect(&callbacksHandler, &CallbacksHandler::exportOnRingEnded, this, &NewAccountModelPimpl::slotExportOnRingEnded);
...@@ -325,28 +339,62 @@ NewAccountModelPimpl::NewAccountModelPimpl(NewAccountModel& linked, ...@@ -325,28 +339,62 @@ NewAccountModelPimpl::NewAccountModelPimpl(NewAccountModel& linked,
connect(&callbacksHandler, &CallbacksHandler::migrationEnded, this, &NewAccountModelPimpl::slotMigrationEnded); connect(&callbacksHandler, &CallbacksHandler::migrationEnded, this, &NewAccountModelPimpl::slotMigrationEnded);
// NOTE: because we still use the legacy LRC for configuration, we are still using old signals // NOTE: because we still use the legacy LRC for configuration, we are still using old signals
connect(&AccountModel::instance(), &AccountModel::accountRemoved, this, &NewAccountModelPimpl::slotAccountRemoved);
connect(&ProfileModel::instance(), &ProfileModel::profileUpdated, this, &NewAccountModelPimpl::slotProfileUpdated); connect(&ProfileModel::instance(), &ProfileModel::profileUpdated, this, &NewAccountModelPimpl::slotProfileUpdated);
} }
NewAccountModelPimpl::~NewAccountModelPimpl() NewAccountModelPimpl::~NewAccountModelPimpl()
{ {
}
void
NewAccountModelPimpl::updateAccounts()
{
qDebug() << "Syncing lrc accounts list with the daemon";
ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance();
QStringList accountIds = configurationManager.getAccountList();
// Detect removed accounts
std::list<std::string> toBeRemoved;
for (auto& it : accounts) {
auto& accountInfo = it.second;
if (!accountIds.contains(QString::fromStdString(accountInfo.id))) {
qDebug("detected account removal %s", accountInfo.id.c_str());
toBeRemoved.push_back(accountInfo.id);
}
}
for (auto it = toBeRemoved.begin(); it != toBeRemoved.end(); ++it) {
removeFromAccounts(*it);
}
// Detect new accounts
for (auto& id : accountIds) {
auto accountInfo = accounts.find(id.toStdString());
if (accountInfo == accounts.end()) {
qDebug("detected new account %s", id.toStdString().c_str());
addToAccounts(id.toStdString());
}
}
} }
void void
NewAccountModelPimpl::slotAccountStatusChanged(const std::string& accountID, const api::account::Status status) NewAccountModelPimpl::slotAccountStatusChanged(const std::string& accountID, const api::account::Status status)
{ {
auto accountInfo = accounts.find(accountID); auto it = accounts.find(accountID);
if (status == api::account::Status::REGISTERED && accountInfo == accounts.end()) {
// Update account // If account is not in the map yet, don't add it, it is updateAccounts's job
// NOTE we don't connect to newAccountAdded from AccountModel if (it == accounts.end()) {
// because the account is not ready. return;
}
auto& accountInfo = it->second;
if (status == api::account::Status::REGISTERED && accountInfo.profileInfo.uri.empty()) {
accounts.erase(accountID); accounts.erase(accountID);
addToAccounts(accountID); addToAccounts(accountID);
emit linked.accountAdded(accountID); emit linked.accountAdded(accountID);
} else if (accountInfo != accounts.end()) { } else {
accountInfo->second.status = status; accountInfo.status = status;
emit linked.accountStatusChanged(accountID); emit linked.accountStatusChanged(accountID);
} }
} }
...@@ -460,39 +508,50 @@ NewAccountModelPimpl::slotMigrationEnded(const std::string& accountId, bool ok) ...@@ -460,39 +508,50 @@ NewAccountModelPimpl::slotMigrationEnded(const std::string& accountId, bool ok)
void void
NewAccountModelPimpl::addToAccounts(const std::string& accountId) NewAccountModelPimpl::addToAccounts(const std::string& accountId)
{ {
auto it = accounts.emplace(accountId, account::Info());
if (!it.second) {
qDebug("failed to add new account: id already present in map");
return;
}
// Init profile // Init profile
auto& item = *(accounts.emplace(accountId, account::Info()).first); account::Info& newAcc = (it.first)->second;
auto& owner = item.second; newAcc.id = accountId;
owner.id = accountId;
// Fill account::Info struct with details from daemon // Fill account::Info struct with details from daemon
MapStringString details = ConfigurationManager::instance().getAccountDetails(accountId.c_str()); MapStringString details = ConfigurationManager::instance().getAccountDetails(accountId.c_str());
owner.fromDetails(details); newAcc.fromDetails(details);
// Add profile into database // Add profile to database
using namespace DRing::Account; std::string accountType = newAcc.profileInfo.type == profile::Type::RING ?
auto accountType = owner.profileInfo.type == profile::Type::RING ? std::string(ProtocolNames::RING) : std::string(ProtocolNames::SIP); DRing::Account::ProtocolNames::RING :
auto accountProfileId = authority::database::getOrInsertProfile(database, owner.profileInfo.uri, DRing::Account::ProtocolNames::SIP;
owner.profileInfo.alias, "", auto accountProfileId = authority::database::getOrInsertProfile(database,
newAcc.profileInfo.uri,
newAcc.profileInfo.alias,
"",
accountType); accountType);
// Retrieve avatar from database // Retrieve avatar from database
auto avatar = authority::database::getAvatarForProfileId(database, accountProfileId); newAcc.profileInfo.avatar = authority::database::getAvatarForProfileId(database, accountProfileId);
owner.profileInfo.avatar = avatar;
// Init models for this account // Init models for this account
owner.callModel = std::make_unique<NewCallModel>(owner, callbacksHandler); newAcc.callModel = std::make_unique<NewCallModel>(newAcc, callbacksHandler);
owner.contactModel = std::make_unique<ContactModel>(owner, database, callbacksHandler, behaviorController); newAcc.contactModel = std::make_unique<ContactModel>(newAcc, database, callbacksHandler, behaviorController);
owner.conversationModel = std::make_unique<ConversationModel>(owner, lrc, database, callbacksHandler, behaviorController); newAcc.conversationModel = std::make_unique<ConversationModel>(newAcc, lrc, database, callbacksHandler, behaviorController);
owner.deviceModel = std::make_unique<NewDeviceModel>(owner, callbacksHandler); newAcc.deviceModel = std::make_unique<NewDeviceModel>(newAcc, callbacksHandler);
owner.codecModel = std::make_unique<NewCodecModel>(owner, callbacksHandler); newAcc.codecModel = std::make_unique<NewCodecModel>(newAcc, callbacksHandler);
owner.accountModel = &linked; newAcc.accountModel = &linked;
MapStringString volatileDetails = ConfigurationManager::instance().getVolatileAccountDetails(accountId.c_str()); MapStringString volatileDetails = ConfigurationManager::instance().getVolatileAccountDetails(accountId.c_str());
owner.status = lrc::api::account::to_status(toStdString(volatileDetails[ConfProperties::Registration::STATUS])); std::string daemonStatus = volatileDetails[DRing::Account::ConfProperties::Registration::STATUS].toStdString();
newAcc.status = lrc::api::account::to_status(daemonStatus);
} }
void void
NewAccountModelPimpl::slotAccountRemoved(Account* account) NewAccountModelPimpl::removeFromAccounts(const std::string& accountId)
{ {
auto accountId = account->id().toStdString();
/* Update db before waiting for the client to stop using the structs is fine /* Update db before waiting for the client to stop using the structs is fine
as long as we don't free anything */ as long as we don't free anything */
authority::database::removeAccount(database, accounts[accountId].profileInfo.uri); authority::database::removeAccount(database, accounts[accountId].profileInfo.uri);
...@@ -530,7 +589,7 @@ account::Info::fromDetails(const MapStringString& details) ...@@ -530,7 +589,7 @@ account::Info::fromDetails(const MapStringString& details)
// General // General
if (details[ConfProperties::TYPE] != "") if (details[ConfProperties::TYPE] != "")
profileInfo.type = details[ConfProperties::TYPE] == QString(ProtocolNames::RING) ? profile::Type::RING : profile::Type::SIP; profileInfo.type = details[ConfProperties::TYPE] == QString(ProtocolNames::RING) ? profile::Type::RING : profile::Type::SIP;
registeredName = profileInfo.type == profile::Type::RING ? volatileDetails[VolatileProperties::REGISTERED_NAME].toStdString() : profileInfo.alias; registeredName = profileInfo.type == profile::Type::RING ? volatileDetails[VolatileProperties::REGISTERED_NAME].toStdString() : profileInfo.alias;
profileInfo.alias = toStdString(details[ConfProperties::ALIAS]); profileInfo.alias = toStdString(details[ConfProperties::ALIAS]);
enabled = toBool(details[ConfProperties::ENABLED]); enabled = toBool(details[ConfProperties::ENABLED]);
...@@ -539,7 +598,9 @@ account::Info::fromDetails(const MapStringString& details) ...@@ -539,7 +598,9 @@ account::Info::fromDetails(const MapStringString& details)
confProperties.autoAnswer = toBool(details[ConfProperties::AUTOANSWER]); confProperties.autoAnswer = toBool(details[ConfProperties::AUTOANSWER]);
confProperties.activeCallLimit = toInt(details[ConfProperties::ACTIVE_CALL_LIMIT]); confProperties.activeCallLimit = toInt(details[ConfProperties::ACTIVE_CALL_LIMIT]);
confProperties.hostname = toStdString(details[ConfProperties::HOSTNAME]); confProperties.hostname = toStdString(details[ConfProperties::HOSTNAME]);
profileInfo.uri = (profileInfo.type == profile::Type::RING and details[ConfProperties::USERNAME].contains("ring:")) ? details[ConfProperties::USERNAME].toStdString().substr(std::string("ring:").size()) : details[ConfProperties::USERNAME].toStdString(); profileInfo.uri = (profileInfo.type == profile::Type::RING and details[ConfProperties::USERNAME].contains("ring:"))
? details[ConfProperties::USERNAME].toStdString().substr(std::string("ring:").size())
: details[ConfProperties::USERNAME].toStdString();
confProperties.username = toStdString(details[ConfProperties::USERNAME]); confProperties.username = toStdString(details[ConfProperties::USERNAME]);
confProperties.routeset = toStdString(details[ConfProperties::ROUTE]); confProperties.routeset = toStdString(details[ConfProperties::ROUTE]);
confProperties.password = toStdString(details[ConfProperties::PASSWORD]); confProperties.password = toStdString(details[ConfProperties::PASSWORD]);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment