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
This diff is collapsed.
......@@ -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.
///
/// \exception std::invalid_argument not existing account
/// \exception std::ios_base::failure file opening failures
/// \param info a DataTransferInfo structure filled with information usefull for a file transfer.
/// \param[out] id data transfer identifiant if function succeed, usable with other APIs. Undefined value in case of error.
///
/// \return DataTransferError::success if file is accepted for transfer, any other value in case of errors
/// \note If the account is valid but doesn't support file transfer, or if the peer is unjoignable,
/// or at events during the transfer, the function returns a valid DataTransferId and the user
/// will be signaled throught DataTransferEvent signal for such event.
/// There is no reserved or special values on DataTransferId type.
/// or at any further events during the transfer, the function returns a valid DataTransferId as
/// the processing is asynchronous. Application will be signaled throught DataTransferEvent signal
/// for such event. There is no reserved or special values on DataTransferId type.
///
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;
/// Accept an incoming file transfer.
///
......@@ -99,7 +115,11 @@ DataTransferId sendFile(const std::string& account_id, const std::string& peer_u
/// \param offset used to indicate the remote side about the number of bytes already received in
/// a previous transfer session, usefull in transfer continuation mode.
///
void acceptFileTransfer(const DataTransferId& id, const std::string& file_path, std::size_t offset);
/// \return DataTransferError::invalid_argument if id is unknown.
/// \note unknown \a id results to a no-op call.
///
DataTransferError acceptFileTransfer(const DataTransferId& id, const std::string& file_path,
int64_t offset) noexcept;
/// Refuse or abort an outgoing or an incoming file transfer.
///
......@@ -110,23 +130,32 @@ void acceptFileTransfer(const DataTransferId& id, const std::string& file_path,
///
/// \param id data transfer identification value as given by a DataTransferEvent signal.
///
void cancelDataTransfer(const DataTransferId& id);
/// \return DataTransferError::invalid_argument if id is unknown.
/// \note unknown \a id results to a no-op call.
///
DataTransferError cancelDataTransfer(const DataTransferId& id) noexcept;
/// Return some information on given data transfer.
///
/// \param id data transfer identification value as given by a DataTransferEvent signal.
/// \param[out] info data transfer information.
///
/// \return transfer information.
/// \return DataTransferError::invalid_argument if id is unknown.
/// \note \a info structure is in undefined state in case of error.
///
DataTransferInfo dataTransferInfo(const DataTransferId& id);
DataTransferError dataTransferInfo(const DataTransferId& id, DataTransferInfo& info) noexcept;
/// Return the amount of sent/received bytes of an existing data transfer.
///
/// \param id data transfer identification value as given by a DataTransferEvent signal.
/// \param[out] total positive number of bytes to sent/received, or -1 if unknown.
/// \param[out] progress positive number of bytes already sent/received.
///
/// \return number of successfuly transfered bytes.
/// \return DataTransferError::success if \a total and \a progress is set with valid values.
/// DataTransferError::invalid_argument if the id is unknown.
///
std::streamsize dataTransferBytesProgress(const DataTransferId& id);
DataTransferError dataTransferBytesProgress(const DataTransferId& id, int64_t& total,
int64_t& progress) noexcept;
// Signal handlers registration
void registerDataXferHandlers(const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>&);
......
......@@ -59,11 +59,13 @@ bool
FtpServer::startNewFile()
{
// Request filename from client (WARNING: synchrone call!)
out_ = Manager::instance().dataTransfers->onIncomingFileRequest(accountId_,
peerUri_,
displayName_,
fileSize_,
0 /* TODO: offset */);
DRing::DataTransferInfo info {};
info.accountId = accountId_;
info.peer = peerUri_;
info.displayName = displayName_;
info.totalSize = fileSize_;
info.bytesProgress = 0;
out_ = Manager::instance().dataTransfers->onIncomingFileRequest(info);
return true;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment