Commit 44a3d071 authored by Anthony Léonard's avatar Anthony Léonard Committed by Guillaume Roguez

fix code for datatransfer

Many fixes to adapt LRC to the new datatransfer.

Change-Id: Ibbe322a32d44800c54e9a7ffd99c42a57200deb7
Signed-off-by: Guillaume Roguez's avatarGuillaume Roguez <guillaume.roguez@savoirfairelinux.com>
parent 4ce62577
......@@ -33,6 +33,7 @@
// Data
#include "api/conversation.h"
#include "api/profile.h"
#include "api/datatransfer.h"
namespace lrc
{
......@@ -46,6 +47,8 @@ namespace api
namespace account { struct Info; }
namespace interaction { struct Info; }
class Lrc;
class BehaviorController;
class NewAccountModel;
......@@ -60,6 +63,7 @@ public:
const account::Info& owner;
ConversationModel(const account::Info& owner,
Lrc& lrc,
Database& db,
const CallbacksHandler& callbacksHandler,
const api::BehaviorController& behaviorController);
......@@ -154,6 +158,8 @@ public:
void cancelTransfer(const std::string& convUid, uint64_t interactionId);
void getTransferInfo(uint64_t interactionId, api::datatransfer::Info& info);
Q_SIGNALS:
/**
* Emitted when a conversation receives a new interaction
......
......@@ -91,7 +91,7 @@ to_status(const std::string& status)
struct Info
{
const std::string uid; ///< long-term and unique identifier (used for historic)
std::string uid; ///< long-term and unique identifier (used for historic)
Status status;
bool isOutgoing;
std::size_t totalSize;
......
......@@ -52,16 +52,15 @@ class LIB_EXPORT DataTransferModel : public QObject {
Q_OBJECT
public:
DataTransferModel(Database& database,
const CallbacksHandler& callbacksHandler);
DataTransferModel();
~DataTransferModel();
void sendFile(const std::string& account_id, const std::string& peer_uri,
const std::string& file_path, const std::string& display_name);
const std::string& file_path, const std::string& display_name);
datatransfer::Info transferInfo(const std::string& uid);
void transferInfo(long long ringId, datatransfer::Info& lrc_info);
std::streamsize bytesProgress(int interactionId);
void bytesProgress(int interactionId, int64_t& total, int64_t& progress);
void accept(int interactionId, const std::string& file_path, std::size_t offset);
......@@ -71,6 +70,8 @@ public:
int getInteractionIdFromDringId(long long dringId);
long long getDringIdFromInteractionId(int interactionId);
Q_SIGNALS:
/**
* Connect this signal to know when a data transfer is incoming.
......
......@@ -125,6 +125,7 @@ to_string(const Status& status)
return "TRANSFER_AWAITING";
case Status::TRANSFER_FINISHED:
return "TRANSFER_FINISHED";
case Status::INVALID:
default:
return "INVALID";
}
......
......@@ -34,6 +34,7 @@ namespace api
class BehaviorController;
class NewAccountModel;
class DataTransferModel;
class LIB_EXPORT Lrc {
public:
......@@ -49,6 +50,11 @@ public:
* @return a BehaviorController&.
*/
const BehaviorController& getBehaviorController() const;
/**
* get a reference on the DataTransfer controller.
* @return a DataTransferModel&.
*/
DataTransferModel& getDataTransferModel() const;
private:
std::unique_ptr<LrcPimpl> lrcPimpl_;
......
......@@ -39,6 +39,8 @@ class NewAccountModelPimpl;
namespace api
{
class Lrc;
class BehaviorController;
namespace account { struct Info; }
......@@ -51,7 +53,8 @@ class LIB_EXPORT NewAccountModel : public QObject {
public:
using AccountInfoMap = std::map<std::string, account::Info>;
NewAccountModel(Database& database,
NewAccountModel(Lrc& lrc,
Database& database,
const CallbacksHandler& callbackHandler,
const api::BehaviorController& behaviorController);
......
......@@ -20,6 +20,8 @@
#include "api/profile.h"
#include "api/datatransfer.h"
#include <datatransfer_interface.h>
namespace lrc
{
......@@ -181,7 +183,7 @@ getHistory(Database& db, api::conversation::Info& conversation)
{{":conversation_id", conversation.uid}});
if (interactionsResult.nbrOfCols == 6) {
auto payloads = interactionsResult.payloads;
for (auto i = 0; i < payloads.size(); i += 6) {
for (decltype(payloads.size()) i = 0; i < payloads.size(); i += 6) {
auto msg = api::interaction::Info({payloads[i + 1], payloads[i + 2],
std::stoi(payloads[i + 3]),
api::interaction::to_type(payloads[i + 4]),
......@@ -214,21 +216,30 @@ int
addDataTransferToConversation(Database& db,
const std::string& accountProfileId,
const std::string& conversationId,
const DataTransferInfo& infoFromDaemon)
const api::datatransfer::Info& infoFromDaemon)
{
auto peerProfileId = getProfileId(db, infoFromDaemon.peer.toStdString());
auto authorId = (infoFromDaemon.isOutgoing) ? peerProfileId : peerProfileId;
return db.insertInto("interactions",
{{":account_id", "account_id"}, {":author_id", "author_id"},
{":conversation_id", "conversation_id"}, {":timestamp", "timestamp"},
{":body", "body"}, {":type", "type"},
{":status", "status"}},
{{":account_id", accountProfileId}, {":author_id", authorId},
{":conversation_id", conversationId},
{":timestamp", std::to_string(std::time(nullptr))},
{":body", infoFromDaemon.displayName.toStdString()}, {":type", (infoFromDaemon.isOutgoing)?"OUTGOING_DATA_TRANSFER":"INCOMING_DATA_TRANSFER"},
{":status", "TRANSFER_CREATED"}});
auto peerProfileId = getProfileId(db, infoFromDaemon.peerUri);
auto authorId = peerProfileId;
return db.insertInto("interactions", {
{":account_id", "account_id"},
{":author_id", "author_id"},
{":conversation_id", "conversation_id"},
{":timestamp", "timestamp"},
{":body", "body"},
{":type", "type"},
{":status", "status"}
}, {
{":account_id", accountProfileId},
{":author_id", authorId},
{":conversation_id", conversationId},
{":timestamp", std::to_string(std::time(nullptr))},
{":body", infoFromDaemon.displayName},
{":type", infoFromDaemon.isOutgoing ?
"OUTGOING_DATA_TRANSFER" :
"INCOMING_DATA_TRANSFER"},
{":status", "TRANSFER_CREATED"}
});
}
int
......@@ -296,6 +307,21 @@ void updateInteractionStatus(Database& db, unsigned int id,
"id=:id", {{":id", std::to_string(id)}});
}
std::string
conversationIdFromInteractionId(Database& db, unsigned int interactionId)
{
auto result = db.select("conversation_id",
"interactions",
"id=:interaction_id",
{{":interaction_id", std::to_string(interactionId)}});
if (result.nbrOfCols == 1) {
auto payloads = result.payloads;
return payloads[0];
}
return {};
}
void clearHistory(Database& db,
const std::string& conversationId)
{
......
......@@ -29,6 +29,10 @@
namespace lrc
{
namespace api { namespace datatransfer {
struct Info;
}}
namespace authority
{
......@@ -232,7 +236,10 @@ int countUnreadFromInteractions(Database& db, const std::string& conversationId)
int addDataTransferToConversation(Database& db,
const std::string& accountProfileId,
const std::string& conversationId,
const DataTransferInfo& infoFromDaemon);
const api::datatransfer::Info& infoFromDaemon);
std::string conversationIdFromInteractionId(Database& db, unsigned int interactionId);
} // namespace database
} // namespace authority
......
......@@ -22,7 +22,7 @@
#include "api/account.h"
#include "api/lrc.h"
#include "api/newaccountmodel.h"
#include "api/datatransfer.h"
#include "api/datatransfermodel.h"
// Lrc
#include "account.h"
......@@ -218,8 +218,9 @@ CallbacksHandler::slotRegistrationStateChanged(const QString& accountId,
unsigned detail_code,
const QString& detail_str)
{
(void) detail_code;
(void) detail_str;
emit accountStatusChanged(accountId.toStdString(), lrc::api::account::to_status(registration_state.toStdString()));
}
void
......@@ -286,28 +287,35 @@ CallbacksHandler::slotDataTransferEvent(qulonglong dringId, uint codeStatus)
{
auto event = DRing::DataTransferEventCode(codeStatus);
api::datatransfer::Info info;
parent.getDataTransferModel().transferInfo(dringId, info);
// WARNING: info.status could be INVALID in case of async signaling
// So listeners must only take account of dringId in such case.
// Is useful for "termination" status like unjoinable_peer.
switch (event) {
case DRing::DataTransferEventCode::created:
emit incomingTransfer(static_cast<long long>(dringId));
emit transferStatusCreated(static_cast<long long>(dringId), info);
break;
case DRing::DataTransferEventCode::closed_by_host:
case DRing::DataTransferEventCode::closed_by_peer:
emit transferStatusCanceled(static_cast<long long>(dringId));
emit transferStatusCanceled(static_cast<long long>(dringId), info);
break;
case DRing::DataTransferEventCode::wait_peer_acceptance:
case DRing::DataTransferEventCode::wait_host_acceptance:
emit transferStatusAwaiting(static_cast<long long>(dringId));
emit transferStatusAwaiting(static_cast<long long>(dringId), info);
break;
case DRing::DataTransferEventCode::ongoing:
emit transferStatusOngoing(static_cast<long long>(dringId));
emit transferStatusOngoing(static_cast<long long>(dringId), info);
break;
case DRing::DataTransferEventCode::finished:
emit transferStatusFinished(static_cast<long long>(dringId));
emit transferStatusFinished(static_cast<long long>(dringId), info);
break;
case DRing::DataTransferEventCode::invalid_pathname:
case DRing::DataTransferEventCode::unjoinable_peer:
case DRing::DataTransferEventCode::unsupported:
emit transferStatusError(static_cast<long long>(dringId));
emit transferStatusError(static_cast<long long>(dringId), info);
break;
}
}
......
......@@ -27,6 +27,7 @@
// Lrc
#include "typedefs.h"
#include "namedirectory.h"
#include "api/datatransfer.h"
namespace lrc
{
......@@ -160,13 +161,12 @@ Q_SIGNALS:
const uint64_t id,
const std::string& to, int status);
void incomingTransfer(long long dringId);
//~ void transferStatusChanged(const long long dringId, uint codeStatus);
void transferStatusCanceled(long long dringId);
void transferStatusAwaiting(long long dringId);
void transferStatusOngoing(long long dringId);
void transferStatusFinished(long long dringId);
void transferStatusError(long long dringId);
void transferStatusCreated(long long dringId, api::datatransfer::Info info);
void transferStatusCanceled(long long dringId, api::datatransfer::Info info);
void transferStatusAwaiting(long long dringId, api::datatransfer::Info info);
void transferStatusOngoing(long long dringId, api::datatransfer::Info info);
void transferStatusFinished(long long dringId, api::datatransfer::Info info);
void transferStatusError(long long dringId, api::datatransfer::Info info);
private Q_SLOTS:
/**
......
......@@ -136,11 +136,6 @@ public Q_SLOTS:
void slotNewAccountMessage(std::string& accountId,
std::string& from,
std::map<std::string,std::string> payloads);
/**
* Listen from callbacksHandler for new account file transfer and add pending contact if not present
* @param dringId Id of transfer from daemon. Used to retrieve transfer informations.
*/
void slotNewAccountTransfer(long long dringId);
};
using namespace authority;
......@@ -368,9 +363,6 @@ ContactModelPimpl::ContactModelPimpl(const ContactModel& linked,
this, &ContactModelPimpl::slotIncomingCall);
connect(&callbacksHandler, &lrc::CallbacksHandler::newAccountMessage,
this, &ContactModelPimpl::slotNewAccountMessage);
connect(&callbacksHandler, &lrc::CallbacksHandler::incomingTransfer,
this, &ContactModelPimpl::slotNewAccountTransfer);
}
ContactModelPimpl::~ContactModelPimpl()
......@@ -596,30 +588,6 @@ ContactModelPimpl::slotNewAccountMessage(std::string& accountId,
emit linked.newAccountMessage(accountId, from, payloads);
}
void
ContactModelPimpl::slotNewAccountTransfer(long long dringId)
{
DataTransferInfo infoFromDaemon = ConfigurationManager::instance().dataTransferInfo(dringId);
auto accountId = infoFromDaemon.accountId.toStdString();
auto peerId = infoFromDaemon.peer.toStdString(); // TODO valeur à checker
if (accountId != linked.owner.id) return;
auto* account = AccountModel::instance().getById(linked.owner.id.c_str());
if (not account) {
qDebug() << "ContactModel::slotNewAccountTransfer(), nullptr";
return;
}
if (contacts.find(peerId) == contacts.end()) {
// Contact not found, load profile from database.
// The conversation model will create an entry and link the incomingCall.
auto* cm = PhoneDirectoryModel::instance().getNumber(infoFromDaemon.peer, account);
addToContacts(cm, profile::Type::PENDING);
}
emit linked.newAccountTransfer(dringId, infoFromDaemon);
}
} // namespace lrc
#include "api/moc_contactmodel.cpp"
......
......@@ -19,14 +19,19 @@
***************************************************************************/
#include "api/conversationmodel.h"
//Qt
#include <QtCore/QTimer>
// daemon
#include <account_const.h>
#include <datatransfer_interface.h>
// std
#include <regex>
#include <algorithm>
// LRC
#include "api/lrc.h"
#include "api/behaviorcontroller.h"
#include "api/contactmodel.h"
#include "api/newcallmodel.h"
......@@ -58,6 +63,7 @@ class ConversationModelPimpl : public QObject
Q_OBJECT
public:
ConversationModelPimpl(const ConversationModel& linked,
Lrc& lrc,
Database& db,
const CallbacksHandler& callbacksHandler,
const BehaviorController& behaviorController);
......@@ -132,12 +138,21 @@ public:
*/
int getNumberOfUnreadMessagesFor(const std::string& uid);
/**
* Handle data transfer progression
*/
void updateTransfer(QTimer* timer, const std::string& conversation, int conversationIdx,
int interactionId);
bool usefulDataFromDataTransfer(long long dringId, const datatransfer::Info& info,
int& interactionId, std::string& convId);
const ConversationModel& linked;
Lrc& lrc;
Database& db;
const CallbacksHandler& callbacksHandler;
const std::string accountProfileId;
const BehaviorController& behaviorController;
DataTransferModel dataTransferModel;
ConversationModel::ConversationQueue conversations; ///< non-filtered conversations
ConversationModel::ConversationQueue filteredConversations;
......@@ -214,25 +229,21 @@ public Q_SLOTS:
*/
void slotConferenceRemoved(const std::string& confId);
void slotIncomingTransfer(long long dringId, const DataTransferInfo& transferInfo);
//~ void slotTransferStatusChanged(long long dringId, uint codeStatus);
void slotCancelTransfer(long long dringId);
void slotTransferStatusAwaiting(long long dringId);
void slotTransferStatusOngoing(long long dringId);
void slotTransferStatusFinished(long long dringId);
void slotTransferStatusError(long long dringId);
void slotTransferStatusCreated(long long dringId, api::datatransfer::Info info);
void slotTransferStatusCanceled(long long dringId, api::datatransfer::Info info);
void slotTransferStatusAwaiting(long long dringId, api::datatransfer::Info info);
void slotTransferStatusOngoing(long long dringId, api::datatransfer::Info info);
void slotTransferStatusFinished(long long dringId, api::datatransfer::Info info);
void slotTransferStatusError(long long dringId, api::datatransfer::Info info);
};
ConversationModel::ConversationModel(const account::Info& owner,
Lrc& lrc,
Database& db,
const CallbacksHandler& callbacksHandler,
const BehaviorController& behaviorController)
: QObject()
, pimpl_(std::make_unique<ConversationModelPimpl>(*this, db, callbacksHandler, behaviorController))
, pimpl_(std::make_unique<ConversationModelPimpl>(*this, lrc, db, callbacksHandler, behaviorController))
, owner(owner)
{
......@@ -657,16 +668,17 @@ ConversationModel::setInteractionRead(const std::string& convId, const uint64_t&
}
ConversationModelPimpl::ConversationModelPimpl(const ConversationModel& linked,
Lrc& lrc,
Database& db,
const CallbacksHandler& callbacksHandler,
const BehaviorController& behaviorController)
: linked(linked)
, lrc {lrc}
, db(db)
, callbacksHandler(callbacksHandler)
, typeFilter(profile::Type::INVALID)
, accountProfileId(database::getProfileId(db, linked.owner.profileInfo.uri))
, behaviorController(behaviorController)
, dataTransferModel(db, callbacksHandler)
{
initConversations();
......@@ -716,14 +728,14 @@ ConversationModelPimpl::ConversationModelPimpl(const ConversationModel& linked,
&ConversationModelPimpl::slotConferenceRemoved);
// data transfer
connect(&*linked.owner.contactModel,
&ContactModel::newAccountTransfer,
connect(&callbacksHandler,
&CallbacksHandler::transferStatusCreated,
this,
&ConversationModelPimpl::slotIncomingTransfer);
&ConversationModelPimpl::slotTransferStatusCreated);
connect(&callbacksHandler,
&CallbacksHandler::transferStatusCanceled,
this,
&ConversationModelPimpl::slotCancelTransfer);
&ConversationModelPimpl::slotTransferStatusCanceled);
connect(&callbacksHandler,
&CallbacksHandler::transferStatusAwaiting,
this,
......@@ -1258,108 +1270,31 @@ ConversationModelPimpl::getNumberOfUnreadMessagesFor(const std::string& uid)
return database::countUnreadFromInteractions(db, uid);
}
void
ConversationModelPimpl::slotIncomingTransfer(long long dringId, const DataTransferInfo& transferInfo)
{
// check if transfer is for the current account
if (transferInfo.accountId.toStdString() != linked.owner.id)
return;
auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri);
auto contactProfileId = database::getProfileId(db, transferInfo.peer.toStdString());
// get the conversation if any
auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
if (conv.empty()) {
conv.emplace_back(database::beginConversationsBetween(
db, accountProfileId, contactProfileId,
QObject::tr("Invitation received").toStdString()
));
}
// add interaction to the db
auto interactionId = database::addDataTransferToConversation(db, accountProfileId, conv[0], transferInfo);
// add transfert to the transfer model
dataTransferModel.registerTransferId(dringId, interactionId);
// prepare interaction Info and emit signal for the client
auto conversationIdx = indexOf(conv[0]);
if (conversationIdx == -1) {
addConversationWith(conv[0], transferInfo.peer.toStdString());
emit linked.newConversation(conv[0]);
} else {
auto& interactions = conversations[conversationIdx].interactions;
auto it = interactions.find(interactionId);
if (it != interactions.end()) {
return;
}
auto interaction = interaction::Info {contactProfileId, transferInfo.displayName.toStdString(),
std::time(nullptr),
(transferInfo.isOutgoing)?interaction::Type::OUTGOING_DATA_TRANSFER:interaction::Type::INCOMING_DATA_TRANSFER,
interaction::Status::TRANSFER_CREATED};
auto it2 = conversations[conversationIdx].interactions.emplace(interactionId, interaction);
conversations[conversationIdx].lastMessageUid = interactionId;
dirtyConversations = true;
emit linked.newInteraction(conv[0], interactionId, interaction);
}
sortConversations();
emit linked.modelSorted();
}
void
ConversationModelPimpl::slotCancelTransfer(long long dringId)
ConversationModel::sendFile(const std::string& convUid,
const std::string& path,
const std::string& filename)
{
// no auto [jn] facto le code
DataTransferInfo infoFromDaemon = ConfigurationManager::instance().dataTransferInfo(dringId);
auto accountProfileId = database::getProfileId(db, linked.owner.profileInfo.uri);
auto contactProfileId = database::getProfileId(db, infoFromDaemon.peer.toStdString());
// get the conversation if any
auto conv = database::getConversationsBetween(db, accountProfileId, contactProfileId);
if (conv.empty())
auto conversationIdx = pimpl_->indexOf(convUid);
if (conversationIdx == -1)
return;
// get interaction id from data transfer model
auto interactionId = dataTransferModel.getInteractionIdFromDringId(dringId);
// update information in the db
database::updateInteractionStatus(db, interactionId, interaction::Status::TRANSFER_CANCELED);
// prepare interaction Info and emit signal for the client
auto conversationIdx = indexOf(conv[0]);
if (conversationIdx != -1) {
auto& interactions = conversations[conversationIdx].interactions;
auto it = interactions.find(interactionId);
if (it != interactions.end()) {
emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
}
}
}
const auto& peerUri = pimpl_->conversations[conversationIdx].participants.front();
if (peerUri.empty())
return;
void
ConversationModel::sendFile(const std::string& uid, const std::string& path, const std::string& filename)
{
auto conversationIdx = pimpl_->indexOf(uid);
if (conversationIdx != -1) {
auto& peerUri = pimpl_->conversations[conversationIdx].participants.front();
if (not peerUri.empty()) {
pimpl_->sendContactRequest(peerUri);
pimpl_->dataTransferModel.sendFile(owner.id.c_str(), peerUri.c_str(), path.c_str(), filename.c_str());
}
}
pimpl_->sendContactRequest(peerUri);
pimpl_->lrc.getDataTransferModel().sendFile(owner.id.c_str(),
peerUri.c_str(),
path.c_str(),
filename.c_str());
}
void