Skip to content
Snippets Groups Projects
Commit 64cce564 authored by Nicolas Jager's avatar Nicolas Jager Committed by Anthony Léonard
Browse files

Implementation of datatransfer


add the data transfer functionality to LRC

this patch does not fullfil all the models specifications
and is not fully "concern separated" due to design flaws
(much of the datatransfer is delegated to conversation model).
That will be corrected further in time.

Change-Id: I9bc3d3f8fc544fe97ef43805bad54a5779797234
Reviewed-by: default avatarAnthony Léonard <anthony.leonard@savoirfairelinux.com>
parent 6b874a99
No related branches found
No related tags found
No related merge requests found
...@@ -148,9 +148,11 @@ public: ...@@ -148,9 +148,11 @@ public:
*/ */
void deleteObsoleteHistory(int date); void deleteObsoleteHistory(int date);
void sendFile(const std::string& uid, const std::string& path, const std::string& filename); void sendFile(const std::string& convUid, const std::string& path, const std::string& filename);
void acceptFile(const std::string& uid, uint64_t interactionId); void acceptTransfer(const std::string& convUid, uint64_t interactionId, const std::string& path);
void cancelTransfer(const std::string& convUid, uint64_t interactionId);
Q_SIGNALS: Q_SIGNALS:
/** /**
......
...@@ -17,6 +17,9 @@ ...@@ -17,6 +17,9 @@
***************************************************************************/ ***************************************************************************/
#pragma once #pragma once
// std
#include <ctime>
// LRC // LRC
#include "typedefs.h" #include "typedefs.h"
...@@ -33,11 +36,62 @@ enum class Status { ...@@ -33,11 +36,62 @@ enum class Status {
unjoinable_peer, // error: (outgoing only) peer connection failed unjoinable_peer, // error: (outgoing only) peer connection failed
invalid_pathname, // error: (file transfer only) given file is not a valid invalid_pathname, // error: (file transfer only) given file is not a valid
unsupported, // error: unable to do the transfer (generic error) unsupported, // error: unable to do the transfer (generic error)
INVALID
}; };
static inline const std::string
to_string(const Status& status)
{
switch(status) {
case Status::on_connection:
return "on_connection";
case Status::on_progress:
return "on_progress";
case Status::success:
return "success";
case Status::stop_by_peer:
return "stop_by_peer";
case Status::stop_by_host:
return "stop_by_host";
case Status::unjoinable_peer:
return "unjoinable_peer";
case Status::invalid_pathname:
return "invalid_pathname";
case Status::unsupported:
return "unsupported";
case Status::INVALID:
default:
return "INVALID";
}
}
static inline Status
to_status(const std::string& status)
{
if (status == "on_connection")
return datatransfer::Status::on_connection;
else if (status == "on_progress")
return datatransfer::Status::on_progress;
else if (status == "success")
return datatransfer::Status::success;
else if (status == "stop_by_peer")
return datatransfer::Status::stop_by_peer;
else if (status == "stop_by_host")
return datatransfer::Status::stop_by_host;
else if (status == "unjoinable_peer")
return datatransfer::Status::unjoinable_peer;
else if (status == "invalid_pathname")
return datatransfer::Status::invalid_pathname;
else if (status == "unsupported")
return datatransfer::Status::unsupported;
else
return datatransfer::Status::INVALID;
}
struct Info struct Info
{ {
std::string uid; ///< long-term and unique identifier (used for historic) const std::string uid; ///< long-term and unique identifier (used for historic)
Status status; Status status;
bool isOutgoing; bool isOutgoing;
std::size_t totalSize; std::size_t totalSize;
...@@ -46,6 +100,7 @@ struct Info ...@@ -46,6 +100,7 @@ struct Info
std::string displayName; std::string displayName;
std::string accountId; std::string accountId;
std::string peerUri; std::string peerUri;
std::time_t timestamp = 0;
}; };
} // namespace lrc::api::datatransfer } // namespace lrc::api::datatransfer
......
...@@ -41,6 +41,10 @@ namespace api { ...@@ -41,6 +41,10 @@ namespace api {
class BehaviorController; class BehaviorController;
namespace datatransfer {
class Info;
} // namespace datatransfer
/** /**
* @brief Class that manages data transfer. * @brief Class that manages data transfer.
*/ */
...@@ -52,32 +56,26 @@ public: ...@@ -52,32 +56,26 @@ public:
const CallbacksHandler& callbacksHandler); const CallbacksHandler& callbacksHandler);
~DataTransferModel(); ~DataTransferModel();
std::vector<std::string> transferIdList() const; void sendFile(const std::string& account_id, const std::string& peer_uri,
std::string 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); datatransfer::Info transferInfo(const std::string& uid);
std::streamsize bytesProgress(const std::string& id); std::streamsize bytesProgress(int interactionId);
void accept(int interactionId, const std::string& file_path, std::size_t offset);
void acceptFile(const std::string& id, const std::string& file_path, std::size_t offset); void cancel(int interactionId);
void cancel(const std::string& id); void registerTransferId(long long dringId, int interactionId);
int getInteractionIdFromDringId(long long dringId);
Q_SIGNALS: Q_SIGNALS:
/** /**
* Connect this signal to know when a data transfer is incoming. * Connect this signal to know when a data transfer is incoming.
* \note the unique identification is generated by the libring and its unicity scope is limited
* to the libring process life.
*
* @param transfer_id unique identification of incoming data transfer.
* @param display_name a free identification string given by sender.
* @oaram size total number of bytes of the transfer (including offset).
* @oaram offset offset of first given bytes for continued transfer.
*/ */
void incomingTransfer(const std::string& uid, const std::string& display_name, void incomingTransfer(api::datatransfer::Info dataTransferInfo);
const std::size_t size, const std::size_t offset);
/** /**
* Connect this signal to know when an existing data transfer has changed of status. * Connect this signal to know when an existing data transfer has changed of status.
......
...@@ -35,7 +35,9 @@ enum class Type { ...@@ -35,7 +35,9 @@ enum class Type {
INVALID, INVALID,
TEXT, TEXT,
CALL, CALL,
CONTACT CONTACT,
OUTGOING_DATA_TRANSFER,
INCOMING_DATA_TRANSFER
}; };
static inline const std::string static inline const std::string
...@@ -48,6 +50,10 @@ to_string(const Type& type) ...@@ -48,6 +50,10 @@ to_string(const Type& type)
return "CALL"; return "CALL";
case Type::CONTACT: case Type::CONTACT:
return "CONTACT"; return "CONTACT";
case Type::OUTGOING_DATA_TRANSFER:
return "OUTGOING_DATA_TRANSFER";
case Type::INCOMING_DATA_TRANSFER:
return "INCOMING_DATA_TRANSFER";
case Type::INVALID: case Type::INVALID:
default: default:
return "INVALID"; return "INVALID";
...@@ -63,6 +69,10 @@ to_type(const std::string& type) ...@@ -63,6 +69,10 @@ to_type(const std::string& type)
return interaction::Type::CALL; return interaction::Type::CALL;
else if (type == "CONTACT") else if (type == "CONTACT")
return interaction::Type::CONTACT; return interaction::Type::CONTACT;
else if (type == "OUTGOING_DATA_TRANSFER")
return interaction::Type::OUTGOING_DATA_TRANSFER;
else if (type == "INCOMING_DATA_TRANSFER")
return interaction::Type::INCOMING_DATA_TRANSFER;
else else
return interaction::Type::INVALID; return interaction::Type::INVALID;
} }
...@@ -75,7 +85,14 @@ enum class Status { ...@@ -75,7 +85,14 @@ enum class Status {
FAILED, FAILED,
SUCCEED, SUCCEED,
READ, READ,
UNREAD UNREAD,
TRANSFER_CREATED, /*[jn] mettre à jour les fonctions de conversion */
TRANSFER_ACCEPTED,
TRANSFER_CANCELED,
TRANSFER_ERROR,
TRANSFER_ONGOING,
TRANSFER_AWAITING,
TRANSFER_FINISHED
}; };
static inline const std::string static inline const std::string
...@@ -94,7 +111,20 @@ to_string(const Status& status) ...@@ -94,7 +111,20 @@ to_string(const Status& status)
return "READ"; return "READ";
case Status::UNREAD: case Status::UNREAD:
return "UNREAD"; return "UNREAD";
case Status::INVALID: case Status::TRANSFER_CREATED:
return "TRANSFER_CREATED";
case Status::TRANSFER_ACCEPTED:
return "TRANSFER_ACCEPTED";
case Status::TRANSFER_CANCELED:
return "TRANSFER_CANCELED";
case Status::TRANSFER_ERROR:
return "TRANSFER_ERROR";
case Status::TRANSFER_ONGOING:
return "TRANSFER_ONGOING";
case Status::TRANSFER_AWAITING:
return "TRANSFER_AWAITING";
case Status::TRANSFER_FINISHED:
return "TRANSFER_FINISHED";
default: default:
return "INVALID"; return "INVALID";
} }
...@@ -115,6 +145,20 @@ to_status(const std::string& status) ...@@ -115,6 +145,20 @@ to_status(const std::string& status)
return interaction::Status::READ; return interaction::Status::READ;
else if (status == "UNREAD") else if (status == "UNREAD")
return interaction::Status::UNREAD; return interaction::Status::UNREAD;
else if (status == "TRANSFER_CREATED")
return interaction::Status::TRANSFER_CREATED;
else if (status == "TRANSFER_ACCEPTED")
return interaction::Status::TRANSFER_ACCEPTED;
else if (status == "TRANSFER_CANCELED")
return interaction::Status::TRANSFER_CANCELED;
else if (status == "TRANSFER_ERROR")
return interaction::Status::TRANSFER_ERROR;
else if (status == "TRANSFER_ONGOING")
return interaction::Status::TRANSFER_ONGOING;
else if (status == "TRANSFER_AWAITING")
return interaction::Status::TRANSFER_AWAITING;
else if (status == "TRANSFER_FINISHED")
return interaction::Status::TRANSFER_FINISHED;
else else
return interaction::Status::INVALID; return interaction::Status::INVALID;
...@@ -130,8 +174,9 @@ struct Info ...@@ -130,8 +174,9 @@ struct Info
}; };
static inline bool isOutgoing(const Info& interaction) { static inline bool isOutgoing(const Info& interaction) {
return interaction.status != lrc::api::interaction::Status::READ return (interaction.status != lrc::api::interaction::Status::READ
&& interaction.status != lrc::api::interaction::Status::UNREAD; && interaction.status != lrc::api::interaction::Status::UNREAD)
|| interaction.type == lrc::api::interaction::Type::OUTGOING_DATA_TRANSFER;
} }
} // namespace interaction } // namespace interaction
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
***************************************************************************/ ***************************************************************************/
#include "databasehelper.h" #include "databasehelper.h"
#include "api/profile.h" #include "api/profile.h"
#include "api/datatransfer.h"
namespace lrc namespace lrc
{ {
...@@ -209,6 +210,27 @@ addMessageToConversation(Database& db, ...@@ -209,6 +210,27 @@ addMessageToConversation(Database& db,
{":status", to_string(msg.status)}}); {":status", to_string(msg.status)}});
} }
int
addDataTransferToConversation(Database& db,
const std::string& accountProfileId,
const std::string& conversationId,
const DataTransferInfo& 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"}});
}
int int
addOrUpdateMessage(Database& db, addOrUpdateMessage(Database& db,
const std::string& accountProfile, const std::string& accountProfile,
...@@ -267,7 +289,7 @@ std::string getInteractionIdByDaemonId(Database& db, const std::string& id) ...@@ -267,7 +289,7 @@ std::string getInteractionIdByDaemonId(Database& db, const std::string& id)
void updateInteractionStatus(Database& db, unsigned int id, void updateInteractionStatus(Database& db, unsigned int id,
api::interaction::Status& newStatus) api::interaction::Status newStatus)
{ {
db.update("interactions", "status=:status", db.update("interactions", "status=:status",
{{":status", api::interaction::to_string(newStatus)}}, {{":status", api::interaction::to_string(newStatus)}},
......
...@@ -177,7 +177,7 @@ std::string getInteractionIdByDaemonId(Database& db, const std::string& id); ...@@ -177,7 +177,7 @@ std::string getInteractionIdByDaemonId(Database& db, const std::string& id);
* @param newStatus * @param newStatus
*/ */
void updateInteractionStatus(Database& db, unsigned int id, void updateInteractionStatus(Database& db, unsigned int id,
api::interaction::Status& newStatus); api::interaction::Status newStatus);
/** /**
* Clear history but not the conversation started interaction * Clear history but not the conversation started interaction
...@@ -229,6 +229,10 @@ void addContact(Database& db, const std::string& accountUri, const std::string& ...@@ -229,6 +229,10 @@ void addContact(Database& db, const std::string& accountUri, const std::string&
*/ */
int countUnreadFromInteractions(Database& db, const std::string& conversationId); int countUnreadFromInteractions(Database& db, const std::string& conversationId);
int addDataTransferToConversation(Database& db,
const std::string& accountProfileId,
const std::string& conversationId,
const DataTransferInfo& infoFromDaemon);
} // namespace database } // namespace database
} // namespace authority } // namespace authority
......
...@@ -282,9 +282,34 @@ CallbacksHandler::slotAccountMessageStatusChanged(const QString& accountId, ...@@ -282,9 +282,34 @@ CallbacksHandler::slotAccountMessageStatusChanged(const QString& accountId,
} }
void void
CallbacksHandler::slotDataTransferEvent(qulonglong dring_id, uint code) CallbacksHandler::slotDataTransferEvent(qulonglong dringId, uint codeStatus)
{ {
emit incomingTransfer(-1, -1); auto event = DRing::DataTransferEventCode(codeStatus);
switch (event) {
case DRing::DataTransferEventCode::created:
emit incomingTransfer(static_cast<long long>(dringId));
break;
case DRing::DataTransferEventCode::closed_by_host:
case DRing::DataTransferEventCode::closed_by_peer:
emit transferStatusCanceled(static_cast<long long>(dringId));
break;
case DRing::DataTransferEventCode::wait_peer_acceptance:
case DRing::DataTransferEventCode::wait_host_acceptance:
emit transferStatusAwaiting(static_cast<long long>(dringId));
break;
case DRing::DataTransferEventCode::ongoing:
emit transferStatusOngoing(static_cast<long long>(dringId));
break;
case DRing::DataTransferEventCode::finished:
emit transferStatusFinished(static_cast<long long>(dringId));
break;
case DRing::DataTransferEventCode::invalid_pathname:
case DRing::DataTransferEventCode::unjoinable_peer:
case DRing::DataTransferEventCode::unsupported:
emit transferStatusError(static_cast<long long>(dringId));
break;
}
} }
} // namespace lrc } // namespace lrc
...@@ -160,7 +160,13 @@ Q_SIGNALS: ...@@ -160,7 +160,13 @@ Q_SIGNALS:
const uint64_t id, const uint64_t id,
const std::string& to, int status); const std::string& to, int status);
void incomingTransfer(long long dring_id, uint code); 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);
private Q_SLOTS: private Q_SLOTS:
/** /**
......
...@@ -214,13 +214,16 @@ public Q_SLOTS: ...@@ -214,13 +214,16 @@ public Q_SLOTS:
*/ */
void slotConferenceRemoved(const std::string& confId); void slotConferenceRemoved(const std::string& confId);
void slotIncomingTransfer(const std::string& uid, void slotIncomingTransfer(long long dringId);
const std::string& display_name,
const std::size_t size,
const std::size_t offset);
void slotTransferStatusChanged(const std::string& uid, //~ void slotTransferStatusChanged(long long dringId, uint codeStatus);
datatransfer::Status status);
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);
}; };
...@@ -712,16 +715,31 @@ ConversationModelPimpl::ConversationModelPimpl(const ConversationModel& linked, ...@@ -712,16 +715,31 @@ ConversationModelPimpl::ConversationModelPimpl(const ConversationModel& linked,
this, this,
&ConversationModelPimpl::slotConferenceRemoved); &ConversationModelPimpl::slotConferenceRemoved);
connect(&dataTransferModel, // data transfer
&DataTransferModel::incomingTransfer, connect(&callbacksHandler,
&CallbacksHandler::incomingTransfer,
this, this,
&ConversationModelPimpl::slotIncomingTransfer); &ConversationModelPimpl::slotIncomingTransfer);
connect(&callbacksHandler,
connect(&dataTransferModel, &CallbacksHandler::transferStatusCanceled,
&DataTransferModel::transferStatusChanged,
this, this,
&ConversationModelPimpl::slotTransferStatusChanged); &ConversationModelPimpl::slotCancelTransfer);
connect(&callbacksHandler,
&CallbacksHandler::transferStatusAwaiting,
this,
&ConversationModelPimpl::slotTransferStatusAwaiting);
connect(&callbacksHandler,
&CallbacksHandler::transferStatusOngoing,
this,
&ConversationModelPimpl::slotTransferStatusOngoing);
connect(&callbacksHandler,
&CallbacksHandler::transferStatusFinished,
this,
&ConversationModelPimpl::slotTransferStatusFinished);
connect(&callbacksHandler,
&CallbacksHandler::transferStatusError,
this,
&ConversationModelPimpl::slotTransferStatusError);
} }
ConversationModelPimpl::~ConversationModelPimpl() ConversationModelPimpl::~ConversationModelPimpl()
...@@ -948,6 +966,14 @@ ConversationModelPimpl::addConversationWith(const std::string& convId, ...@@ -948,6 +966,14 @@ ConversationModelPimpl::addConversationWith(const std::string& convId,
} }
slotUpdateInteractionStatus(linked.owner.id, std::stoull(id), slotUpdateInteractionStatus(linked.owner.id, std::stoull(id),
contactUri, status); contactUri, status);
} else if (interaction.second.status == interaction::Status::TRANSFER_CREATED
|| interaction.second.status == interaction::Status::TRANSFER_AWAITING
|| interaction.second.status == interaction::Status::TRANSFER_ONGOING
|| interaction.second.status == interaction::Status::TRANSFER_ACCEPTED) {
// If a datatransfer was left in a non-terminal status in DB, we switch this status to ERROR
// TODO : Improve for DBus clients as daemon and transfer may still be ongoing
database::updateInteractionStatus(db, interaction.first, interaction::Status::TRANSFER_ERROR);
interaction.second.status = interaction::Status::TRANSFER_ERROR;
} }
} }
...@@ -1226,18 +1252,80 @@ ConversationModelPimpl::getNumberOfUnreadMessagesFor(const std::string& uid) ...@@ -1226,18 +1252,80 @@ ConversationModelPimpl::getNumberOfUnreadMessagesFor(const std::string& uid)
} }
void void
ConversationModelPimpl::slotIncomingTransfer(const std::string& uid, ConversationModelPimpl::slotIncomingTransfer(long long dringId)
const std::string& display_name,
const std::size_t size,
const std::size_t offset)
{ {
emit linked.newInteraction("", -1, {}); // no auto
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())
return;
// add interaction to the db
auto interactionId = database::addDataTransferToConversation(db, accountProfileId, conv[0], infoFromDaemon);
// 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) {
auto& interactions = conversations[conversationIdx].interactions;
auto it = interactions.find(interactionId);
if (it != interactions.end()) {
return;
}
auto interaction = interaction::Info {contactProfileId, infoFromDaemon.displayName.toStdString(),
std::time(nullptr),
(infoFromDaemon.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 void
ConversationModelPimpl::slotTransferStatusChanged(const std::string& uid, datatransfer::Status status) ConversationModelPimpl::slotCancelTransfer(long long dringId)
{ {
emit linked.interactionStatusUpdated("", -1, {}); // 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())
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);
}
}
} }
void void
...@@ -1246,19 +1334,188 @@ ConversationModel::sendFile(const std::string& uid, const std::string& path, con ...@@ -1246,19 +1334,188 @@ ConversationModel::sendFile(const std::string& uid, const std::string& path, con
auto conversationIdx = pimpl_->indexOf(uid); auto conversationIdx = pimpl_->indexOf(uid);
if (conversationIdx != -1) { if (conversationIdx != -1) {
auto& peerUri = pimpl_->conversations[conversationIdx].participants.front(); auto& peerUri = pimpl_->conversations[conversationIdx].participants.front();
if (not peerUri.empty()) if (not peerUri.empty()) {
pimpl_->dataTransferModel.sendFile(owner.id.c_str(), peerUri.c_str(), path.c_str(), filename.c_str()); pimpl_->dataTransferModel.sendFile(owner.id.c_str(), peerUri.c_str(), path.c_str(), filename.c_str());
} }
} }
}
void void
ConversationModel::acceptFile(const std::string& uid, uint64_t interactionId) ConversationModel::acceptTransfer(const std::string& convUid, uint64_t interactionId, const std::string& path)
{ {
auto conversationIdx = pimpl_->indexOf(uid); pimpl_->dataTransferModel.accept(interactionId, path, 0);
database::updateInteractionStatus(pimpl_->db, interactionId, interaction::Status::TRANSFER_ACCEPTED);
// prepare interaction Info and emit signal for the client
auto conversationIdx = pimpl_->indexOf(convUid);
if (conversationIdx != -1) {
auto& interactions = pimpl_->conversations[conversationIdx].interactions;
auto it = interactions.find(interactionId);
if (it != interactions.end()) {
it->second.status = interaction::Status::TRANSFER_ACCEPTED;
pimpl_->dirtyConversations = true;
emit interactionStatusUpdated(convUid, interactionId, it->second);
}
}
}
void
ConversationModel::cancelTransfer(const std::string& convUid, uint64_t interactionId)
{
// For this action, we change interaction status before effective canceling as daemon will
// emit Finished event code immediatly (before leaving this method) in non-DBus mode.
auto conversationIdx = pimpl_->indexOf(convUid);
if (conversationIdx != -1) {
auto& interactions = pimpl_->conversations[conversationIdx].interactions;
auto it = interactions.find(interactionId);
if (it != interactions.end()) {
it->second.status = interaction::Status::TRANSFER_CANCELED;
// update information in the db
database::updateInteractionStatus(pimpl_->db, interactionId, interaction::Status::TRANSFER_CANCELED);
// Forward cancel action to daemon
pimpl_->dataTransferModel.cancel(interactionId);
pimpl_->dirtyConversations = true;
emit interactionStatusUpdated(convUid, interactionId, it->second);
}
}
}
void
ConversationModelPimpl::slotTransferStatusAwaiting(long long dringId)
{
// 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())
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_AWAITING);
// 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()) {
it->second.status = interaction::Status::TRANSFER_AWAITING;
dirtyConversations = true;
emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
}
}
}
void
ConversationModelPimpl::slotTransferStatusOngoing(long long dringId)
{
// 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())
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_ONGOING);
// prepare interaction Info and emit signal for the client
auto conversationIdx = indexOf(conv[0]);
if (conversationIdx != -1) { if (conversationIdx != -1) {
auto& dataTransferUid = pimpl_->dataTransferModel.transferIdList()[interactionId]; auto& interactions = conversations[conversationIdx].interactions;
if (not dataTransferUid.empty()) auto it = interactions.find(interactionId);
pimpl_->dataTransferModel.acceptFile(dataTransferUid, "~", 0); if (it != interactions.end()) {
it->second.status = interaction::Status::TRANSFER_ONGOING;
dirtyConversations = true;
emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
}
}
}
void
ConversationModelPimpl::slotTransferStatusFinished(long long dringId)
{
// 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())
return;
// get interaction id from data transfer model
auto interactionId = dataTransferModel.getInteractionIdFromDringId(dringId);
// 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()) {
// We need to check if current status is ONGOING as CANCELED must not be transformed into FINISHED
if (it->second.status == interaction::Status::TRANSFER_ONGOING) {
// update information in the db
database::updateInteractionStatus(db, interactionId, interaction::Status::TRANSFER_FINISHED);
it->second.status = interaction::Status::TRANSFER_FINISHED;
dirtyConversations = true;
emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
}
}
}
}
void
ConversationModelPimpl::slotTransferStatusError(long long dringId)
{
// 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())
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_ERROR);
// 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()) {
dirtyConversations = true;
emit linked.interactionStatusUpdated(conv[0], interactionId, it->second);
}
} }
} }
......
...@@ -65,16 +65,13 @@ public: ...@@ -65,16 +65,13 @@ public:
Database& database, Database& database,
const CallbacksHandler& callbacksHandler); const CallbacksHandler& callbacksHandler);
std::vector<std::string> transferIdList() const;
DataTransferModel& upLink; DataTransferModel& upLink;
std::map<DRing::DataTransferId, std::string> dring2lrcIdMap; std::map<long long, int> dring2lrcIdMap;
std::map<std::string, DRing::DataTransferId> lrc2dringIdMap; // stricly the reverse map of dring2lrcIdMap std::map<int, long long> lrc2dringIdMap; // stricly the reverse map of dring2lrcIdMap
Database& database; Database& database;
const CallbacksHandler& callbacksHandler; const CallbacksHandler& callbacksHandler;
std::string registerTransferId(DRing::DataTransferId id);
public Q_SLOTS:
void slotDataTransferEvent(long long dring_id, uint code);
}; };
DataTransferModel::Impl::Impl(DataTransferModel& up_link, DataTransferModel::Impl::Impl(DataTransferModel& up_link,
...@@ -84,41 +81,18 @@ DataTransferModel::Impl::Impl(DataTransferModel& up_link, ...@@ -84,41 +81,18 @@ DataTransferModel::Impl::Impl(DataTransferModel& up_link,
, callbacksHandler {callbacksHandler} , callbacksHandler {callbacksHandler}
, database {database} , database {database}
, upLink {up_link} , upLink {up_link}
{ {}
connect(&callbacksHandler, &CallbacksHandler::incomingTransfer,
this, &DataTransferModel::Impl::slotDataTransferEvent);
}
std::string
DataTransferModel::Impl::registerTransferId(DRing::DataTransferId dring_id)
{
const auto& iter = dring2lrcIdMap.find(dring_id);
if (iter != std::cend(dring2lrcIdMap))
return iter->second;
while (true) {
auto res = dring2lrcIdMap.emplace(dring_id, QUuid::createUuid().toString().toStdString());
if (res.second) {
lrc2dringIdMap.emplace(res.first->second, dring_id);
return res.first->second;
}
}
}
void void
DataTransferModel::Impl::slotDataTransferEvent(long long dring_id, uint code) DataTransferModel::registerTransferId(long long dringId, int interactionId)
{ {
auto event = DRing::DataTransferEventCode(code);
if (event == DRing::DataTransferEventCode::created) {
auto info = static_cast<DataTransferInfo>(ConfigurationManager::instance().dataTransferInfo(dring_id));
if (!info.isOutgoing) {
emit upLink.incomingTransfer("", "", 0, 0);
return;
}
}
emit upLink.transferStatusChanged("", convertDataTransferEvent(event)); pimpl_->dring2lrcIdMap.emplace(dringId, interactionId);
pimpl_->lrc2dringIdMap.emplace(interactionId, dringId);
} }
DataTransferModel::DataTransferModel(Database& database, DataTransferModel::DataTransferModel(Database& database,
const CallbacksHandler& callbacksHandler) const CallbacksHandler& callbacksHandler)
: QObject() : QObject()
...@@ -128,21 +102,21 @@ DataTransferModel::DataTransferModel(Database& database, ...@@ -128,21 +102,21 @@ DataTransferModel::DataTransferModel(Database& database,
DataTransferModel::~DataTransferModel() = default; DataTransferModel::~DataTransferModel() = default;
std::vector<std::string> std::vector<std::string>
DataTransferModel::transferIdList() const DataTransferModel::Impl::transferIdList() const
{ {
VectorULongLong dring_list = ConfigurationManager::instance().dataTransferList(); VectorULongLong dring_list = ConfigurationManager::instance().dataTransferList();
for (auto dring_id : dring_list) { //~ for (auto dring_id : dring_list) {
pimpl_->registerTransferId(dring_id); //~ pimpl_->registerTransferId(dring_id);
} //~ }
std::vector<std::string> result; std::vector<std::string> result;
result.reserve(dring_list.size()); //~ result.reserve(dring_list.size());
for (auto& item : pimpl_->lrc2dringIdMap) { //~ for (auto& item : pimpl_->lrc2dringIdMap) {
result.push_back(item.first); //~ result.push_back(item.first);
} //~ }
return result; return result;
} }
std::string void
DataTransferModel::sendFile(const std::string& account_id, const std::string& peer_uri, DataTransferModel::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)
{ {
...@@ -151,49 +125,36 @@ DataTransferModel::sendFile(const std::string& account_id, const std::string& pe ...@@ -151,49 +125,36 @@ DataTransferModel::sendFile(const std::string& account_id, const std::string& pe
QString::fromStdString(peer_uri), QString::fromStdString(peer_uri),
QString::fromStdString(file_path), QString::fromStdString(file_path),
QString::fromStdString(display_name))); QString::fromStdString(display_name)));
return pimpl_->registerTransferId(dring_id);
}
datatransfer::Info
DataTransferModel::transferInfo(const std::string& lrc_id)
{
auto dring_id = pimpl_->lrc2dringIdMap.at(lrc_id);
auto dring_info = static_cast<DataTransferInfo>(ConfigurationManager::instance().dataTransferInfo(dring_id));
datatransfer::Info lrc_info;
lrc_info.uid = lrc_id;
lrc_info.isOutgoing = dring_info.isOutgoing;
lrc_info.totalSize = dring_info.totalSize;
lrc_info.progress = dring_info.lastEvent;
lrc_info.path = dring_info.displayName.toStdString();
lrc_info.displayName = dring_info.displayName.toStdString();
lrc_info.status = convertDataTransferEvent(DRing::DataTransferEventCode(dring_info.lastEvent));
lrc_info.accountId = dring_info.accountId.toStdString();
lrc_info.peerUri = dring_info.peer.toStdString();
return lrc_info;
} }
std::streamsize std::streamsize
DataTransferModel::bytesProgress(const std::string& lrc_id) DataTransferModel::bytesProgress(int interactionId)
{ {
return ConfigurationManager::instance().dataTransferBytesProgress(pimpl_->lrc2dringIdMap.at(lrc_id)); return ConfigurationManager::instance().dataTransferBytesProgress(pimpl_->lrc2dringIdMap.at(interactionId));
} }
void void
DataTransferModel::acceptFile(const std::string& lrc_id, DataTransferModel::accept(int interactionId,
const std::string& file_path, const std::string& file_path,
std::size_t offset) std::size_t offset)
{ {
auto dring_id = pimpl_->lrc2dringIdMap.at(lrc_id); auto dring_id = pimpl_->lrc2dringIdMap.at(interactionId);
ConfigurationManager::instance().acceptFileTransfer(dring_id, QString::fromStdString(file_path), offset); ConfigurationManager::instance().acceptFileTransfer(dring_id, QString::fromStdString(file_path), offset);
} }
void void
DataTransferModel::cancel(const std::string& lrc_id) DataTransferModel::cancel(int interactionId)
{ {
auto dring_id = pimpl_->lrc2dringIdMap.at(lrc_id); auto dring_id = pimpl_->lrc2dringIdMap.at(interactionId);
ConfigurationManager::instance().cancelDataTransfer(dring_id); ConfigurationManager::instance().cancelDataTransfer(dring_id);
} }
int
DataTransferModel::getInteractionIdFromDringId(long long dringId)
{
return pimpl_->dring2lrcIdMap.at(dringId);
}
}} // namespace lrc::api }} // namespace lrc::api
#include "api/moc_datatransfermodel.cpp" #include "api/moc_datatransfermodel.cpp"
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment