diff --git a/src/api/conversationmodel.h b/src/api/conversationmodel.h index 82c0faa7ff1de5fdb60366045fa6e30103c587a8..a30a141bc4f38b2f4f997da318d96aca01fd6869 100644 --- a/src/api/conversationmodel.h +++ b/src/api/conversationmodel.h @@ -148,9 +148,11 @@ public: */ 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: /** diff --git a/src/api/datatransfer.h b/src/api/datatransfer.h index 1de9fe7fe7b2bb9532e9eaadc31b9efc1b3be25f..8e9209f2a464d5478fd7bf7c51883d01431dc4be 100644 --- a/src/api/datatransfer.h +++ b/src/api/datatransfer.h @@ -17,6 +17,9 @@ ***************************************************************************/ #pragma once +// std +#include <ctime> + // LRC #include "typedefs.h" @@ -33,11 +36,62 @@ enum class Status { unjoinable_peer, // error: (outgoing only) peer connection failed invalid_pathname, // error: (file transfer only) given file is not a valid 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 { - 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; bool isOutgoing; std::size_t totalSize; @@ -46,6 +100,7 @@ struct Info std::string displayName; std::string accountId; std::string peerUri; + std::time_t timestamp = 0; }; } // namespace lrc::api::datatransfer diff --git a/src/api/datatransfermodel.h b/src/api/datatransfermodel.h index de0edb858245e08f2629f87e7e373bc89f770d55..fc171a969dca5813d2d0613c56ea2339eae546d0 100644 --- a/src/api/datatransfermodel.h +++ b/src/api/datatransfermodel.h @@ -41,6 +41,10 @@ namespace api { class BehaviorController; +namespace datatransfer { +class Info; +} // namespace datatransfer + /** * @brief Class that manages data transfer. */ @@ -52,32 +56,26 @@ public: const CallbacksHandler& callbacksHandler); ~DataTransferModel(); - std::vector<std::string> transferIdList() const; - - std::string sendFile(const std::string& account_id, const std::string& peer_uri, + void sendFile(const std::string& account_id, const std::string& peer_uri, const std::string& file_path, const std::string& display_name); 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: /** * 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, - const std::size_t size, const std::size_t offset); + void incomingTransfer(api::datatransfer::Info dataTransferInfo); /** * Connect this signal to know when an existing data transfer has changed of status. diff --git a/src/api/interaction.h b/src/api/interaction.h index 71f50705ae78c19b34f6738f1562c290bda2eded..f0871b4c41e6fd39de7da363d2978466a4b85514 100644 --- a/src/api/interaction.h +++ b/src/api/interaction.h @@ -35,7 +35,9 @@ enum class Type { INVALID, TEXT, CALL, - CONTACT + CONTACT, + OUTGOING_DATA_TRANSFER, + INCOMING_DATA_TRANSFER }; static inline const std::string @@ -48,6 +50,10 @@ to_string(const Type& type) return "CALL"; case Type::CONTACT: return "CONTACT"; + case Type::OUTGOING_DATA_TRANSFER: + return "OUTGOING_DATA_TRANSFER"; + case Type::INCOMING_DATA_TRANSFER: + return "INCOMING_DATA_TRANSFER"; case Type::INVALID: default: return "INVALID"; @@ -63,6 +69,10 @@ to_type(const std::string& type) return interaction::Type::CALL; else if (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 return interaction::Type::INVALID; } @@ -75,7 +85,14 @@ enum class Status { FAILED, SUCCEED, 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 @@ -94,7 +111,20 @@ to_string(const Status& status) return "READ"; case Status::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: return "INVALID"; } @@ -115,6 +145,20 @@ to_status(const std::string& status) return interaction::Status::READ; else if (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 return interaction::Status::INVALID; @@ -130,8 +174,9 @@ struct Info }; static inline bool isOutgoing(const Info& interaction) { - return interaction.status != lrc::api::interaction::Status::READ - && interaction.status != lrc::api::interaction::Status::UNREAD; + return (interaction.status != lrc::api::interaction::Status::READ + && interaction.status != lrc::api::interaction::Status::UNREAD) + || interaction.type == lrc::api::interaction::Type::OUTGOING_DATA_TRANSFER; } } // namespace interaction diff --git a/src/authority/databasehelper.cpp b/src/authority/databasehelper.cpp index 2a2b19337c4851f051ef79c2e603f68cd8b7e440..67b3343af123136cc90fef0666e91a846dbf2f21 100644 --- a/src/authority/databasehelper.cpp +++ b/src/authority/databasehelper.cpp @@ -18,6 +18,7 @@ ***************************************************************************/ #include "databasehelper.h" #include "api/profile.h" +#include "api/datatransfer.h" namespace lrc { @@ -209,6 +210,27 @@ addMessageToConversation(Database& db, {":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 addOrUpdateMessage(Database& db, const std::string& accountProfile, @@ -267,7 +289,7 @@ std::string getInteractionIdByDaemonId(Database& db, const std::string& id) void updateInteractionStatus(Database& db, unsigned int id, - api::interaction::Status& newStatus) + api::interaction::Status newStatus) { db.update("interactions", "status=:status", {{":status", api::interaction::to_string(newStatus)}}, diff --git a/src/authority/databasehelper.h b/src/authority/databasehelper.h index f4bcbe69855f6d20a51614b8a7019380da8a1f03..9ee85493c39ca7fd391384d51f8f709dcb0e03fc 100644 --- a/src/authority/databasehelper.h +++ b/src/authority/databasehelper.h @@ -177,7 +177,7 @@ std::string getInteractionIdByDaemonId(Database& db, const std::string& id); * @param newStatus */ void updateInteractionStatus(Database& db, unsigned int id, - api::interaction::Status& newStatus); + api::interaction::Status newStatus); /** * Clear history but not the conversation started interaction @@ -229,6 +229,10 @@ void addContact(Database& db, const std::string& accountUri, const std::string& */ 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 authority diff --git a/src/callbackshandler.cpp b/src/callbackshandler.cpp index 7781cf279044abfd23c4b323a7fff6678b2dbdba..f2e5fa92f6deec46c830b0512edda436db61f5d4 100644 --- a/src/callbackshandler.cpp +++ b/src/callbackshandler.cpp @@ -282,9 +282,34 @@ CallbacksHandler::slotAccountMessageStatusChanged(const QString& accountId, } 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 diff --git a/src/callbackshandler.h b/src/callbackshandler.h index a1e4a65dfb5e6d6a466dc2a34c95cb2c72b363ba..adf4d2bdd2687bbc0c6d393d3e10f54c68188aa5 100644 --- a/src/callbackshandler.h +++ b/src/callbackshandler.h @@ -160,7 +160,13 @@ Q_SIGNALS: const uint64_t id, 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: /** diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp index 9dd7ce5b47cc42118a02b9adda2997ca22f24cd2..5ac5ea654258998891d93f43c507cf6757bfc219 100644 --- a/src/conversationmodel.cpp +++ b/src/conversationmodel.cpp @@ -214,13 +214,16 @@ public Q_SLOTS: */ void slotConferenceRemoved(const std::string& confId); - void slotIncomingTransfer(const std::string& uid, - const std::string& display_name, - const std::size_t size, - const std::size_t offset); + void slotIncomingTransfer(long long dringId); - void slotTransferStatusChanged(const std::string& uid, - datatransfer::Status status); + //~ 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); }; @@ -712,16 +715,31 @@ ConversationModelPimpl::ConversationModelPimpl(const ConversationModel& linked, this, &ConversationModelPimpl::slotConferenceRemoved); - connect(&dataTransferModel, - &DataTransferModel::incomingTransfer, + // data transfer + connect(&callbacksHandler, + &CallbacksHandler::incomingTransfer, this, &ConversationModelPimpl::slotIncomingTransfer); - - connect(&dataTransferModel, - &DataTransferModel::transferStatusChanged, + connect(&callbacksHandler, + &CallbacksHandler::transferStatusCanceled, 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() @@ -948,6 +966,14 @@ ConversationModelPimpl::addConversationWith(const std::string& convId, } slotUpdateInteractionStatus(linked.owner.id, std::stoull(id), 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) } void -ConversationModelPimpl::slotIncomingTransfer(const std::string& uid, - const std::string& display_name, - const std::size_t size, - const std::size_t offset) +ConversationModelPimpl::slotIncomingTransfer(long long dringId) { - 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 -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 @@ -1246,19 +1334,188 @@ ConversationModel::sendFile(const std::string& uid, const std::string& path, con auto conversationIdx = pimpl_->indexOf(uid); if (conversationIdx != -1) { 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()); + } } } 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) { - auto& dataTransferUid = pimpl_->dataTransferModel.transferIdList()[interactionId]; - if (not dataTransferUid.empty()) - pimpl_->dataTransferModel.acceptFile(dataTransferUid, "~", 0); + auto& interactions = conversations[conversationIdx].interactions; + auto it = interactions.find(interactionId); + 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); + } } } diff --git a/src/datatransfermodel.cpp b/src/datatransfermodel.cpp index 82d4f1d229ea8108c28a2c2852fe67264166eb77..3bc088f6922632cd0abf30da397df5b8733d04e2 100644 --- a/src/datatransfermodel.cpp +++ b/src/datatransfermodel.cpp @@ -65,16 +65,13 @@ public: Database& database, const CallbacksHandler& callbacksHandler); + std::vector<std::string> transferIdList() const; + DataTransferModel& upLink; - std::map<DRing::DataTransferId, std::string> dring2lrcIdMap; - std::map<std::string, DRing::DataTransferId> lrc2dringIdMap; // stricly the reverse map of dring2lrcIdMap + std::map<long long, int> dring2lrcIdMap; + std::map<int, long long> lrc2dringIdMap; // stricly the reverse map of dring2lrcIdMap Database& database; 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, @@ -84,41 +81,18 @@ DataTransferModel::Impl::Impl(DataTransferModel& up_link, , callbacksHandler {callbacksHandler} , database {database} , 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 -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, const CallbacksHandler& callbacksHandler) : QObject() @@ -128,21 +102,21 @@ DataTransferModel::DataTransferModel(Database& database, DataTransferModel::~DataTransferModel() = default; std::vector<std::string> -DataTransferModel::transferIdList() const +DataTransferModel::Impl::transferIdList() const { VectorULongLong dring_list = ConfigurationManager::instance().dataTransferList(); - for (auto dring_id : dring_list) { - pimpl_->registerTransferId(dring_id); - } + //~ for (auto dring_id : dring_list) { + //~ pimpl_->registerTransferId(dring_id); + //~ } std::vector<std::string> result; - result.reserve(dring_list.size()); - for (auto& item : pimpl_->lrc2dringIdMap) { - result.push_back(item.first); - } + //~ result.reserve(dring_list.size()); + //~ for (auto& item : pimpl_->lrc2dringIdMap) { + //~ result.push_back(item.first); + //~ } return result; } -std::string +void DataTransferModel::sendFile(const std::string& account_id, const std::string& peer_uri, 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 QString::fromStdString(peer_uri), QString::fromStdString(file_path), 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 -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 -DataTransferModel::acceptFile(const std::string& lrc_id, +DataTransferModel::accept(int interactionId, const std::string& file_path, 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); } 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); } +int +DataTransferModel::getInteractionIdFromDringId(long long dringId) +{ + return pimpl_->dring2lrcIdMap.at(dringId); +} + }} // namespace lrc::api #include "api/moc_datatransfermodel.cpp"