From ac77015af5af52d8502e1945b8be7619cd0b70de Mon Sep 17 00:00:00 2001
From: Timm Fitschen <t.fitschen@indiscale.com>
Date: Wed, 4 Aug 2021 13:54:37 +0200
Subject: [PATCH] WIP: file download

---
 include/caosdb/configuration.h |  7 +--
 include/caosdb/entity.h        | 12 +++++
 include/caosdb/transaction.h   | 13 +++++
 src/caosdb/configuration.cpp   | 11 ++--
 src/caosdb/entity.cpp          | 13 +++++
 src/caosdb/transaction.cpp     | 92 +++++++++++++++++++++++++++++++++-
 6 files changed, 139 insertions(+), 9 deletions(-)

diff --git a/include/caosdb/configuration.h b/include/caosdb/configuration.h
index 6426ab4..80bc927 100644
--- a/include/caosdb/configuration.h
+++ b/include/caosdb/configuration.h
@@ -26,9 +26,10 @@
 #include "boost/json/object.hpp"           // for object
 #include "boost/json/value.hpp"            // for value
 #include "boost/json/value_ref.hpp"        // IWYU pragma: keep
-#include "caosdb/authentication.h"         // for Authenticator, PlainPassw...
-#include "caosdb/certificate_provider.h"   // for CertificateProvider, path
-#include "caosdb/exceptions.h"             // for ConfigurationError
+// IWYU pragma: no_include "boost/json/fwd.hpp"
+#include "caosdb/authentication.h"       // for Authenticator, PlainPassw...
+#include "caosdb/certificate_provider.h" // for CertificateProvider, path
+#include "caosdb/exceptions.h"           // for ConfigurationError
 #include "caosdb/logging.h"
 #include "caosdb/utility.h"              // for load_json_file
 #include "grpcpp/security/credentials.h" // for ChannelCredentials
diff --git a/include/caosdb/entity.h b/include/caosdb/entity.h
index 10333d7..5f261df 100644
--- a/include/caosdb/entity.h
+++ b/include/caosdb/entity.h
@@ -39,6 +39,7 @@ using caosdb::entity::v1alpha1::IdResponse;
 using ProtoParent = caosdb::entity::v1alpha1::Parent;
 using ProtoProperty = caosdb::entity::v1alpha1::Property;
 using ProtoEntity = caosdb::entity::v1alpha1::Entity;
+using caosdb::entity::v1alpha1::FileTransmissionId;
 
 /**
  * Messages convey information about the state and result of transactions.
@@ -456,12 +457,23 @@ public:
    */
   auto CopyTo(ProtoEntity *target) -> void;
 
+  auto SetFileTransmissionId(const std::string &registration_id,
+                             const std::string &file_id) -> void;
+  auto SetFilePath(const std::string &path) -> void;
+  inline auto GetFileTransmissionId() const -> const FileTransmissionId & {
+    return *(this->file_transmission_id);
+  }
+  inline auto HasFile() const -> bool {
+    return this->file_transmission_id != nullptr;
+  }
+
 protected:
   static auto CreateProtoEntity() -> ProtoEntity *;
   auto SetId(const std::string &id) -> void;
   auto SetVersionId(const std::string &id) -> void;
 
 private:
+  FileTransmissionId *file_transmission_id = nullptr;
   ProtoEntity *wrapped;
   Properties properties;
   Parents parents;
diff --git a/include/caosdb/transaction.h b/include/caosdb/transaction.h
index ce7eb42..a129590 100644
--- a/include/caosdb/transaction.h
+++ b/include/caosdb/transaction.h
@@ -37,6 +37,7 @@
 #include "google/protobuf/util/json_util.h" // for MessageToJsonString, Jso...
 #include <stdexcept>
 #include <iterator>
+// IWYU pragma: no_include <ext/alloc_traits.h>
 #include <memory> // for shared_ptr, unique_ptr
 #include <string> // for string
 #include <vector> // for vector
@@ -139,10 +140,15 @@ namespace caosdb::transaction {
 using caosdb::entity::Entity;
 using ProtoEntity = caosdb::entity::v1alpha1::Entity;
 using caosdb::entity::v1alpha1::EntityTransactionService;
+using caosdb::entity::v1alpha1::FileDownloadResponse;
 using caosdb::entity::v1alpha1::FileTransmissionService;
+using caosdb::entity::v1alpha1::FileUploadRequest;
+using caosdb::entity::v1alpha1::FileUploadResponse;
 using caosdb::entity::v1alpha1::IdResponse;
 using caosdb::entity::v1alpha1::MultiTransactionRequest;
 using caosdb::entity::v1alpha1::MultiTransactionResponse;
+using caosdb::entity::v1alpha1::RegisterFileDownloadRequest;
+using caosdb::entity::v1alpha1::RegisterFileDownloadResponse;
 using caosdb::entity::v1alpha1::RegisterFileUploadResponse;
 using caosdb::transaction::TransactionStatus;
 using WrappedResponseCase =
@@ -221,7 +227,14 @@ private:
  */
 class Transaction {
 public:
+  auto UploadFile(FileUploadResponse *response,
+                  const std::string &registration_id) -> void;
   auto RegisterUploadFile(RegisterFileUploadResponse *response) -> void;
+  auto DownloadFile(FileDownloadResponse *response,
+                    const RegisterFileDownloadResponse &registration_response)
+    -> void;
+  auto RegisterDownloadFile(const RegisterFileDownloadRequest &request,
+                            RegisterFileDownloadResponse *response) -> void;
   enum TransactionType {
     NONE,
     READ_ONLY,
diff --git a/src/caosdb/configuration.cpp b/src/caosdb/configuration.cpp
index ffa8604..76c4372 100644
--- a/src/caosdb/configuration.cpp
+++ b/src/caosdb/configuration.cpp
@@ -39,11 +39,12 @@
 #include <cstdlib>                                     // for getenv
 #include <cstring>                                     // for strcmp
 #include <exception>                                   // IWYU pragma: keep
-#include <grpcpp/security/credentials.h>               // for SslCredentials
-#include <iterator>                                    // for next
-#include <map>                                         // for map
-#include <stdexcept>                                   // for out_of_range
-#include <string>                                      // for string, operator+
+// IWYU pragma: no_include <bits/exception.h>
+#include <grpcpp/security/credentials.h> // for SslCredentials
+#include <iterator>                      // for next
+#include <map>                           // for map
+#include <stdexcept>                     // for out_of_range
+#include <string>                        // for string, operator+
 
 namespace caosdb::configuration {
 using boost::filesystem::exists;
diff --git a/src/caosdb/entity.cpp b/src/caosdb/entity.cpp
index 999ba37..11e0ca0 100644
--- a/src/caosdb/entity.cpp
+++ b/src/caosdb/entity.cpp
@@ -208,4 +208,17 @@ auto Entity::SetDatatype(const std::string &datatype) -> void {
   this->wrapped->set_datatype(datatype);
 }
 
+auto Entity::SetFilePath(const std::string &path) -> void {
+  this->wrapped->mutable_file_descriptor()->set_path(path);
+}
+
+auto Entity::SetFileTransmissionId(const std::string &registration_id,
+                                   const std::string &file_id) -> void {
+  this->file_transmission_id =
+    google::protobuf::Arena::CreateMessage<FileTransmissionId>(get_arena());
+
+  this->file_transmission_id->set_registration_id(registration_id);
+  this->file_transmission_id->set_file_id(file_id);
+}
+
 } // namespace caosdb::entity
diff --git a/src/caosdb/transaction.cpp b/src/caosdb/transaction.cpp
index 3a23b49..1c889fe 100644
--- a/src/caosdb/transaction.cpp
+++ b/src/caosdb/transaction.cpp
@@ -91,9 +91,15 @@ auto get_status_description(int code) -> const std::string & {
 
 namespace caosdb::transaction {
 using caosdb::entity::v1alpha1::EntityTransactionService;
+using caosdb::entity::v1alpha1::FileDownloadRequest;
+using caosdb::entity::v1alpha1::FileDownloadResponse;
 using caosdb::entity::v1alpha1::FileTransmissionService;
+using caosdb::entity::v1alpha1::FileUploadRequest;
+using caosdb::entity::v1alpha1::FileUploadResponse;
 using caosdb::entity::v1alpha1::MultiTransactionRequest;
 using caosdb::entity::v1alpha1::MultiTransactionResponse;
+using caosdb::entity::v1alpha1::RegisterFileDownloadRequest;
+using caosdb::entity::v1alpha1::RegisterFileDownloadResponse;
 using caosdb::entity::v1alpha1::RegisterFileUploadRequest;
 using caosdb::entity::v1alpha1::RegisterFileUploadResponse;
 using WrappedResponseCase =
@@ -154,6 +160,10 @@ auto Transaction::InsertEntity(Entity *entity) noexcept -> StatusCode {
 
   // copy the original entity for the transaction
   entity->CopyTo(proto_entity);
+  if (entity->HasFile()) {
+    sub_request->mutable_insert_request()->mutable_upload_id()->CopyFrom(
+      entity->GetFileTransmissionId());
+  }
   return StatusCode::INITIAL;
 }
 
@@ -302,7 +312,87 @@ auto Transaction::RegisterUploadFile(RegisterFileUploadResponse *response)
   void *recv_tag = nullptr;
   bool ok = false;
 
-  // TODO(tf) make this actually asynchronous by moving this to WaitForIt()
+  cq.Next(&recv_tag, &ok);
+  assert(recv_tag == send_tag);
+  assert(ok);
+}
+
+auto Transaction::UploadFile(FileUploadResponse *response,
+                             const std::string &registration_id) -> void {
+  grpc::Status grpc_status;
+  CompletionQueue cq;
+  grpc::ClientContext context;
+
+  FileUploadRequest request;
+  auto *chunk = request.mutable_chunk();
+  auto *file_transmission_id = chunk->mutable_file_transmission_id();
+  file_transmission_id->set_registration_id(registration_id);
+  file_transmission_id->set_file_id("test.txt");
+  chunk->set_data("this is some data");
+
+  std::unique_ptr<ClientAsyncResponseReader<FileUploadResponse>> rpc(
+    this->file_service->PrepareAsyncFileUpload(&context, request, &cq));
+
+  rpc->StartCall();
+
+  int tag = 1;
+  void *send_tag = static_cast<void *>(&tag);
+  rpc->Finish(response, &grpc_status, send_tag);
+  void *recv_tag = nullptr;
+  bool ok = false;
+
+  cq.Next(&recv_tag, &ok);
+  assert(recv_tag == send_tag);
+  assert(ok);
+}
+
+auto Transaction::DownloadFile(
+  FileDownloadResponse *response,
+  const RegisterFileDownloadResponse &registration_response) -> void {
+
+  FileDownloadRequest request;
+  auto *file_transmission_id = request.mutable_file_transmission_id();
+  file_transmission_id->CopyFrom(
+    registration_response.files(0).file_transmission_id());
+  grpc::Status grpc_status;
+  CompletionQueue cq;
+
+  grpc::ClientContext context;
+  std::unique_ptr<ClientAsyncResponseReader<FileDownloadResponse>> rpc(
+    this->file_service->PrepareAsyncFileDownload(&context, request, &cq));
+
+  rpc->StartCall();
+
+  int tag = 1;
+  void *send_tag = static_cast<void *>(&tag);
+  rpc->Finish(response, &grpc_status, send_tag);
+  void *recv_tag = nullptr;
+  bool ok = false;
+
+  cq.Next(&recv_tag, &ok);
+  assert(recv_tag == send_tag);
+  assert(ok);
+}
+
+auto Transaction::RegisterDownloadFile(
+  const RegisterFileDownloadRequest &request,
+  RegisterFileDownloadResponse *response) -> void {
+  grpc::Status grpc_status;
+  CompletionQueue cq;
+
+  grpc::ClientContext context;
+  std::unique_ptr<ClientAsyncResponseReader<RegisterFileDownloadResponse>> rpc(
+    this->file_service->PrepareAsyncRegisterFileDownload(&context, request,
+                                                         &cq));
+
+  rpc->StartCall();
+
+  int tag = 1;
+  void *send_tag = static_cast<void *>(&tag);
+  rpc->Finish(response, &grpc_status, send_tag);
+  void *recv_tag = nullptr;
+  bool ok = false;
+
   cq.Next(&recv_tag, &ok);
   assert(recv_tag == send_tag);
   assert(ok);
-- 
GitLab