Skip to content
Snippets Groups Projects
Commit de91228b authored by Henrik tom Wörden's avatar Henrik tom Wörden
Browse files

Merge branch 'f-files' into 'dev'

F files

See merge request !11
parents e58611aa d8bd8fce
No related branches found
No related tags found
1 merge request!11F files
Pipeline #12167 passed
Pipeline: caosdb-cppinttest

#12170

    Showing
    with 1346 additions and 151 deletions
    ...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
    cmake_minimum_required(VERSION 3.13) cmake_minimum_required(VERSION 3.13)
    set(libcaosdb_VERSION 0.0.10) set(libcaosdb_VERSION 0.0.11)
    set(libcaosdb_COMPATIBLE_SERVER_VERSION_MAJOR 0) set(libcaosdb_COMPATIBLE_SERVER_VERSION_MAJOR 0)
    set(libcaosdb_COMPATIBLE_SERVER_VERSION_MINOR 5) set(libcaosdb_COMPATIBLE_SERVER_VERSION_MINOR 5)
    set(libcaosdb_COMPATIBLE_SERVER_VERSION_PATCH 0) set(libcaosdb_COMPATIBLE_SERVER_VERSION_PATCH 0)
    ...@@ -38,6 +38,7 @@ set(CMAKE_C_EXTENSIONS OFF) ...@@ -38,6 +38,7 @@ set(CMAKE_C_EXTENSIONS OFF)
    set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
    set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
    set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
    set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
    set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
    ......
    ...@@ -116,6 +116,7 @@ Please adhere to [Google's C++ naming conventions](https://google.github.io/styl ...@@ -116,6 +116,7 @@ Please adhere to [Google's C++ naming conventions](https://google.github.io/styl
    You can use a json file for the configuration of the client. See You can use a json file for the configuration of the client. See
    `test/test_data/test_caosdb_client.json` for an example. You may use `test/test_data/test_caosdb_client.json` for an example. You may use
    `caosdb-client-configuration-schema.json` to validate your schema. `caosdb-client-configuration-schema.json` to validate your schema.
    Typically, you will need to provide the path to your SSL certificate.
    The client will load the configuration file from the first existing The client will load the configuration file from the first existing
    file in the following locations (precedence from highest to lowest): file in the following locations (precedence from highest to lowest):
    ......
    ...@@ -3,7 +3,7 @@ from conans import ConanFile, CMake, tools ...@@ -3,7 +3,7 @@ from conans import ConanFile, CMake, tools
    class CaosdbConan(ConanFile): class CaosdbConan(ConanFile):
    name = "caosdb" name = "caosdb"
    version = "0.0.10" version = "0.0.11"
    license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
    author = "Timm C. Fitschen <t.fitschen@indiscale.com>" author = "Timm C. Fitschen <t.fitschen@indiscale.com>"
    url = "https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib.git" url = "https://gitlab.indiscale.com/caosdb/src/caosdb-cpplib.git"
    ......
    ...@@ -24,6 +24,21 @@ ...@@ -24,6 +24,21 @@
    C API C API
    ===== =====
    .. note::
    When working with libcaosdb's C API keep the following in
    mind. Delete all objects (transactions, entities, properties,
    parents, ...) that you created using a `caosdb_..._create_...`
    function and only those.
    The underlying reason is that all C++ objects are realized in the
    Extern C interface as mutable structs containing a void pointer to
    the actuall C++ object which is not filled when initializing the
    struct but after calling a create function instead. If the C++
    object wasn't created using a create function, e.g., the parent
    object when getting a parent of an entity, it is owned by another
    object and deleted together with that object.
    .. toctree:: .. toctree::
    :glob: :glob:
    ......
    ...@@ -27,6 +27,7 @@ set(libcaosdb_INCL ...@@ -27,6 +27,7 @@ set(libcaosdb_INCL
    ${CMAKE_CURRENT_BINARY_DIR}/caosdb/constants.h ${CMAKE_CURRENT_BINARY_DIR}/caosdb/constants.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/entity.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/entity.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/exceptions.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/exceptions.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/handler_interface.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/info.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/info.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/log_level.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/log_level.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/logging.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/logging.h
    ...@@ -34,8 +35,18 @@ set(libcaosdb_INCL ...@@ -34,8 +35,18 @@ set(libcaosdb_INCL
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/protobuf_helper.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/protobuf_helper.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/status_code.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/status_code.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction_handler.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction_status.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/transaction_status.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/unary_rpc_handler.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/utility.h ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/utility.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/register_file_upload_handler.h
    # TODO this file is still missing
    # ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/register_file_download_handler.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/upload_request_handler.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/download_request_handler.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/file_writer.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/file_reader.h
    ${CMAKE_CURRENT_SOURCE_DIR}/caosdb/file_transmission/file_error.h
    ) )
    # pass variable to parent scope # pass variable to parent scope
    ......
    ...@@ -45,6 +45,7 @@ using boost::filesystem::path; ...@@ -45,6 +45,7 @@ using boost::filesystem::path;
    using caosdb::authentication::Authenticator; using caosdb::authentication::Authenticator;
    using caosdb::configuration::ConnectionConfiguration; using caosdb::configuration::ConnectionConfiguration;
    using caosdb::entity::v1alpha1::EntityTransactionService; using caosdb::entity::v1alpha1::EntityTransactionService;
    using caosdb::entity::v1alpha1::FileTransmissionService;
    using caosdb::info::VersionInfo; using caosdb::info::VersionInfo;
    using caosdb::info::v1alpha1::GeneralInfoService; using caosdb::info::v1alpha1::GeneralInfoService;
    using caosdb::transaction::Transaction; using caosdb::transaction::Transaction;
    ...@@ -104,6 +105,9 @@ private: ...@@ -104,6 +105,9 @@ private:
    /// Service for entity transactions. We use a shared pointer because /// Service for entity transactions. We use a shared pointer because
    /// Transaction instances also own this service stub. /// Transaction instances also own this service stub.
    std::shared_ptr<EntityTransactionService::Stub> entity_transaction_service; std::shared_ptr<EntityTransactionService::Stub> entity_transaction_service;
    /// Service for file transmission (download and upload). We use a shared
    /// pointer because Transaction instances also own this service stub.
    std::shared_ptr<FileTransmissionService::Stub> file_transmission_service;
    }; };
    /** /**
    ......
    ...@@ -29,29 +29,241 @@ ...@@ -29,29 +29,241 @@
    #ifndef CAOSDB_ENTITY_H #ifndef CAOSDB_ENTITY_H
    #define CAOSDB_ENTITY_H #define CAOSDB_ENTITY_H
    #include <string> // for string #include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField
    #include "caosdb/entity/v1alpha1/main.pb.h" // for RepeatedPtrField, Message #include "caosdb/logging.h" // for CAOSDB_LOG_WARN
    #include "caosdb/message_code.h" // for get_message_code, Messag... #include "caosdb/message_code.h" // for get_message_code
    #include "google/protobuf/util/json_util.h" // for MessageToJsonString, Jso... #include "caosdb/status_code.h" // for StatusCode
    #include <boost/filesystem/operations.hpp> // for exists, is_di...
    #include <boost/filesystem/path.hpp> // for path
    #include <boost/log/core/record.hpp> // for record
    #include <boost/log/detail/attachable_sstream_buf.hpp> // for basic_ostring...
    #include <boost/log/sources/record_ostream.hpp> // for basic_record_...
    #include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_...
    #include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_...
    #include <google/protobuf/message.h> // for RepeatedPtrField
    #include <google/protobuf/util/json_util.h> // for MessageToJson...
    #include <iosfwd> // for streamsize
    #include <iterator> // for iterator, output_iterato...
    #include <map> // for map
    #include <random> // for mt19937, rand...
    #include <stdexcept> // for out_of_range
    #include <string> // for string, basic...
    namespace caosdb::entity { namespace caosdb::entity {
    using boost::filesystem::exists;
    using boost::filesystem::is_directory;
    using caosdb::entity::v1alpha1::IdResponse; using caosdb::entity::v1alpha1::IdResponse;
    using ProtoParent = caosdb::entity::v1alpha1::Parent; using ProtoParent = caosdb::entity::v1alpha1::Parent;
    using ProtoProperty = caosdb::entity::v1alpha1::Property; using ProtoProperty = caosdb::entity::v1alpha1::Property;
    using ProtoEntity = caosdb::entity::v1alpha1::Entity; using ProtoEntity = caosdb::entity::v1alpha1::Entity;
    using ProtoFileDescriptor = caosdb::entity::v1alpha1::FileDescriptor;
    using ProtoMessage = caosdb::entity::v1alpha1::Message; using ProtoMessage = caosdb::entity::v1alpha1::Message;
    using caosdb::StatusCode;
    using caosdb::entity::v1alpha1::EntityResponse;
    using caosdb::entity::v1alpha1::FileTransmissionId;
    using ::google::protobuf::RepeatedPtrField;
    using google::protobuf::RepeatedPtrField;
    static const std::string logger_name = "caosdb::entity";
    struct FileDescriptor {
    FileTransmissionId *file_transmission_id;
    ProtoFileDescriptor *wrapped;
    boost::filesystem::path local_path;
    };
    /**
    * Abstract base class for Messages, Properties and Parents container classes.
    *
    * This is a list-like class.
    */
    template <typename T, typename P> class RepeatedPtrFieldWrapper {
    class iterator;
    public:
    /**
    * Return the current size of the container.
    */
    [[nodiscard]] inline auto size() const -> int { return wrapped->size(); }
    /**
    * Return a const reference to the element at the given index.
    */
    [[nodiscard]] inline auto at(int index) const -> const T & {
    return *mutable_at(index);
    }
    /**
    * Return a mutable pointer to the element at the given index.
    */
    [[nodiscard]] inline auto mutable_at(int index) const -> T * {
    if (index >= size() || index < 0) {
    throw std::out_of_range("Container has size " + std::to_string(size()));
    }
    if (cache.count(index) == 0) {
    cache.emplace(index, T(&(wrapped->at(index))));
    }
    return &(cache.at(index));
    }
    /**
    * Return iterator positioned at the beginning of the list.
    */
    auto begin() -> iterator;
    /**
    * Return iterator positioned at the end of the list.
    */
    auto end() -> iterator;
    /**
    * Return constant iterator positioned at the beginning of the list.
    */
    auto begin() const -> const iterator;
    /**
    * Return constant iterator positioned at the end of the list.
    */
    auto end() const -> const iterator;
    friend class Entity;
    virtual ~RepeatedPtrFieldWrapper(){};
    protected:
    RepeatedPtrFieldWrapper(){};
    explicit inline RepeatedPtrFieldWrapper(
    ::google::protobuf::RepeatedPtrField<P> *wrapped)
    : wrapped(wrapped){};
    /**
    * Append an element. This adds the element to the end of the wrapped list
    * and increases the size by one.
    */
    inline auto Append(const T &element) -> void {
    auto *destination = this->wrapped->Add();
    destination->Swap(element.wrapped);
    // Clear the originally wrapped object and return it to the Arena
    element.wrapped->Clear();
    // set the pointer to the new object which is owned by the RepeatedPtrField
    element.wrapped = destination;
    }
    /**
    * Remove the element at the given index.
    */
    inline auto remove(int index) -> void {
    this->wrapped->DeleteSubrange(index, 1);
    if (cache.count(index) > 0) {
    cache.erase(index);
    }
    // shift all indices in the cache above index (such that the values do not
    // get deleted/copied because this could destroy pointers (c-interface).
    for (int i = index + 1; i < size(); i++) {
    if (cache.count(i) > 0) {
    auto handle = cache.extract(i);
    handle.key()--;
    cache.insert(std::move(handle));
    }
    }
    }
    ::google::protobuf::RepeatedPtrField<P> *wrapped;
    mutable std::map<int, T> cache;
    private:
    class iterator : public std::iterator<std::output_iterator_tag, T> {
    public:
    explicit iterator(const RepeatedPtrFieldWrapper<T, P> *instance,
    int index = 0);
    auto operator*() const -> T &;
    auto operator++() -> iterator &;
    auto operator++(int) -> iterator;
    auto operator!=(const iterator &rhs) const -> bool;
    private:
    int current_index = 0;
    const RepeatedPtrFieldWrapper<T, P> *instance;
    };
    };
    template <class T, class P>
    RepeatedPtrFieldWrapper<T, P>::iterator::iterator(
    const RepeatedPtrFieldWrapper<T, P> *instance, int index)
    : current_index(index), instance(instance) {}
    template <typename T, typename P>
    auto RepeatedPtrFieldWrapper<T, P>::iterator::operator*() const -> T & {
    return *(this->instance->mutable_at(current_index));
    }
    template <typename T, typename P>
    auto RepeatedPtrFieldWrapper<T, P>::iterator::operator++()
    -> RepeatedPtrFieldWrapper<T, P>::iterator & {
    current_index++;
    return *this;
    }
    template <typename T, typename P>
    auto RepeatedPtrFieldWrapper<T, P>::iterator::operator++(int)
    -> RepeatedPtrFieldWrapper<T, P>::iterator {
    iterator tmp(*this);
    operator++();
    return tmp;
    }
    template <typename T, typename P>
    auto RepeatedPtrFieldWrapper<T, P>::iterator::operator!=(
    const iterator &rhs) const -> bool {
    return this->current_index != rhs.current_index;
    }
    template <typename T, typename P>
    auto RepeatedPtrFieldWrapper<T, P>::begin()
    -> RepeatedPtrFieldWrapper<T, P>::iterator {
    return RepeatedPtrFieldWrapper<T, P>::iterator(this, 0);
    }
    template <typename T, typename P>
    auto RepeatedPtrFieldWrapper<T, P>::end()
    -> RepeatedPtrFieldWrapper<T, P>::iterator {
    return RepeatedPtrFieldWrapper<T, P>::iterator(this, size());
    }
    template <typename T, typename P>
    auto RepeatedPtrFieldWrapper<T, P>::begin() const
    -> const RepeatedPtrFieldWrapper<T, P>::iterator {
    return RepeatedPtrFieldWrapper<T, P>::iterator(this, 0);
    }
    template <typename T, typename P>
    auto RepeatedPtrFieldWrapper<T, P>::end() const
    -> const RepeatedPtrFieldWrapper<T, P>::iterator {
    return RepeatedPtrFieldWrapper<T, P>::iterator(this, size());
    }
    /** /**
    * Messages convey information about the state and result of transactions. * Messages convey information about the state of entities and result of
    * transactions.
    * *
    * A Message object can be thought of as kinf of a generalized error object in * A Message object can be thought of as kinf of a generalized error object in
    * other frameworks. Please have a look at MessageCodes for more details. * other frameworks. Please have a look at MessageCodes for more details.
    */ */
    class Message { class Message {
    public: public:
    /**
    * Get the code of this message.
    *
    * The message code is a unique identifier of the type of message and is
    * intended to make it easiert to identify messages in a machine-readable
    * way.
    */
    [[nodiscard]] inline auto GetCode() const -> MessageCode { [[nodiscard]] inline auto GetCode() const -> MessageCode {
    return get_message_code(wrapped->code()); return get_message_code(wrapped->code());
    } }
    /**
    * Get the description of this message.
    *
    * The description is intended for a human reader.
    */
    [[nodiscard]] inline auto GetDescription() const -> std::string { [[nodiscard]] inline auto GetDescription() const -> std::string {
    return wrapped->description(); return wrapped->description();
    } }
    ...@@ -62,6 +274,7 @@ public: ...@@ -62,6 +274,7 @@ public:
    // friend class Parent; // friend class Parent;
    // friend class Property; // friend class Property;
    friend class Messages; friend class Messages;
    friend class RepeatedPtrFieldWrapper<Message, ProtoMessage>;
    private: private:
    explicit inline Message(ProtoMessage *wrapped) : wrapped(wrapped){}; explicit inline Message(ProtoMessage *wrapped) : wrapped(wrapped){};
    ...@@ -72,12 +285,9 @@ private: ...@@ -72,12 +285,9 @@ private:
    /** /**
    * Container for Messages. * Container for Messages.
    */ */
    class Messages { class Messages : public RepeatedPtrFieldWrapper<Message, ProtoMessage> {
    public: public:
    [[nodiscard]] inline auto Size() const -> int { return wrapped->size(); } ~Messages();
    [[nodiscard]] inline auto At(int index) const -> const Message {
    return Message(&(wrapped->at(index)));
    }
    friend class Entity; friend class Entity;
    // TODO(fspreck) Same here. // TODO(fspreck) Same here.
    ...@@ -85,9 +295,7 @@ public: ...@@ -85,9 +295,7 @@ public:
    // friend class Property; // friend class Property;
    private: private:
    inline Messages() : wrapped(nullptr){}; inline Messages() : RepeatedPtrFieldWrapper(){};
    ::google::protobuf::RepeatedPtrField<ProtoMessage> *wrapped;
    }; };
    /** /**
    ...@@ -166,6 +374,7 @@ public: ...@@ -166,6 +374,7 @@ public:
    friend class Entity; friend class Entity;
    friend class Parents; friend class Parents;
    friend class RepeatedPtrFieldWrapper<Parent, ProtoParent>;
    private: private:
    /** /**
    ...@@ -194,40 +403,17 @@ private: ...@@ -194,40 +403,17 @@ private:
    * *
    * Should only be instantiated and write-accessed by the owning entity. * Should only be instantiated and write-accessed by the owning entity.
    */ */
    class Parents { class Parents : public RepeatedPtrFieldWrapper<Parent, ProtoParent> {
    public: public:
    /** ~Parents() = default;
    * Return the current size of the parent container.
    *
    * That is also the number of parents the owning entity currently has.
    */
    [[nodiscard]] inline auto Size() const -> int { return wrapped->size(); }
    /**
    * Return the parent at the given index.
    */
    [[nodiscard]] inline auto At(int index) const -> const Parent {
    return Parent(&(wrapped->at(index)));
    }
    friend class Entity; friend class Entity;
    private: private:
    inline Parents(){}; inline Parents() : RepeatedPtrFieldWrapper(){};
    explicit inline Parents( explicit inline Parents(
    ::google::protobuf::RepeatedPtrField<ProtoParent> *wrapped) ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Parent>
    : wrapped(wrapped){}; *wrapped)
    : RepeatedPtrFieldWrapper(wrapped){};
    /**
    * Append a parent.
    *
    * This increases the Size() by one.
    */
    auto Append(const Parent &parent) -> void;
    /**
    * The collection of parent messages which serves as a backend for this
    * class.
    */
    ::google::protobuf::RepeatedPtrField<ProtoParent> *wrapped;
    }; };
    /** /**
    ...@@ -320,6 +506,7 @@ public: ...@@ -320,6 +506,7 @@ public:
    friend class Entity; friend class Entity;
    friend class Properties; friend class Properties;
    friend class RepeatedPtrFieldWrapper<Property, ProtoProperty>;
    private: private:
    static auto CreateProtoProperty() -> ProtoProperty *; static auto CreateProtoProperty() -> ProtoProperty *;
    ...@@ -332,37 +519,20 @@ private: ...@@ -332,37 +519,20 @@ private:
    * *
    * Should only be instantiated and write-accessed by the owning entity. * Should only be instantiated and write-accessed by the owning entity.
    */ */
    class Properties { class Properties
    : public RepeatedPtrFieldWrapper<Property,
    caosdb::entity::v1alpha1::Property> {
    public: public:
    /** ~Properties() = default;
    * Return the current size of the properties container.
    *
    * This is also the number of properties the owningn entity currently has.
    */
    [[nodiscard]] inline auto Size() const -> int { return wrapped->size(); }
    /**
    * Return the property at the given index.
    */
    [[nodiscard]] auto At(int index) const -> const Property {
    return Property(&(wrapped->at(index)));
    }
    friend class Entity; friend class Entity;
    private: private:
    inline Properties(){}; inline Properties(){};
    explicit inline Properties( explicit inline Properties(
    ::google::protobuf::RepeatedPtrField<ProtoProperty> *wrapped) ::google::protobuf::RepeatedPtrField<caosdb::entity::v1alpha1::Property>
    : wrapped(wrapped){}; *wrapped)
    : RepeatedPtrFieldWrapper<Property, caosdb::entity::v1alpha1::Property>(
    /** wrapped){};
    * Append a property
    *
    * This increases the Size() by one.
    */
    auto Append(const Property &property) -> void;
    ::google::protobuf::RepeatedPtrField<ProtoProperty> *wrapped;
    }; };
    /** /**
    ...@@ -375,12 +545,18 @@ public: ...@@ -375,12 +545,18 @@ public:
    this->wrapped->CopyFrom(*original.wrapped); this->wrapped->CopyFrom(*original.wrapped);
    }; };
    explicit Entity(IdResponse *idResponse); explicit Entity(IdResponse *idResponse);
    explicit inline Entity(ProtoEntity *wrapped) : wrapped(wrapped) { explicit Entity(ProtoEntity *wrapped) : wrapped(wrapped) {
    errors.wrapped = this->wrapped->mutable_errors();
    warnings.wrapped = this->wrapped->mutable_warnings();
    infos.wrapped = this->wrapped->mutable_infos();
    properties.wrapped = this->wrapped->mutable_properties(); properties.wrapped = this->wrapped->mutable_properties();
    parents.wrapped = this->wrapped->mutable_parents(); parents.wrapped = this->wrapped->mutable_parents();
    errors.wrapped = CreateMessagesField();
    warnings.wrapped = CreateMessagesField();
    infos.wrapped = CreateMessagesField();
    };
    explicit inline Entity(EntityResponse *response)
    : Entity(response->release_entity()) {
    errors.wrapped->Swap(response->mutable_errors());
    warnings.wrapped->Swap(response->mutable_warnings());
    infos.wrapped->Swap(response->mutable_infos());
    }; };
    [[nodiscard]] inline auto GetId() const noexcept -> const std::string & { [[nodiscard]] inline auto GetId() const noexcept -> const std::string & {
    ...@@ -448,18 +624,80 @@ public: ...@@ -448,18 +624,80 @@ public:
    auto SetUnit(const std::string &unit) -> void; auto SetUnit(const std::string &unit) -> void;
    // Currently no references or lists. // Currently no references or lists.
    auto SetDatatype(const std::string &datatype) -> void; auto SetDatatype(const std::string &datatype) -> void;
    auto AppendProperty(const Property &property) -> void; auto AppendProperty(const Property &property) -> void;
    auto RemoveProperty(int index) -> void;
    auto AppendParent(const Parent &parent) -> void; auto AppendParent(const Parent &parent) -> void;
    auto RemoveParent(int index) -> void;
    /** /**
    * Copy all of this entity's features to the target ProtoEntity. * Copy all of this entity's features to the target ProtoEntity.
    */ */
    auto CopyTo(ProtoEntity *target) -> void; auto CopyTo(ProtoEntity *target) -> void;
    protected: auto SetFilePath(const std::string &path) -> void;
    inline auto HasFile() const -> bool {
    return !this->file_descriptor.local_path.empty();
    }
    auto SetFileTransmissionRegistrationId(const std::string &registration_id)
    -> void;
    inline auto SetFileTransmissionId(FileTransmissionId *file_transmission_id)
    -> void {
    file_transmission_id->set_file_id(GetNextFileId());
    file_descriptor.file_transmission_id = file_transmission_id;
    }
    inline auto GetFileDescriptor() -> FileDescriptor & {
    return this->file_descriptor;
    }
    inline auto GetLocalPath() const noexcept -> const boost::filesystem::path & {
    return this->file_descriptor.local_path;
    }
    inline auto SetLocalPath(const boost::filesystem::path &local_path) noexcept
    -> StatusCode {
    if (GetRole() != "File") {
    CAOSDB_LOG_WARN(logger_name)
    << "Entity::SetLocalPath failed. This is not a file entity.";
    return StatusCode::NOT_A_FILE_ENTITY;
    }
    if (!exists(local_path)) {
    CAOSDB_LOG_WARN(logger_name)
    << "Entity::SetLocalPath failed. This file does not exists: "
    << local_path.string();
    return StatusCode::FILE_DOES_NOT_EXIST_LOCALLY;
    }
    if (is_directory(local_path)) {
    CAOSDB_LOG_WARN(logger_name)
    << "Entity::SetLocalPath failed. This file is a directory: "
    << local_path.string();
    return StatusCode::PATH_IS_A_DIRECTORY;
    }
    CAOSDB_LOG_TRACE(logger_name)
    << "Entity::SetLocalPath(" << local_path.string() << ");";
    this->file_descriptor.local_path = local_path;
    return StatusCode::SUCCESS;
    }
    private:
    inline auto GetNextFileId() -> std::string {
    std::string str = "0123456789abcdef";
    std::mt19937 generator(std::random_device{}());
    std::uniform_int_distribution<int> distribution(0, str.size() - 1);
    std::string result(10, '\0');
    for (auto &dis : result) {
    dis = str[distribution(generator)];
    }
    return result;
    }
    static auto CreateProtoEntity() -> ProtoEntity *; static auto CreateProtoEntity() -> ProtoEntity *;
    static auto CreateMessagesField() -> RepeatedPtrField<ProtoMessage> *;
    auto SetId(const std::string &id) -> void; auto SetId(const std::string &id) -> void;
    auto SetVersionId(const std::string &id) -> void; auto SetVersionId(const std::string &id) -> void;
    FileDescriptor file_descriptor;
    ProtoEntity *wrapped; ProtoEntity *wrapped;
    Properties properties; Properties properties;
    Parents parents; Parents parents;
    ......
    /*
    * This file is a part of the CaosDB Project.
    * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
    * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
    *
    * This program is free software: you can redistribute it and/or modify
    * it under the terms of the GNU Affero General Public License as
    * published by the Free Software Foundation, either version 3 of the
    * License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU Affero General Public License for more details.
    *
    * You should have received a copy of the GNU Affero General Public License
    * along with this program. If not, see <https://www.gnu.org/licenses/>.
    *
    *********************************************************************************
    *
    * This is derived work which is heavily based on
    * https://github.com/NeiRo21/grpcpp-bidi-streaming, Commit
    * cd9cb78e5d6d72806c2ec4c703e5e856b223dc96, Aug 10, 2020
    *
    * The orginal work is licensed as
    *
    * > MIT License
    * >
    * > Copyright (c) 2019 NeiRo21
    * >
    * > Permission is hereby granted, free of charge, to any person obtaining a
    * > copy of this software and associated documentation files (the "Software"),
    * > to deal in the Software without restriction, including without limitation
    * > the rights to use, copy, modify, merge, publish, distribute, sublicense,
    * > and/or sell copies of the Software, and to permit persons to whom the
    * > Software is furnished to do so, subject to the following conditions:
    * >
    * > The above copyright notice and this permission notice shall be included in
    * > all copies or substantial portions of the Software.
    * >
    * > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    * > DEALINGS IN THE SOFTWARE.
    */
    #ifndef CAOSDB_FILE_TRANSMISSION_DOWNLOAD_REQUEST_HANDLER_H
    #define CAOSDB_FILE_TRANSMISSION_DOWNLOAD_REQUEST_HANDLER_H
    #include "caosdb/entity.h" // for FileDescriptor
    #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for FileTransmissionS...
    #include "caosdb/entity/v1alpha1/main.pb.h" // for FileDownloadResponse
    #include "caosdb/file_transmission/file_writer.h" // for FileWriter
    #include "caosdb/handler_interface.h" // for HandlerTag, Handl...
    #include <grpcpp/impl/codegen/async_stream.h> // for ClientAsyncReader
    #include <grpcpp/impl/codegen/client_context.h> // for ClientContext
    #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue
    #include <grpcpp/impl/codegen/status.h> // for Status
    #include <memory> // for unique_ptr
    namespace caosdb::transaction {
    using caosdb::entity::FileDescriptor;
    using caosdb::entity::v1alpha1::FileDownloadRequest;
    using caosdb::entity::v1alpha1::FileDownloadResponse;
    using caosdb::entity::v1alpha1::FileTransmissionService;
    using caosdb::transaction::HandlerInterface;
    using caosdb::transaction::HandlerTag;
    /*
    * Handler for the download request of a single file
    */
    class DownloadRequestHandler final : public HandlerInterface {
    public:
    DownloadRequestHandler(HandlerTag tag, FileTransmissionService::Stub *stub,
    grpc::CompletionQueue *cq,
    FileDescriptor file_descriptor);
    ~DownloadRequestHandler() override = default;
    DownloadRequestHandler(const DownloadRequestHandler &) = delete;
    DownloadRequestHandler &operator=(const DownloadRequestHandler &) = delete;
    DownloadRequestHandler(DownloadRequestHandler &&) = delete;
    DownloadRequestHandler &operator=(DownloadRequestHandler &&) = delete;
    void Start() override { OnNext(true); }
    bool OnNext(bool ok) override;
    void Cancel() override;
    protected:
    enum class CallState { NewCall, SendingRequest, ReceivingFile, CallComplete };
    void handleNewCallState();
    void handleSendingRequestState();
    void handleReceivingFileState();
    void handleCallCompleteState();
    HandlerTag tag_;
    FileTransmissionService::Stub *stub_;
    grpc::CompletionQueue *cq_;
    grpc::ClientContext ctx_;
    std::unique_ptr<grpc::ClientAsyncReader<FileDownloadResponse>> rpc_;
    FileDownloadRequest *request_;
    FileDownloadResponse *response_;
    grpc::Status status_;
    CallState state_;
    std::unique_ptr<FileWriter> fileWriter_;
    FileDescriptor file_descriptor_;
    unsigned long long bytesReceived_;
    };
    } // namespace caosdb::transaction
    #endif
    /*
    * This file is a part of the CaosDB Project.
    * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
    * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
    *
    * This program is free software: you can redistribute it and/or modify
    * it under the terms of the GNU Affero General Public License as
    * published by the Free Software Foundation, either version 3 of the
    * License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU Affero General Public License for more details.
    *
    * You should have received a copy of the GNU Affero General Public License
    * along with this program. If not, see <https://www.gnu.org/licenses/>.
    *
    *********************************************************************************
    *
    * This is derived work which is heavily based on
    * https://github.com/NeiRo21/grpcpp-bidi-streaming, Commit
    * cd9cb78e5d6d72806c2ec4c703e5e856b223dc96, Aug 10, 2020
    *
    * The orginal work is licensed as
    *
    * > MIT License
    * >
    * > Copyright (c) 2019 NeiRo21
    * >
    * > Permission is hereby granted, free of charge, to any person obtaining a
    * > copy of this software and associated documentation files (the "Software"),
    * > to deal in the Software without restriction, including without limitation
    * > the rights to use, copy, modify, merge, publish, distribute, sublicense,
    * > and/or sell copies of the Software, and to permit persons to whom the
    * > Software is furnished to do so, subject to the following conditions:
    * >
    * > The above copyright notice and this permission notice shall be included in
    * > all copies or substantial portions of the Software.
    * >
    * > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    * > DEALINGS IN THE SOFTWARE.
    */
    #ifndef CAOSDB_FILE_TRANSMISSION_FILE_ERROR_H
    #define CAOSDB_FILE_TRANSMISSION_FILE_ERROR_H
    #include <stdexcept>
    #include <string>
    namespace caosdb::transaction {
    class FileIOError : public std::runtime_error {
    public:
    FileIOError(const std::string &message) : std::runtime_error(message) {}
    };
    } // namespace caosdb::transaction
    #endif
    /*
    * This file is a part of the CaosDB Project.
    * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
    * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
    *
    * This program is free software: you can redistribute it and/or modify
    * it under the terms of the GNU Affero General Public License as
    * published by the Free Software Foundation, either version 3 of the
    * License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU Affero General Public License for more details.
    *
    * You should have received a copy of the GNU Affero General Public License
    * along with this program. If not, see <https://www.gnu.org/licenses/>.
    *
    *********************************************************************************
    *
    * This is derived work which is heavily based on
    * https://github.com/NeiRo21/grpcpp-bidi-streaming, Commit
    * cd9cb78e5d6d72806c2ec4c703e5e856b223dc96, Aug 10, 2020
    *
    * The orginal work is licensed as
    *
    * > MIT License
    * >
    * > Copyright (c) 2019 NeiRo21
    * >
    * > Permission is hereby granted, free of charge, to any person obtaining a
    * > copy of this software and associated documentation files (the "Software"),
    * > to deal in the Software without restriction, including without limitation
    * > the rights to use, copy, modify, merge, publish, distribute, sublicense,
    * > and/or sell copies of the Software, and to permit persons to whom the
    * > Software is furnished to do so, subject to the following conditions:
    * >
    * > The above copyright notice and this permission notice shall be included in
    * > all copies or substantial portions of the Software.
    * >
    * > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    * > DEALINGS IN THE SOFTWARE.
    */
    #ifndef CAOSDB_FILE_TRANSMISSION_FILE_READER_H
    #define CAOSDB_FILE_TRANSMISSION_FILE_READER_H
    #include <boost/filesystem/fstream.hpp> // for ifstream
    #include <boost/filesystem/operations.hpp> // for exists
    #include <boost/filesystem/path.hpp> // for path
    #include <fstream> // for ifstream, size_t
    #include <string> // for string
    namespace caosdb::transaction {
    using boost::filesystem::exists;
    using boost::filesystem::ifstream;
    using boost::filesystem::path;
    class FileReader final {
    public:
    FileReader(boost::filesystem::path filename);
    ~FileReader() = default;
    FileReader(const FileReader &) = delete;
    FileReader &operator=(const FileReader &) = delete;
    FileReader(FileReader &&) = default;
    FileReader &operator=(FileReader &&) = default;
    unsigned long long fileSize() const { return size_; }
    std::size_t read(std::string &buffer);
    private:
    void openFile();
    std::ifstream stream_;
    boost::filesystem::path filename_;
    unsigned long long size_;
    };
    } // namespace caosdb::transaction
    #endif
    /*
    * This file is a part of the CaosDB Project.
    * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
    * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
    *
    * This program is free software: you can redistribute it and/or modify
    * it under the terms of the GNU Affero General Public License as
    * published by the Free Software Foundation, either version 3 of the
    * License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU Affero General Public License for more details.
    *
    * You should have received a copy of the GNU Affero General Public License
    * along with this program. If not, see <https://www.gnu.org/licenses/>.
    *
    *********************************************************************************
    *
    * This is derived work which is heavily based on
    * https://github.com/NeiRo21/grpcpp-bidi-streaming, Commit
    * cd9cb78e5d6d72806c2ec4c703e5e856b223dc96, Aug 10, 2020
    *
    * The orginal work is licensed as
    *
    * > MIT License
    * >
    * > Copyright (c) 2019 NeiRo21
    * >
    * > Permission is hereby granted, free of charge, to any person obtaining a
    * > copy of this software and associated documentation files (the "Software"),
    * > to deal in the Software without restriction, including without limitation
    * > the rights to use, copy, modify, merge, publish, distribute, sublicense,
    * > and/or sell copies of the Software, and to permit persons to whom the
    * > Software is furnished to do so, subject to the following conditions:
    * >
    * > The above copyright notice and this permission notice shall be included in
    * > all copies or substantial portions of the Software.
    * >
    * > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    * > DEALINGS IN THE SOFTWARE.
    */
    #ifndef CAOSDB_FILE_TRANSMISSION_FILE_WRITER_H
    #define CAOSDB_FILE_TRANSMISSION_FILE_WRITER_H
    #include <boost/filesystem/path.hpp> // for path
    #include <fstream> // for ofstream
    #include <string> // for string
    namespace caosdb::transaction {
    class FileWriter final {
    public:
    FileWriter(boost::filesystem::path filename);
    ~FileWriter() = default;
    FileWriter(const FileWriter &) = delete;
    FileWriter &operator=(const FileWriter &) = delete;
    FileWriter(FileWriter &&) = default;
    FileWriter &operator=(FileWriter &&) = default;
    void write(const std::string &buffer);
    private:
    void openFile();
    std::ofstream stream_;
    boost::filesystem::path filename_;
    };
    } // namespace caosdb::transaction
    #endif
    /*
    * This file is a part of the CaosDB Project.
    * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
    * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
    *
    * This program is free software: you can redistribute it and/or modify
    * it under the terms of the GNU Affero General Public License as
    * published by the Free Software Foundation, either version 3 of the
    * License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU Affero General Public License for more details.
    *
    * You should have received a copy of the GNU Affero General Public License
    * along with this program. If not, see <https://www.gnu.org/licenses/>.
    *
    *********************************************************************************
    *
    * This is derived work which is heavily based on
    * https://github.com/NeiRo21/grpcpp-bidi-streaming, Commit
    * cd9cb78e5d6d72806c2ec4c703e5e856b223dc96, Aug 10, 2020
    *
    * The orginal work is licensed as
    *
    * > MIT License
    * >
    * > Copyright (c) 2019 NeiRo21
    * >
    * > Permission is hereby granted, free of charge, to any person obtaining a
    * > copy of this software and associated documentation files (the "Software"),
    * > to deal in the Software without restriction, including without limitation
    * > the rights to use, copy, modify, merge, publish, distribute, sublicense,
    * > and/or sell copies of the Software, and to permit persons to whom the
    * > Software is furnished to do so, subject to the following conditions:
    * >
    * > The above copyright notice and this permission notice shall be included in
    * > all copies or substantial portions of the Software.
    * >
    * > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    * > DEALINGS IN THE SOFTWARE.
    */
    #ifndef CAOSDB_FILE_TRANSMISSION_REGISTER_FILE_UPLOAD_H
    #define CAOSDB_FILE_TRANSMISSION_REGISTER_FILE_UPLOAD_H
    #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for FileTransmissionS...
    #include "caosdb/entity/v1alpha1/main.pb.h" // for FileDownloadResponse
    #include "caosdb/handler_interface.h" // for HandlerTag, Handl...
    #include "caosdb/unary_rpc_handler.h"
    #include <grpcpp/impl/codegen/async_unary_call.h> // for ClientAsyncRespons...
    #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue
    #include <memory> // for unique_ptr
    namespace caosdb::transaction {
    using caosdb::entity::v1alpha1::FileTransmissionService;
    using caosdb::entity::v1alpha1::RegisterFileUploadRequest;
    using caosdb::entity::v1alpha1::RegisterFileUploadResponse;
    class RegisterFileUploadHandler final : public UnaryRpcHandler {
    public:
    RegisterFileUploadHandler(HandlerTag tag, FileTransmissionService::Stub *stub,
    grpc::CompletionQueue *completion_queue,
    RegisterFileUploadRequest *request,
    RegisterFileUploadResponse *response);
    ~RegisterFileUploadHandler();
    RegisterFileUploadHandler(const RegisterFileUploadHandler &) = delete;
    RegisterFileUploadHandler &
    operator=(const RegisterFileUploadHandler &) = delete;
    RegisterFileUploadHandler(RegisterFileUploadHandler &&) = delete;
    RegisterFileUploadHandler &operator=(RegisterFileUploadHandler &&) = delete;
    protected:
    void handleNewCallState() override;
    HandlerTag tag_;
    FileTransmissionService::Stub *stub_;
    std::unique_ptr<grpc::ClientAsyncResponseReader<RegisterFileUploadResponse>>
    rpc_;
    RegisterFileUploadRequest *request_;
    RegisterFileUploadResponse *response_;
    };
    } // namespace caosdb::transaction
    #endif
    /*
    * This file is a part of the CaosDB Project.
    * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
    * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
    *
    * This program is free software: you can redistribute it and/or modify
    * it under the terms of the GNU Affero General Public License as
    * published by the Free Software Foundation, either version 3 of the
    * License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU Affero General Public License for more details.
    *
    * You should have received a copy of the GNU Affero General Public License
    * along with this program. If not, see <https://www.gnu.org/licenses/>.
    *
    *********************************************************************************
    *
    * This is derived work which is heavily based on
    * https://github.com/NeiRo21/grpcpp-bidi-streaming, Commit
    * cd9cb78e5d6d72806c2ec4c703e5e856b223dc96, Aug 10, 2020
    *
    * The orginal work is licensed as
    *
    * > MIT License
    * >
    * > Copyright (c) 2019 NeiRo21
    * >
    * > Permission is hereby granted, free of charge, to any person obtaining a
    * > copy of this software and associated documentation files (the "Software"),
    * > to deal in the Software without restriction, including without limitation
    * > the rights to use, copy, modify, merge, publish, distribute, sublicense,
    * > and/or sell copies of the Software, and to permit persons to whom the
    * > Software is furnished to do so, subject to the following conditions:
    * >
    * > The above copyright notice and this permission notice shall be included in
    * > all copies or substantial portions of the Software.
    * >
    * > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    * > DEALINGS IN THE SOFTWARE.
    */
    #ifndef CAOSDB_FILE_TRANSMISSION_UPLOAD_REQUEST_HANDLER_H
    #define CAOSDB_FILE_TRANSMISSION_UPLOAD_REQUEST_HANDLER_H
    #include "caosdb/entity.h" // for FileDescriptor
    #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for FileTransmissionS...
    #include "caosdb/entity/v1alpha1/main.pb.h" // for FileUploadRequest
    #include "caosdb/file_transmission/file_reader.h" // for FileReader
    #include "caosdb/handler_interface.h" // for HandlerTag, Handl...
    #include <cstdint> // for uint64_t
    #include <grpcpp/impl/codegen/async_stream.h> // for ClientAsyncWriter
    #include <grpcpp/impl/codegen/client_context.h> // for ClientContext
    #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue
    #include <grpcpp/impl/codegen/status.h> // for Status
    #include <memory> // for unique_ptr
    namespace caosdb::transaction {
    using caosdb::entity::FileDescriptor;
    using caosdb::entity::v1alpha1::FileTransmissionService;
    using caosdb::entity::v1alpha1::FileUploadRequest;
    using caosdb::entity::v1alpha1::FileUploadResponse;
    using caosdb::transaction::HandlerInterface;
    using caosdb::transaction::HandlerTag;
    class UploadRequestHandler final : public HandlerInterface {
    public:
    UploadRequestHandler(HandlerTag tag, FileTransmissionService::Stub *stub,
    grpc::CompletionQueue *cq,
    FileDescriptor file_descriptor);
    ~UploadRequestHandler() override = default;
    UploadRequestHandler(const UploadRequestHandler &) = delete;
    UploadRequestHandler &operator=(const UploadRequestHandler &) = delete;
    UploadRequestHandler(UploadRequestHandler &&) = delete;
    UploadRequestHandler &operator=(UploadRequestHandler &&) = delete;
    void Start() override { OnNext(true); }
    bool OnNext(bool ok) override;
    void Cancel() override;
    protected:
    enum class CallState {
    NewCall,
    SendingHeader,
    SendingFile,
    ExpectingResponse,
    CallComplete
    };
    void handleNewCallState();
    void handleSendingHeaderState();
    void handleSendingFileState();
    void handleExpectingResponseState();
    void handleCallCompleteState();
    HandlerTag tag_;
    FileTransmissionService::Stub *stub_;
    grpc::CompletionQueue *cq_;
    grpc::ClientContext ctx_;
    std::unique_ptr<grpc::ClientAsyncWriter<FileUploadRequest>> rpc_;
    FileUploadRequest *request_;
    FileUploadResponse *response_;
    grpc::Status status_;
    CallState state_;
    std::unique_ptr<FileReader> fileReader_;
    FileDescriptor file_descriptor_;
    uint64_t bytesToSend_;
    };
    } // namespace caosdb::transaction
    #endif
    /*
    * This file is a part of the CaosDB Project.
    * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
    * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
    *
    * This program is free software: you can redistribute it and/or modify
    * it under the terms of the GNU Affero General Public License as
    * published by the Free Software Foundation, either version 3 of the
    * License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU Affero General Public License for more details.
    *
    * You should have received a copy of the GNU Affero General Public License
    * along with this program. If not, see <https://www.gnu.org/licenses/>.
    *
    *********************************************************************************
    *
    * This is derived work which is heavily based on
    * https://github.com/NeiRo21/grpcpp-bidi-streaming, Commit
    * cd9cb78e5d6d72806c2ec4c703e5e856b223dc96, Aug 10, 2020
    *
    * The orginal work is licensed as
    *
    * > MIT License
    * >
    * > Copyright (c) 2019 NeiRo21
    * >
    * > Permission is hereby granted, free of charge, to any person obtaining a
    * > copy of this software and associated documentation files (the "Software"),
    * > to deal in the Software without restriction, including without limitation
    * > the rights to use, copy, modify, merge, publish, distribute, sublicense,
    * > and/or sell copies of the Software, and to permit persons to whom the
    * > Software is furnished to do so, subject to the following conditions:
    * >
    * > The above copyright notice and this permission notice shall be included in
    * > all copies or substantial portions of the Software.
    * >
    * > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    * > DEALINGS IN THE SOFTWARE.
    */
    #ifndef CAOSDB_HANDLER_INTERFACE_H
    #define CAOSDB_HANDLER_INTERFACE_H
    #include "caosdb/transaction_status.h" // for TransactionStatus
    #include <memory>
    #include <string>
    namespace caosdb::transaction {
    const static std::string logger_name = "caosdb::transaction";
    /*
    * Baseclass for UnaryRpcHandler, DownloadRequestHandler and
    * UploadRequestHandler
    *
    * It handles a request: Its status is contained in the transaction_status
    * member variable and the functions Start, OnNext and Cancel need to be
    * overwritten by child classes.
    */
    class HandlerInterface {
    public:
    HandlerInterface() : transaction_status(TransactionStatus::READY()) {}
    virtual ~HandlerInterface() = default;
    virtual void Start() = 0;
    /*
    * ok indicates whether the current request is in a good state or not. If
    * ok is false, the request will be ended.
    *
    * returns false if the handler is done
    */
    virtual bool OnNext(bool ok) = 0;
    virtual void Cancel() = 0;
    inline TransactionStatus GetStatus() { return this->transaction_status; }
    protected:
    TransactionStatus transaction_status;
    };
    using HandlerPtr = std::unique_ptr<HandlerInterface>;
    using HandlerTag = HandlerPtr *;
    } // namespace caosdb::transaction
    #endif
    ...@@ -22,7 +22,15 @@ ...@@ -22,7 +22,15 @@
    #ifndef CAOSDB_PROTOBUF_HELPER_H #ifndef CAOSDB_PROTOBUF_HELPER_H
    #define CAOSDB_PROTOBUF_HELPER_H #define CAOSDB_PROTOBUF_HELPER_H
    #include <google/protobuf/arena.h> #include <google/protobuf/arena.h> // for Arena
    #include <google/protobuf/extension_set.h> // for Arena
    #define CAOSDB_DEBUG_MESSAGE_STRING(message, out) \
    std::string out; \
    { \
    google::protobuf::util::JsonOptions options; \
    google::protobuf::util::MessageToJsonString(message, &out, options); \
    }
    namespace caosdb::utility { namespace caosdb::utility {
    ......
    ...@@ -41,6 +41,7 @@ enum StatusCode { ...@@ -41,6 +41,7 @@ enum StatusCode {
    INITIAL = -2, INITIAL = -2,
    EXECUTING = -1, EXECUTING = -1,
    SUCCESS = 0, SUCCESS = 0,
    // TODO(tf) Map other GRPC errors
    AUTHENTICATION_ERROR = 16, AUTHENTICATION_ERROR = 16,
    CONNECTION_ERROR = 14, CONNECTION_ERROR = 14,
    GENERIC_RPC_ERROR = 20, GENERIC_RPC_ERROR = 20,
    ...@@ -52,6 +53,13 @@ enum StatusCode { ...@@ -52,6 +53,13 @@ enum StatusCode {
    TRANSACTION_TYPE_ERROR = 26, TRANSACTION_TYPE_ERROR = 26,
    UNSUPPORTED_FEATURE = 27, UNSUPPORTED_FEATURE = 27,
    ORIGINAL_ENTITY_MISSING_ID = 28, ORIGINAL_ENTITY_MISSING_ID = 28,
    EXTERN_C_ASSIGNMENT_ERROR = 29,
    PATH_IS_A_DIRECTORY = 30,
    FILE_DOES_NOT_EXIST_LOCALLY = 31,
    FILE_UPLOAD_ERROR = 32,
    FILE_DOWNLOAD_ERROR = 33,
    NOT_A_FILE_ENTITY = 34,
    OTHER_CLIENT_ERROR = 9999,
    }; };
    auto get_status_description(int code) -> const std::string &; auto get_status_description(int code) -> const std::string &;
    ......
    ...@@ -20,23 +20,30 @@ ...@@ -20,23 +20,30 @@
    */ */
    #ifndef CAOSDB_TRANSACTION_H #ifndef CAOSDB_TRANSACTION_H
    #define CAOSDB_TRANSACTION_H #define CAOSDB_TRANSACTION_H
    #include "boost/log/core/record.hpp" // for record
    #include "boost/log/sources/record_ostream.hpp" // for basic_record_o... #include "caosdb/entity.h" // for Entity, FileDe...
    #include "boost/preprocessor/seq/limits/enum_256.hpp" // for BOOST_PP_SEQ_E... #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransact...
    #include "boost/preprocessor/seq/limits/size_256.hpp" // for BOOST_PP_SEQ_S... #include "caosdb/entity/v1alpha1/main.pb.h" // for MultiTransacti...
    #include "caosdb/entity.h" // for Entity #include "caosdb/handler_interface.h" // for HandlerInterface
    #include "caosdb/logging.h" #include "caosdb/transaction_handler.h" // for EntityTransactionHandler
    #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe... #include "caosdb/logging.h" // for CAOSDB_LOG_ERR...
    #include "caosdb/entity/v1alpha1/main.pb.h" // for Entity, RetrieveReq... #include "caosdb/protobuf_helper.h" // for get_arena
    #include "caosdb/transaction_status.h" // for TransactionStatus
    #include "caosdb/status_code.h" // for StatusCode #include "caosdb/status_code.h" // for StatusCode
    #include "google/protobuf/util/json_util.h" // for MessageToJsonString, Jso... #include "caosdb/transaction_status.h" // for StatusCode
    #include <iterator> #include <boost/log/core/record.hpp> // for record
    #include <boost/log/sources/record_ostream.hpp> // for basic_record_o...
    #include <boost/preprocessor/seq/limits/enum_256.hpp> // for BOOST_PP_SEQ_E...
    #include <boost/preprocessor/seq/limits/size_256.hpp> // for BOOST_PP_SEQ_S...
    #include <google/protobuf/arena.h> // for Arena
    #include <google/protobuf/util/json_util.h> // for MessageToJsonS...
    #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue
    #include <iterator> // for iterator, next
    #include <map> // for map
    // IWYU pragma: no_include <ext/alloc_traits.h> // IWYU pragma: no_include <ext/alloc_traits.h>
    #include <memory> // for shared_ptr, unique_ptr #include <memory> // for unique_ptr
    #include <stdexcept> #include <string> // for string
    #include <string> // for string #include <utility> // for move
    #include <vector> // for vector #include <vector> // for vector
    /** /**
    * Do all necessary checks and assure that another retrieval (by id or by * Do all necessary checks and assure that another retrieval (by id or by
    ...@@ -158,19 +165,28 @@ ...@@ -158,19 +165,28 @@
    */ */
    namespace caosdb::transaction { namespace caosdb::transaction {
    using caosdb::entity::Entity; using caosdb::entity::Entity;
    using ProtoEntity = caosdb::entity::v1alpha1::Entity; using caosdb::entity::FileDescriptor;
    using caosdb::entity::v1alpha1::EntityResponse;
    using caosdb::entity::v1alpha1::EntityTransactionService; using caosdb::entity::v1alpha1::EntityTransactionService;
    using caosdb::entity::v1alpha1::FileDownloadRequest;
    using caosdb::entity::v1alpha1::FileDownloadResponse;
    using caosdb::entity::v1alpha1::FileTransmissionId;
    using caosdb::entity::v1alpha1::FileTransmissionService;
    using caosdb::entity::v1alpha1::FileUploadRequest;
    using caosdb::entity::v1alpha1::FileUploadResponse;
    using caosdb::entity::v1alpha1::IdResponse; using caosdb::entity::v1alpha1::IdResponse;
    using caosdb::entity::v1alpha1::MultiTransactionRequest; using caosdb::entity::v1alpha1::MultiTransactionRequest;
    using caosdb::entity::v1alpha1::MultiTransactionResponse; using caosdb::entity::v1alpha1::MultiTransactionResponse;
    using caosdb::entity::v1alpha1::RegisterFileUploadRequest;
    using caosdb::entity::v1alpha1::RegisterFileUploadResponse;
    using caosdb::transaction::TransactionStatus; using caosdb::transaction::TransactionStatus;
    using WrappedResponseCase = using TransactionResponseCase =
    caosdb::entity::v1alpha1::TransactionResponse::WrappedResponseCase; caosdb::entity::v1alpha1::TransactionResponse::TransactionResponseCase;
    using caosdb::utility::get_arena;
    using google::protobuf::Arena;
    class Transaction; class Transaction;
    static const std::string logger_name = "caosdb::transaction";
    /** /**
    * Abstract base class for the results of a Transaction. * Abstract base class for the results of a Transaction.
    */ */
    ...@@ -179,8 +195,9 @@ class ResultSet { ...@@ -179,8 +195,9 @@ class ResultSet {
    public: public:
    virtual ~ResultSet() = default; virtual ~ResultSet() = default;
    [[nodiscard]] virtual auto Size() const noexcept -> int = 0; [[nodiscard]] virtual auto size() const noexcept -> int = 0;
    [[nodiscard]] virtual auto At(const int index) const -> const Entity & = 0; [[nodiscard]] virtual auto at(const int index) const -> const Entity & = 0;
    [[nodiscard]] virtual auto mutable_at(int index) const -> Entity * = 0;
    auto begin() const -> iterator; auto begin() const -> iterator;
    auto end() const -> iterator; auto end() const -> iterator;
    ...@@ -199,51 +216,34 @@ private: ...@@ -199,51 +216,34 @@ private:
    }; };
    }; };
    /** class AbstractMultiResultSet : public ResultSet {
    * Container with results of a transaction.
    *
    * In contrast to UniqueResult, this one can also hold multiple entities or zero
    * entities.
    */
    class MultiResultSet : public ResultSet {
    public: public:
    ~MultiResultSet() = default; virtual ~AbstractMultiResultSet() = default;
    explicit MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set); inline explicit AbstractMultiResultSet(
    [[nodiscard]] inline auto Size() const noexcept -> int override { std::vector<std::unique_ptr<Entity>> result_set)
    return this->entities.size(); : items(std::move(result_set)) {}
    [[nodiscard]] inline auto size() const noexcept -> int override {
    return this->items.size();
    } }
    [[nodiscard]] inline auto At(const int index) const [[nodiscard]] inline auto at(const int index) const
    -> const Entity & override { -> const Entity & override {
    return *(this->entities.at(index)); return *(this->items.at(index));
    }
    [[nodiscard]] inline auto mutable_at(int index) const -> Entity * override {
    return this->items.at(index).get();
    } }
    std::vector<std::unique_ptr<Entity>> entities;
    protected:
    std::vector<std::unique_ptr<Entity>> items;
    }; };
    /** /**
    * Container with the single result of a transaction. * Container with results of a transaction.
    *
    * In contrast to MultiResultSet, this one guarantees to hold exactly one
    * entity.
    */ */
    class UniqueResult : public ResultSet { class MultiResultSet : public AbstractMultiResultSet {
    public: public:
    ~UniqueResult() = default; ~MultiResultSet() = default;
    explicit inline UniqueResult(ProtoEntity *protoEntity) explicit MultiResultSet(std::vector<std::unique_ptr<Entity>> result_set);
    : entity(new Entity(protoEntity)){};
    explicit inline UniqueResult(IdResponse *idResponse)
    : entity(new Entity(idResponse)){};
    [[nodiscard]] auto GetEntity() const -> const Entity &;
    [[nodiscard]] inline auto Size() const noexcept -> int override { return 1; }
    [[nodiscard]] inline auto At(const int index) const
    -> const Entity & override {
    if (index != 0) {
    throw std::out_of_range("Index out of range. Length is 1.");
    }
    return *(this->entity);
    }
    private:
    std::unique_ptr<Entity> entity;
    }; };
    /** /**
    ...@@ -259,15 +259,36 @@ public: ...@@ -259,15 +259,36 @@ public:
    * yet. * yet.
    */ */
    enum TransactionType { enum TransactionType {
    NONE, /// Unspecified or not specified yet. NONE, //!< Unspecified or not specified yet.
    READ_ONLY, /// Only retrievals (by id, by query) READ_ONLY, //!< Only retrievals (by id, by query)
    INSERT, /// Only insertions INSERT, //!< Only insertions
    UPDATE, /// Only updates UPDATE, //!< Only updates
    DELETE, /// Only deletions DELETE, //!< Only deletions
    MIXED_WRITE, /// Only insertions, deletions, updates MIXED_WRITE, //!< Only insertions, deletions, updates
    MIXED_READ_AND_WRITE /// all kind of transaction. MIXED_READ_AND_WRITE //!< all kind of transaction.
    }; };
    Transaction(std::shared_ptr<EntityTransactionService::Stub> service_stub); Transaction(std::shared_ptr<EntityTransactionService::Stub> entity_service,
    std::shared_ptr<FileTransmissionService::Stub> file_service);
    ~Transaction();
    Transaction(const Transaction &) = delete;
    Transaction &operator=(const Transaction &) = delete;
    Transaction(Transaction &&) = delete;
    Transaction &operator=(Transaction &&) = delete;
    /**
    * Add an entity id to this transaction for retrieval and also download the
    * file.
    *
    * If the entity doesn't have a file a warning is appended.
    *
    * If the file cannot be downloaded due to unsufficient permissions an error
    * is appended.
    */
    auto RetrieveAndDownloadFilesById(const std::string &id,
    const std::string &local_path) noexcept
    -> StatusCode;
    /** /**
    * Add an entity id to this transaction for retrieval. * Add an entity id to this transaction for retrieval.
    ...@@ -348,13 +369,12 @@ public: ...@@ -348,13 +369,12 @@ public:
    /** /**
    * Return the current status of the transaction. * Return the current status of the transaction.
    */ */
    [[nodiscard]] inline auto GetStatus() const -> TransactionStatus { [[nodiscard]] inline auto GetStatus() const noexcept -> TransactionStatus {
    return this->status; return this->status;
    } }
    [[nodiscard]] inline auto GetResultSet() const -> const ResultSet & { [[nodiscard]] inline auto GetResultSet() const noexcept -> const ResultSet & {
    const ResultSet *result_set = this->result_set.get(); return *(this->result_set.get());
    return *result_set;
    } }
    /** /**
    ...@@ -364,7 +384,7 @@ public: ...@@ -364,7 +384,7 @@ public:
    * this transaction. In all other cases, the return value will be * this transaction. In all other cases, the return value will be
    * -1. * -1.
    */ */
    [[nodiscard]] inline auto GetCountResult() const -> long { [[nodiscard]] inline auto GetCountResult() const noexcept -> long {
    return query_count; return query_count;
    } }
    ...@@ -402,12 +422,58 @@ public: ...@@ -402,12 +422,58 @@ public:
    return out; return out;
    } }
    /**
    * Return the vector which holds all the files which are to be uploaded.
    */
    inline auto GetUploadFiles() const -> const std::vector<FileDescriptor> & {
    return upload_files;
    }
    protected:
    /**
    * Await and process the current handler's results.
    *
    * This implies consecutive calls to the handler's OnNext function.
    */
    auto ProcessCalls() -> TransactionStatus;
    /**
    * Cancels any active handler and drains the completion_queue.
    *
    * Can stay protected until ExecuteAsynchronously() is actually asynchronous.
    * Then it is also intended for aborting an execution after it has already
    * started.
    */
    auto Cancel() -> void;
    /**
    * Return the Arena where this transaction may create Message instances.
    *
    * Currently, this implementation is only a call to
    * caosdb::utility::get_arena(), but in the future we might want to have a
    * smarter memory management.
    */
    inline auto GetArena() const -> Arena * { return get_arena(); }
    private: private:
    grpc::CompletionQueue completion_queue;
    std::unique_ptr<HandlerInterface> handler_;
    std::vector<FileDescriptor> upload_files;
    std::map<std::string, FileDescriptor> download_files;
    // auto RegisterUploadFile(RegisterFileUploadResponse *response) -> void;
    auto UploadFile(FileUploadResponse *response,
    const FileDescriptor &file_descriptor,
    const std::string &registration_id) -> void;
    auto DownloadFile(FileDownloadResponse *response,
    const FileTransmissionId &file_transmission_id) -> void;
    bool has_query = false; bool has_query = false;
    TransactionType transaction_type = TransactionType::NONE; TransactionType transaction_type = TransactionType::NONE;
    mutable std::unique_ptr<ResultSet> result_set; mutable std::unique_ptr<ResultSet> result_set;
    mutable TransactionStatus status = TransactionStatus::INITIAL(); mutable TransactionStatus status = TransactionStatus::INITIAL();
    std::shared_ptr<EntityTransactionService::Stub> service_stub; std::shared_ptr<EntityTransactionService::Stub> entity_service;
    std::shared_ptr<FileTransmissionService::Stub> file_service;
    MultiTransactionRequest *request; MultiTransactionRequest *request;
    mutable MultiTransactionResponse *response; mutable MultiTransactionResponse *response;
    std::string error_message; std::string error_message;
    ......
    #pragma once
    #include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for FileTransmissionS...
    #include "caosdb/entity/v1alpha1/main.pb.h" // for FileDownloadResponse
    #include "caosdb/handler_interface.h" // for HandlerTag
    #include "caosdb/unary_rpc_handler.h" // for HandlerTag, Handl...
    #include <grpcpp/impl/codegen/async_unary_call.h> // for ClientAsyncRespons...
    #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue
    #include <memory> // for unique_ptr
    namespace caosdb::transaction {
    using caosdb::entity::v1alpha1::EntityTransactionService;
    using caosdb::entity::v1alpha1::MultiTransactionRequest;
    using caosdb::entity::v1alpha1::MultiTransactionResponse;
    class EntityTransactionHandler final : public UnaryRpcHandler {
    public:
    EntityTransactionHandler(HandlerTag tag, EntityTransactionService::Stub *stub,
    grpc::CompletionQueue *completion_queue,
    MultiTransactionRequest *request,
    MultiTransactionResponse *response);
    ~EntityTransactionHandler() override = default;
    EntityTransactionHandler(const EntityTransactionHandler &) = delete;
    EntityTransactionHandler &
    operator=(const EntityTransactionHandler &) = delete;
    EntityTransactionHandler(EntityTransactionHandler &&) = delete;
    EntityTransactionHandler &operator=(EntityTransactionHandler &&) = delete;
    protected:
    virtual void handleNewCallState() override;
    HandlerTag tag_;
    EntityTransactionService::Stub *stub_;
    std::unique_ptr<grpc::ClientAsyncResponseReader<MultiTransactionResponse>>
    rpc_;
    MultiTransactionRequest *request_;
    MultiTransactionResponse *response_;
    };
    } // namespace caosdb::transaction
    ...@@ -119,6 +119,22 @@ public: ...@@ -119,6 +119,22 @@ public:
    caosdb::get_status_description(StatusCode::AUTHENTICATION_ERROR) + caosdb::get_status_description(StatusCode::AUTHENTICATION_ERROR) +
    " Original error: " + details); " Original error: " + details);
    } }
    /**
    * Factory for a FILE_UPLOAD_ERROR status.
    *
    * This status means that the transaction failed during the upload of the
    * file blobs of file entities.
    */
    CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(FILE_UPLOAD_ERROR,
    StatusCode::FILE_UPLOAD_ERROR);
    /**
    * Factory for a FILE_DOWN_ERROR status.
    *
    * This status means that the transaction failed during the download of the
    * file blobs of file entities.
    */
    CAOSDB_TRANSACTION_STATUS_DEFAULT_FACTORY(FILE_DOWNLOAD_ERROR,
    StatusCode::FILE_DOWNLOAD_ERROR);
    /** /**
    * Factory for a TRANSACTION_ERROR status. * Factory for a TRANSACTION_ERROR status.
    * *
    ...@@ -154,6 +170,19 @@ public: ...@@ -154,6 +170,19 @@ public:
    " Original error: " + details); " Original error: " + details);
    } }
    /**
    * Factory for a GENERIC_ERROR status.
    *
    * This status means that the transaction failed due to errors which
    * supposedly do not have a special handling.
    */
    inline static auto GENERIC_ERROR(const std::string &details) {
    return TransactionStatus(
    StatusCode::GENERIC_ERROR,
    caosdb::get_status_description(StatusCode::GENERIC_ERROR) +
    "Original error: " + details);
    }
    inline auto ThrowExceptionIfError() const -> void { inline auto ThrowExceptionIfError() const -> void {
    TransactionStatus::ThrowExceptionIfError(this->code, this->description); TransactionStatus::ThrowExceptionIfError(this->code, this->description);
    } }
    ...@@ -176,7 +205,7 @@ public: ...@@ -176,7 +205,7 @@ public:
    case StatusCode::TRANSACTION_TYPE_ERROR: case StatusCode::TRANSACTION_TYPE_ERROR:
    throw TransactionTypeError(description); throw TransactionTypeError(description);
    default: default:
    throw Exception(StatusCode::GENERIC_ERROR, description); throw Exception(code, description);
    } }
    } }
    ...@@ -211,6 +240,9 @@ public: ...@@ -211,6 +240,9 @@ public:
    */ */
    inline auto GetCode() const -> StatusCode { return this->code; } inline auto GetCode() const -> StatusCode { return this->code; }
    TransactionStatus(StatusCode code, const std::string &description)
    : code(code), description(description){};
    private: private:
    /** /**
    * The code is an identifier of errors. * The code is an identifier of errors.
    ...@@ -221,9 +253,6 @@ private: ...@@ -221,9 +253,6 @@ private:
    * Description of the error * Description of the error
    */ */
    std::string description; std::string description;
    TransactionStatus(StatusCode code, const std::string &description)
    : code(code), description(description){};
    }; };
    } // namespace caosdb::transaction } // namespace caosdb::transaction
    ......
    /*
    * This file is a part of the CaosDB Project.
    * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
    * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
    *
    * This program is free software: you can redistribute it and/or modify
    * it under the terms of the GNU Affero General Public License as
    * published by the Free Software Foundation, either version 3 of the
    * License, or (at your option) any later version.
    *
    * This program is distributed in the hope that it will be useful,
    * but WITHOUT ANY WARRANTY; without even the implied warranty of
    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    * GNU Affero General Public License for more details.
    *
    * You should have received a copy of the GNU Affero General Public License
    * along with this program. If not, see <https://www.gnu.org/licenses/>.
    *
    *********************************************************************************
    *
    * This is derived work which is heavily based on
    * https://github.com/NeiRo21/grpcpp-bidi-streaming, Commit
    * cd9cb78e5d6d72806c2ec4c703e5e856b223dc96, Aug 10, 2020
    *
    * The orginal work is licensed as
    *
    * > MIT License
    * >
    * > Copyright (c) 2019 NeiRo21
    * >
    * > Permission is hereby granted, free of charge, to any person obtaining a
    * > copy of this software and associated documentation files (the "Software"),
    * > to deal in the Software without restriction, including without limitation
    * > the rights to use, copy, modify, merge, publish, distribute, sublicense,
    * > and/or sell copies of the Software, and to permit persons to whom the
    * > Software is furnished to do so, subject to the following conditions:
    * >
    * > The above copyright notice and this permission notice shall be included in
    * > all copies or substantial portions of the Software.
    * >
    * > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    * > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    * > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    * > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    * > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
    * > FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    * > DEALINGS IN THE SOFTWARE.
    */
    #ifndef CAOSDB_UNARY_RPC_HANDLER_H
    #define CAOSDB_UNARY_RPC_HANDLER_H
    #include "caosdb/handler_interface.h" // for HandlerTag, Handl...
    #include "caosdb/transaction_status.h" // for TransactionStatus
    #include <grpcpp/impl/codegen/client_context.h> // for ClientContext
    #include <grpcpp/impl/codegen/completion_queue.h> // for CompletionQueue
    #include <grpcpp/impl/codegen/status.h> // for Status
    namespace caosdb::transaction {
    class UnaryRpcHandler : public HandlerInterface {
    public:
    inline UnaryRpcHandler(grpc::CompletionQueue *completion_queue)
    : HandlerInterface(), state_(CallState::NewCall),
    completion_queue(completion_queue) {}
    void Start() override {
    transaction_status = TransactionStatus::EXECUTING();
    OnNext(true);
    }
    bool OnNext(bool ok) override;
    void Cancel() override;
    protected:
    virtual void handleNewCallState() = 0;
    void handleCallCompleteState();
    enum class CallState { NewCall, CallComplete };
    CallState state_;
    grpc::CompletionQueue *completion_queue;
    grpc::ClientContext call_context;
    grpc::Status status_;
    };
    } // namespace caosdb::transaction
    #endif
    0% Loading or .
    You are about to add 0 people to the discussion. Proceed with caution.
    Finish editing this message first!
    Please register or to comment