Commit 19dbc124 authored by Guillaume Roguez's avatar Guillaume Roguez Committed by Anthony Léonard

datatransfer: API changes to not throw

GTK client uses D-Bus, so is unable to forward exceptions.
This causes crashes of daemon (unhandled exception).

This patch changes DataTransfer API to not throw (noexcept).
This is an important changes, not backware compatible,
so the API version has been modified consequently.

Change-Id: I9f2a2fe1732b2622ace16225b6e792dc15383ba1
Reviewed-by: default avatarAnthony Léonard <anthony.leonard@savoirfairelinux.com>
parent 66b2627a
......@@ -1409,59 +1409,48 @@
</arg>
</method>
<method name="sendFile" tp:name-for-bindings="sendFile">
<method name="dataTransferList" tp:name-for-bindings="dataTransferList">
<tp:added version="4.2.0"/>
<arg type="t" name="DataTransferId" direction="out">
</arg>
<arg type="s" name="accountID" direction="in">
</arg>
<arg type="s" name="peer_uri" direction="in">
<tp:docstring>
RingID of request's recipient.
</tp:docstring>
</arg>
<arg type="s" name="file_path" direction="in"></arg>
<arg type="s" name="display_name" direction="in"></arg>
<arg type="at" name="dataTransferList" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorULongLong"/>
</method>
<method name="dataTransferList" tp:name-for-bindings="dataTransferList">
<method name="sendFile" tp:name-for-bindings="sendFile">
<tp:added version="4.2.0"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="VectorULongLong"/>
<arg type="at" name="DataTransferList" direction="out">
</arg>
<arg type="u" name="dataTransferError" direction="out"/>
<arg type="(suuxxssss)" name="DataTransferInfo" direction="in"/>
<arg type="t" name="dataTransferId" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="DataTransferInfo"/>
</method>
<method name="dataTransferInfo" tp:name-for-bindings="dataTransferInfo">
<tp:added version="4.2.0"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="DataTransferInfo"/>
<arg type="(buttssss)" name="DataTransferInfo" direction="out">
</arg>
<arg type="t" name="DataTransferId" direction="in">
</arg>
<tp:added version="5.0.0"/>
<arg type="u" name="dataTransferError" direction="out"/>
<arg type="t" name="dataTransferId" direction="in"/>
<arg type="(suuxxssss)" name="dataTransferInfo" direction="out"/>
<annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="DataTransferInfo"/>
</method>
<method name="dataTransferBytesProgress" tp:name-for-bindings="dataTransferBytesProgress">
<tp:added version="4.2.0"/>
<arg type="t" name="BytesProgress" direction="out">
</arg>
<arg type="t" name="DataTransferId" direction="in">
</arg>
<tp:added version="5.0.0"/>
<arg type="u" name="dataTransferError" direction="out"/>
<arg type="t" name="dataTransferId" direction="in"/>
<arg type="x" name="totalSize" direction="out"/>
<arg type="x" name="bytesProgress" direction="out"/>
</method>
<method name="acceptFileTransfer" tp:name-for-bindings="acceptFileTransfer">
<tp:added version="4.2.0"/>
<arg type="t" name="DataTransferId" direction="in">
</arg>
<arg type="s" name="file_path" direction="in">
</arg>
<arg type="t" name="offset" direction="in">
</arg>
<tp:added version="5.0.0"/>
<arg type="u" name="dataTransferError" direction="out"/>
<arg type="t" name="dataTransferId" direction="in"/>
<arg type="s" name="filePath" direction="in"/>
<arg type="x" name="offset" direction="in"/>
</method>
<method name="cancelDataTransfer" tp:name-for-bindings="cancelDataTransfer">
<tp:added version="4.2.0"/>
<arg type="t" name="DataTransferId" direction="in">
</arg>
<tp:added version="5.0.0"/>
<arg type="u" name="dataTransferError" direction="out"/>
<arg type="t" name="dataTransferId" direction="in"/>
</method>
<signal name="mediaParametersChanged" tp:name-for-bindings="mediaParametersChanged">
......
......@@ -615,48 +615,66 @@ DBusConfigurationManager::connectivityChanged()
}
auto
DBusConfigurationManager::sendFile(const std::string& account_id, const std::string& peer_uri,
const std::string& file_path, const std::string& display_name) -> decltype(DRing::sendFile(account_id, peer_uri, file_path, display_name))
DBusConfigurationManager::dataTransferList() -> decltype(DRing::dataTransferList())
{
return DRing::sendFile(account_id, peer_uri, file_path, display_name);
return DRing::dataTransferList();
}
DBus::Struct<bool, uint32_t, uint64_t, uint64_t, std::string, std::string, std::string, std::string>
DBusConfigurationManager::dataTransferInfo(const DRing::DataTransferId& id)
{
DBus::Struct<bool, uint32_t, uint64_t, uint64_t, std::string, std::string, std::string, std::string> out;
auto info = DRing::dataTransferInfo(id);
out._1 = info.isOutgoing;
out._2 = uint32_t(info.lastEvent);
out._3 = info.totalSize;
out._4 = info.bytesProgress;
out._5 = info.displayName;
out._6 = info.path;
out._7 = info.accountId;
out._8 = info.peer;
return out;
void
DBusConfigurationManager::sendFile(const RingDBusDataTransferInfo& in,
uint32_t& error,
DRing::DataTransferId& id)
{
DRing::DataTransferInfo info;
info.accountId = in._1;
info.lastEvent = DRing::DataTransferEventCode(in._2);
info.flags = in._3;
info.totalSize = in._4;
info.bytesProgress = in._5;
info.peer = in._6;
info.displayName = in._7;
info.path = in._8;
info.mimetype = in._9;
error = uint32_t(DRing::sendFile(info, id));
}
uint64_t
DBusConfigurationManager::dataTransferBytesProgress(const uint64_t& id)
{
return DRing::dataTransferBytesProgress(id);
void
DBusConfigurationManager::dataTransferInfo(const DRing::DataTransferId& id,
uint32_t& error,
RingDBusDataTransferInfo& out)
{
DRing::DataTransferInfo info;
auto res = DRing::dataTransferInfo(id, info);
if (res == DRing::DataTransferError::success) {
out._1 = info.accountId;
out._2 = uint32_t(info.lastEvent);
out._3 = info.flags;
out._4 = info.totalSize;
out._5 = info.bytesProgress;
out._6 = info.peer;
out._7 = info.displayName;
out._8 = info.path;
out._9 = info.mimetype;
}
error = uint32_t(res);
}
auto
DBusConfigurationManager::dataTransferList() -> decltype(DRing::dataTransferList())
void
DBusConfigurationManager::dataTransferBytesProgress(const uint64_t& id, uint32_t& error,
int64_t& total, int64_t& progress)
{
return DRing::dataTransferList();
error = uint32_t(DRing::dataTransferBytesProgress(id, total, progress));
}
void
DBusConfigurationManager::acceptFileTransfer(const uint64_t& id, const std::string& file_path, const uint64_t& offset)
uint32_t
DBusConfigurationManager::acceptFileTransfer(const uint64_t& id, const std::string& file_path,
const int64_t& offset)
{
DRing::acceptFileTransfer(id, file_path, offset);
return uint32_t(DRing::acceptFileTransfer(id, file_path, offset));
}
void
uint32_t
DBusConfigurationManager::cancelDataTransfer(const uint64_t& id)
{
DRing::cancelDataTransfer(id);
return uint32_t(DRing::cancelDataTransfer(id));
}
......@@ -55,6 +55,8 @@ class DBusConfigurationManager :
public DBus::ObjectAdaptor
{
public:
using RingDBusDataTransferInfo = DBus::Struct<std::string, uint32_t, uint32_t, int64_t, int64_t, std::string, std::string, std::string, std::string>;
DBusConfigurationManager(DBus::Connection& connection);
// Methods
......@@ -153,13 +155,12 @@ class DBusConfigurationManager :
int exportAccounts(const std::vector<std::string>& accountIDs, const std::string& filepath, const std::string& password);
int importAccounts(const std::string& archivePath, const std::string& password);
void connectivityChanged();
DRing::DataTransferId sendFile(const std::string& account_id, const std::string& peer_uri,
const std::string& file_path, const std::string& display_name);
DBus::Struct<bool, uint32_t, uint64_t, uint64_t, std::string, std::string, std::string, std::string> dataTransferInfo(const DRing::DataTransferId& id);
uint64_t dataTransferBytesProgress(const uint64_t& id);
std::vector<uint64_t> dataTransferList();
void acceptFileTransfer(const uint64_t& id, const std::string& file_path, const uint64_t& offset);
void cancelDataTransfer(const uint64_t& id);
void sendFile(const RingDBusDataTransferInfo& info, uint32_t& error, DRing::DataTransferId& id);
void dataTransferInfo(const DRing::DataTransferId& id, uint32_t& error, RingDBusDataTransferInfo& info);
void dataTransferBytesProgress(const uint64_t& id, uint32_t& error, int64_t& total, int64_t& progress);
uint32_t acceptFileTransfer(const uint64_t& id, const std::string& file_path, const int64_t& offset);
uint32_t cancelDataTransfer(const uint64_t& id);
};
#endif // __RING_DBUSCONFIGURATIONMANAGER_H__
......@@ -2,7 +2,7 @@ dnl Ring - configure.ac for automake 1.9 and autoconf 2.59
dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.65])
AC_INIT([Ring Daemon],[4.3.0],[ring@gnu.org],[ring])
AC_INIT([Ring Daemon],[5.0.0],[ring@gnu.org],[ring])
AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2018]])
AC_REVISION([$Revision$])
......
......@@ -31,7 +31,7 @@ PROJECT_NAME = "Ring Daemon"
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER = 4.3.0
PROJECT_NUMBER = 5.0.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer
......
......@@ -42,45 +42,39 @@ registerDataXferHandlers(const std::map<std::string, std::shared_ptr<CallbackWra
}
std::vector<DataTransferId>
dataTransferList()
dataTransferList() noexcept
{
return ring::Manager::instance().dataTransfers->list();
}
DataTransferId
sendFile(const std::string& account_id,
const std::string& peer_uri,
const std::string& file_path,
const std::string& display_name)
DataTransferError
sendFile(const DataTransferInfo& info, DataTransferId& id) noexcept
{
return ring::Manager::instance().dataTransfers->sendFile(
account_id, peer_uri, file_path, display_name.empty() ? file_path : display_name);
return ring::Manager::instance().dataTransfers->sendFile(info, id);
}
void
acceptFileTransfer(const DataTransferId& id,
const std::string& file_path,
std::size_t offset)
DataTransferError
acceptFileTransfer(const DataTransferId& id, const std::string& file_path, int64_t offset) noexcept
{
ring::Manager::instance().dataTransfers->acceptAsFile(id, file_path, offset);
return ring::Manager::instance().dataTransfers->acceptAsFile(id, file_path, offset);
}
void
cancelDataTransfer(const DataTransferId& id)
DataTransferError
cancelDataTransfer(const DataTransferId& id) noexcept
{
ring::Manager::instance().dataTransfers->cancel(id);
return ring::Manager::instance().dataTransfers->cancel(id);
}
std::streamsize
dataTransferBytesProgress(const DataTransferId& id)
DataTransferError
dataTransferBytesProgress(const DataTransferId& id, int64_t& total, int64_t& progress) noexcept
{
return ring::Manager::instance().dataTransfers->bytesProgress(id);
return ring::Manager::instance().dataTransfers->bytesProgress(id, total, progress);
}
DataTransferInfo
dataTransferInfo(const DataTransferId& id)
DataTransferError
dataTransferInfo(const DataTransferId& id, DataTransferInfo& info) noexcept
{
return ring::Manager::instance().dataTransfers->info(id);
return ring::Manager::instance().dataTransfers->info(id, info);
}
} // namespace DRing
......@@ -72,15 +72,15 @@ public:
started_ = false;
}
virtual std::streamsize bytesProgress() const {
void bytesProgress(int64_t& total, int64_t& progress) const {
std::lock_guard<std::mutex> lk {infoMutex_};
return info_.bytesProgress;
total = info_.totalSize;
progress = info_.bytesProgress;
}
DRing::DataTransferInfo info() const {
bytesProgress();
void info(DRing::DataTransferInfo& info) const {
std::lock_guard<std::mutex> lk {infoMutex_};
return info_;
info = info_;
}
void emit(DRing::DataTransferEventCode code) const;
......@@ -133,7 +133,7 @@ FileTransfer::FileTransfer(DRing::DataTransferId tid, const DRing::DataTransferI
throw std::runtime_error("input file open failed");
info_ = info;
info_.isOutgoing = true;
info_.flags &= ~((uint32_t)1 << int(DRing::DataTransferFlags::direction)); // outgoing
// File size?
input_.seekg(0, std::ios_base::end);
......@@ -211,8 +211,6 @@ public:
void close() noexcept override;
std::streamsize bytesProgress() const override;
std::string requestFilename();
void accept(const std::string&, std::size_t offset) override;
......@@ -233,14 +231,7 @@ IncomingFileTransfer::IncomingFileTransfer(DRing::DataTransferId tid,
RING_WARN() << "[FTP] incoming transfert of " << info.totalSize << " byte(s): " << info.displayName;
info_ = info;
info_.isOutgoing = false;
}
std::streamsize
IncomingFileTransfer::bytesProgress() const
{
std::lock_guard<std::mutex> lk {infoMutex_};
return info_.bytesProgress;
info_.flags |= (uint32_t)1 << int(DRing::DataTransferFlags::direction); // incoming
}
std::string
......@@ -290,7 +281,7 @@ IncomingFileTransfer::close() noexcept
RING_DBG() << "[FTP] file closed, rx " << info_.bytesProgress
<< " on " << info_.totalSize;
if (std::size_t(info_.bytesProgress) == info_.totalSize)
if (info_.bytesProgress >= info_.totalSize)
emit(DRing::DataTransferEventCode::finished);
else
emit(DRing::DataTransferEventCode::closed_by_host);
......@@ -327,7 +318,8 @@ public:
mutable std::mutex mapMutex_;
std::unordered_map<DRing::DataTransferId, std::shared_ptr<DataTransfer>> map_;
std::shared_ptr<DataTransfer> createFileTransfer(const DRing::DataTransferInfo&);
std::shared_ptr<DataTransfer> createFileTransfer(const DRing::DataTransferInfo& info,
DRing::DataTransferId& tid);
std::shared_ptr<IncomingFileTransfer> createIncomingFileTransfer(const DRing::DataTransferInfo&);
std::shared_ptr<DataTransfer> getTransfer(const DRing::DataTransferId&);
void cancel(DataTransfer&);
......@@ -351,9 +343,10 @@ DataTransferFacade::Impl::getTransfer(const DRing::DataTransferId& id)
}
std::shared_ptr<DataTransfer>
DataTransferFacade::Impl::createFileTransfer(const DRing::DataTransferInfo& info)
DataTransferFacade::Impl::createFileTransfer(const DRing::DataTransferInfo& info,
DRing::DataTransferId& tid)
{
auto tid = generateUID();
tid = generateUID();
auto transfer = std::make_shared<FileTransfer>(tid, info);
{
std::lock_guard<std::mutex> lk {mapMutex_};
......@@ -396,106 +389,117 @@ DataTransferFacade::Impl::onConnectionRequestReply(const DRing::DataTransferId&
DataTransferFacade::DataTransferFacade() : pimpl_ {std::make_unique<Impl>()}
{
RING_WARN("facade created, pimpl @%p", pimpl_.get());
RING_WARN("[XFER] facade created, pimpl @%p", pimpl_.get());
}
DataTransferFacade::~DataTransferFacade()
{
RING_WARN("facade destroy, pimpl @%p", pimpl_.get());
RING_WARN("[XFER] facade destroy, pimpl @%p", pimpl_.get());
};
std::vector<DRing::DataTransferId>
DataTransferFacade::list() const
DataTransferFacade::list() const noexcept
{
std::lock_guard<std::mutex> lk {pimpl_->mapMutex_};
return map_utils::extractKeys(pimpl_->map_);
}
DRing::DataTransferId
DataTransferFacade::sendFile(const std::string& account_id, const std::string& peer_uri,
const std::string& file_path, const std::string& display_name)
DRing::DataTransferError
DataTransferFacade::sendFile(const DRing::DataTransferInfo& info,
DRing::DataTransferId& tid) noexcept
{
auto account = Manager::instance().getAccount<RingAccount>(account_id);
if (!account)
throw std::invalid_argument("unknown account id");
if (!fileutils::isFile(file_path))
throw std::invalid_argument("invalid input file");
DRing::DataTransferInfo info;
info.accountId = account_id;
info.peer = peer_uri;
info.displayName = display_name;
info.path = file_path;
// remaining fields are overwritten
auto transfer = pimpl_->createFileTransfer(info);
auto tid = transfer->getId();
// IMPLEMENTATION NOTE: requestPeerConnection() may call the given callback a multiple time.
// This happen when multiple agents handle communications of the given peer for the given account.
// Example: Ring account supports multi-devices, each can answer to the request.
account->requestPeerConnection(
peer_uri,
[this, tid] (PeerConnection* connection) {
pimpl_->onConnectionRequestReply(tid, connection);
});
return tid;
auto account = Manager::instance().getAccount<RingAccount>(info.accountId);
if (!account) {
RING_ERR() << "[XFER] unknown id " << tid;
return DRing::DataTransferError::invalid_argument;
}
if (!fileutils::isFile(info.path)) {
RING_ERR() << "[XFER] invalid filename '" << info.path << "'";
return DRing::DataTransferError::invalid_argument;
}
try {
pimpl_->createFileTransfer(info, tid);
} catch (const std::exception& ex) {
RING_ERR() << "[XFER] exception during createFileTransfer(): " << ex.what();
return DRing::DataTransferError::io;
}
try {
// IMPLEMENTATION NOTE: requestPeerConnection() may call the given callback a multiple time.
// This happen when multiple agents handle communications of the given peer for the given account.
// Example: Ring account supports multi-devices, each can answer to the request.
account->requestPeerConnection(
info.peer,
[this, tid] (PeerConnection* connection) {
pimpl_->onConnectionRequestReply(tid, connection);
});
return DRing::DataTransferError::success;
} catch (const std::exception& ex) {
RING_ERR() << "[XFER] exception during sendFile(): " << ex.what();
return DRing::DataTransferError::unknown;
}
}
void
DRing::DataTransferError
DataTransferFacade::acceptAsFile(const DRing::DataTransferId& id,
const std::string& file_path,
std::size_t offset)
int64_t offset) noexcept
{
std::lock_guard<std::mutex> lk {pimpl_->mapMutex_};
const auto& iter = pimpl_->map_.find(id);
if (iter == std::end(pimpl_->map_))
throw std::invalid_argument("not existing DataTransferId");
return DRing::DataTransferError::invalid_argument;;
iter->second->accept(file_path, offset);
return DRing::DataTransferError::success;
}
void
DataTransferFacade::cancel(const DRing::DataTransferId& id)
DRing::DataTransferError
DataTransferFacade::cancel(const DRing::DataTransferId& id) noexcept
{
if (auto transfer = pimpl_->getTransfer(id))
if (auto transfer = pimpl_->getTransfer(id)) {
pimpl_->cancel(*transfer);
else
throw std::invalid_argument("not existing DataTransferId");
return DRing::DataTransferError::success;
}
return DRing::DataTransferError::invalid_argument;
}
std::streamsize
DataTransferFacade::bytesProgress(const DRing::DataTransferId& id) const
DRing::DataTransferError
DataTransferFacade::bytesProgress(const DRing::DataTransferId& id,
int64_t& total, int64_t& progress) const noexcept
{
if (auto transfer = pimpl_->getTransfer(id))
return transfer->bytesProgress();
throw std::invalid_argument("not existing DataTransferId");
try {
if (auto transfer = pimpl_->getTransfer(id)) {
transfer->bytesProgress(total, progress);
return DRing::DataTransferError::success;
}
return DRing::DataTransferError::invalid_argument;
} catch (const std::exception& ex) {
RING_ERR() << "[XFER] exception during bytesProgress(): " << ex.what();
}
return DRing::DataTransferError::unknown;
}
DRing::DataTransferInfo
DataTransferFacade::info(const DRing::DataTransferId& id) const
DRing::DataTransferError
DataTransferFacade::info(const DRing::DataTransferId& id,
DRing::DataTransferInfo& info) const noexcept
{
if (auto transfer = pimpl_->getTransfer(id))
return transfer->info();
throw std::invalid_argument("not existing DataTransferId");
try {
if (auto transfer = pimpl_->getTransfer(id)) {
transfer->info(info);
return DRing::DataTransferError::success;
}
return DRing::DataTransferError::invalid_argument;
} catch (const std::exception& ex) {
RING_ERR() << "[XFER] exception during info(): " << ex.what();
}
return DRing::DataTransferError::unknown;
}
std::shared_ptr<Stream>
DataTransferFacade::onIncomingFileRequest(const std::string& account_id,
const std::string& peer_uri,
const std::string& display_name,
std::size_t total_size,
std::size_t offset)
DataTransferFacade::onIncomingFileRequest(const DRing::DataTransferInfo& info)
{
DRing::DataTransferInfo info;
info.accountId = account_id;
info.peer = peer_uri;
info.displayName = display_name;
info.totalSize = total_size;
info.bytesProgress = offset;
// remaining fields are overwritten
auto transfer = pimpl_->createIncomingFileTransfer(info);
auto filename = transfer->requestFilename();
if (!filename.empty())
......
......@@ -36,46 +36,32 @@ public:
DataTransferFacade();
~DataTransferFacade();
/// Return all known transfer id
std::vector<DRing::DataTransferId> list() const;
/// \see DRing::dataTransferList
std::vector<DRing::DataTransferId> list() const noexcept;
/// Send a file to a peer.
/// Open a file and send its contents over a reliable connection
/// to given peer using the protocol from given account.
/// This method fails immediately if the file cannot be open in binary read mode,
/// if the account doesn't exist or if it doesn't support data transfer.
/// Remaining actions are operated asynchronously, so events are given by signals.
/// \return a unique data transfer identifier.
/// \except std::invalid_argument account doesn't exist or don't support data transfer.
/// \except std::ios_base::failure in case of open file errors.
DRing::DataTransferId sendFile(const std::string& account_id,
const std::string& peer_uri,
const std::string& file_path,
const std::string& display_name);
/// \see DRing::sendFile
DRing::DataTransferError sendFile(const DRing::DataTransferInfo& info,
DRing::DataTransferId& id) noexcept;
/// Accept an incoming transfer and send data into given file.
void acceptAsFile(const DRing::DataTransferId& id,
const std::string& file_path,
std::size_t offset);
/// \see DRing::acceptFileTransfer
DRing::DataTransferError acceptAsFile(const DRing::DataTransferId& id,
const std::string& file_path,
int64_t offset) noexcept;
/// Abort a transfer.
/// The transfer id is abort and removed. The id is not longer valid after the call.
void cancel(const DRing::DataTransferId& id);
/// \see DRing::cancelDataTransfer
DRing::DataTransferError cancel(const DRing::DataTransferId& id) noexcept;
/// \return a copy of all information about a data transfer
DRing::DataTransferInfo info(const DRing::DataTransferId& id) const;
/// \see DRing::dataTransferInfo
DRing::DataTransferError info(const DRing::DataTransferId& id,
DRing::DataTransferInfo& info) const noexcept;
/// \return number of bytes sent/received by a data transfer
/// \note this method is fatest than info()
std::streamsize bytesProgress(const DRing::DataTransferId& id) const;
/// \see DRing::dataTransferBytesProgress
DRing::DataTransferError bytesProgress(const DRing::DataTransferId& id, int64_t& total,
int64_t& progress) const noexcept;
/// Create an IncomingFileTransfer object.
/// \return a shared pointer on created Stream object, or nullptr in case of error
std::shared_ptr<Stream> onIncomingFileRequest(const std::string& account_id,
const std::string& peer_uri,
const std::string& display_name,
std::size_t total_size,
std::size_t offset);
std::shared_ptr<Stream> onIncomingFileRequest(const DRing::DataTransferInfo& info);
private:
class Impl;
......
......@@ -27,8 +27,7 @@
#include <map>
#include <vector>
#include <memory>
#include <cstdlib> // std::size_t
#include <ios> // std::streamsize
#include <bitset>
namespace DRing {
......@@ -36,6 +35,7 @@ using DataTransferId = uint64_t;
enum class DataTransferEventCode : uint32_t
{
invalid=0,
created,
unsupported,
wait_peer_acceptance,
......@@ -48,19 +48,34 @@ enum class DataTransferEventCode : uint32_t
unjoinable_peer,
};
enum class DataTransferError : uint32_t
{
success=0,
unknown,
io,
invalid_argument,
};
/// Bit definition for DataTransferInfo.flags field
enum class DataTransferFlags
{
direction=0, ///< 0: outgoing, 1: incoming
};
struct DataTransferInfo
{
bool isOutgoing; ///< Outgoing or Incoming?
DataTransferEventCode lastEvent { DataTransferEventCode::created }; ///< Latest event code sent to the user
std::size_t totalSize {0} ; ///< Total number of bytes to sent/receive, 0 if not known
std::streamsize bytesProgress {0}; ///< Number of bytes sent/received
std::string displayName; ///< Human oriented transfer name
std::string path; ///< associated local file path if supported (empty, if not)
std::string accountId; ///< Identifier of the emiter/receiver account
DataTransferEventCode lastEvent { DataTransferEventCode::invalid }; ///< Latest event code sent to the user
uint32_t flags {0}; ///< Transfer global information.
int64_t totalSize {0} ; ///< Total number of bytes to sent/receive, 0 if not known
int64_t bytesProgress {0}; ///< Number of bytes sent/received
std::string peer; ///< Identifier of the remote peer (in the semantic of the associated account)
std::string displayName; ///< Human oriented transfer name
std::string path; ///< associated local file path if supported (empty, if not)
std::string mimetype; ///< MimeType of transfered data (https://www.iana.org/assignments/media-types/media-types.xhtml)
};
std::vector<DataTransferId> dataTransferList();
std::vector<DataTransferId> dataTransferList() noexcept;
/// Asynchronously send a file to a peer using given account connection.
///
......@@ -68,24 +83,25 @@ std::vector<DataTransferId> dataTransferList();
/// an internal data transfer and return its identification.
/// This identity code is used by signals and APIs to follow the transfer progress.
///
/// \param account_id existing account ID with file transfer support
/// \param peer_uri peer address suitable for the given account
/// \param file_path pathname of file to transfer
/// \param display_name optional textual representation given to the peer when the file is proposed.
/// When empty (or not given), \a file_path is used.
/// Following the \a info structure fields usage:
/// - accountId [mandatory] existing account ID with file transfer support
/// - peer [mandatory] peer address suitable for the given account
/// - path [mandatory] pathname of file to transfer
/// - mimetype [optional] file type
/// - displayName [optional] textual representation given to the peer when the file is proposed
///
/// \return DataTransferId value representing the internal transfer.
/// Other fields are not used, but you must keep the default assigned value for compatibility.