Add SendFile Callback
authorDaeheyon Jung <darrenh.jung@samsung.com>
Thu, 30 Aug 2018 09:33:05 +0000 (18:33 +0900)
committer정대현/Tizen Platform Lab(SR)/Staff Engineer/삼성전자 <darrenh.jung@samsung.com>
Thu, 13 Sep 2018 02:38:58 +0000 (09:38 +0700)
Change-Id: I482d046b8f42fc127140af6b18c13448209a75a2
Signed-off-by: Daeheyon Jung <darrenh.jung@samsung.com>
src/capmgr/capmgr.cc [changed mode: 0644->0755]
src/common/connection_manager.h [changed mode: 0644->0755]
src/common/dbus_service.cc [changed mode: 0644->0755]
src/common/dbus_service.h [changed mode: 0644->0755]
src/common/mdg_manager.cc [changed mode: 0644->0755]
src/common/mdg_manager.h [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
old mode 100644 (file)
new mode 100755 (executable)
index 1e34967..e17ffe1
@@ -23,7 +23,7 @@ class ConnectionManager {
   virtual void ExchangeCapabilities() = 0;
   virtual int SendAppControl(const std::string& device_id,
       const unsigned char* data, size_t len) = 0;
-  virtual bool SendFile(const std::string& device_id,
+  virtual int SendFile(const std::string& device_id,
       const std::string& file_path) = 0;
 
  protected:
old mode 100644 (file)
new mode 100755 (executable)
index e8ad633..345fba1
@@ -9,6 +9,7 @@
 #include <sys/types.h>
 
 #include <functional>
+#include <utility>
 #include <vector>
 
 #include "common/utils/logging.h"
@@ -35,14 +36,50 @@ const char kDBusInstropectionXml[] =
   "    <method name='SendFile'>"
   "      <arg type='s' name='device_id' direction='in'/>"
   "      <arg type='s' name='file_path' direction='in'/>"
+  "      <arg type='i' name='result' direction='out'/>"
   "    </method>"
+  "    <signal name='SendFileProgressChanged'>"
+  "      <arg type='s' name='file_path'/>"
+  "      <arg type='x' name='send_size'/>"
+  "      <arg type='x' name='total_size'/>"
+  "    </signal>"
+  "    <signal name='SendFileFinished'>"
+  "      <arg type='i' name='result'/>"
+  "    </signal>"
   "  </interface>"
   "</node>";
 const char kDBusServiceName[] = "org.tizen.capmgr";
 const char kDBusObjectPath[] = "/org/tizen/capmgr";
+const char kDBusInterfaceName[] = "org.tizen.capmgr";
 
 std::map<int, GDBusMethodInvocation*> invoc_map_;
 
+struct SendFileHandle {
+  const std::string file_path;
+  const std::string sender; const std::string device_id;
+  GDBusMethodInvocation* invocation;
+  GDBusConnection* connection;
+
+  SendFileHandle(std::string file_path, std::string sender,
+      std::string device_id, GDBusMethodInvocation* invocation,
+      GDBusConnection* connection)
+      : file_path(std::move(file_path)), sender(std::move(sender)),
+        device_id(std::move(device_id)), invocation(invocation),
+        connection(connection) {}
+
+  ~SendFileHandle() {
+    if (invocation)
+      g_object_unref(invocation);
+
+    if (connection) {
+      g_dbus_connection_flush_sync(connection, nullptr, nullptr);
+      g_object_unref(connection);
+    }
+  }
+};
+
+std::map<std::string, SendFileHandle*> file_map_;
+
 }  // namespace
 
 namespace capmgr {
@@ -86,7 +123,7 @@ void DBusService::RegisterSendAppcontrolHandler(const std::string& method,
 }
 
 void DBusService::RegisterSendFileHandler(const std::string& method,
-    std::function<bool(const std::string&, const std::string&)> handler) {
+    std::function<int(const std::string&, const std::string&)> handler) {
   if (method == "SendFile")
     EventHandler().send_file_event.connect(handler);
 }
@@ -108,6 +145,51 @@ void DBusService::SendAppControlReply(int msg_id, const unsigned char* data,
   g_dbus_method_invocation_return_value(it->second, gv);
 }
 
+void DBusService::SendFileResult(const std::string& file_path, int result) {
+  LOG(DEBUG)  << "result" << result;
+  auto it = file_map_.find(file_path);
+  if (it == file_map_.end()) {
+    LOG(ERROR) << "Cannot find file handle " << file_path;
+    return;
+  } else {
+    LOG(INFO) << "Got a response for " << file_path;
+  }
+
+  SendFileHandle* handle = reinterpret_cast<SendFileHandle*>(it->second);
+  GVariant* gv = g_variant_new("(i)", result);
+  g_dbus_method_invocation_return_value(handle->invocation, gv);
+
+  delete handle;
+}
+
+void DBusService::SendFileProgress(const std::string& file_path,
+                        int64_t send_size, int64_t total_size) {
+  LOG(DEBUG)  << "progress" << file_path << " "
+              << send_size << "/" << total_size;
+  auto it = file_map_.find(file_path);
+  if (it == file_map_.end()) {
+    LOG(ERROR) << "Cannot find file handle " << file_path;
+    return;
+  } else {
+    LOG(INFO) << "Got a response for " << file_path;
+  }
+
+  GError* error = nullptr;
+  GVariant* gv = g_variant_new("(sxx)", file_path.c_str(), send_size,
+                                          total_size);
+  SendFileHandle* handle = reinterpret_cast<SendFileHandle*>(it->second);
+
+  LOG(INFO) << "Emit signal to :" << handle->sender.c_str();
+
+  g_dbus_connection_emit_signal(handle->connection, handle->sender.c_str(),
+                      kDBusObjectPath, kDBusInterfaceName,
+                      "SendFileProgressChanged", gv, &error);
+  if (error) {
+    LOG(ERROR) << "Failed to send progress " << error->message;
+    g_error_free(error);
+  }
+}
+
 bool DBusService::HandleDiscoverUnownedDevices(GVariant* params,
     GDBusMethodInvocation* invocation) {
   EventHandler().on_event();
@@ -159,7 +241,8 @@ bool DBusService::HandleSendRemoteAppControl(GVariant* params,
 }
 
 bool DBusService::HandleSendFile(GVariant* params,
-    GDBusMethodInvocation* invocation) {
+    GDBusMethodInvocation* invocation, const gchar* sender,
+    GDBusConnection* connection) {
   LOG(INFO) << "HandleSendFile ";
   gchar* device_id;
   gchar* file_path;
@@ -168,13 +251,38 @@ bool DBusService::HandleSendFile(GVariant* params,
 
   LOG(INFO) << "To: " << device_id;
   LOG(INFO) << "Path: " << file_path;
+  LOG(INFO) << "Sender: " << sender;
+
+  // To send file multiple devices in simultaneously, we can use
+  // key that conjunction with device_id and file_path.
+  // For now, mdg only allows one file at a time so we had to keep limitation.
+  if (file_map_.count(std::string(file_path)) > 0) {
+    // TODO(darrenh.jung) set real error code
+    g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", -1));
+    return false;
+  }
+
+  SendFileHandle* handle = new SendFileHandle(std::string(file_path),
+            std::string(sender),
+            std::string(device_id),
+            reinterpret_cast<GDBusMethodInvocation*>(g_object_ref(invocation)),
+            reinterpret_cast<GDBusConnection*>(g_object_ref(connection)));
+
+  file_map_.emplace(handle->file_path, handle);
+
+  boost::optional<int> r =
+      EventHandler().send_file_event(handle->device_id, handle->file_path);
+
+  if (!r) {
+    LOG(ERROR) << "Failed to send file";
+    return false;
+  }
 
-  EventHandler().send_file_event(device_id, file_path);
   return true;
 }
 
-void DBusService::HandleMethodCall(GDBusConnection* /* connection */,
-    const gchar* /* sender */, const gchar* /* object_path */,
+void DBusService::HandleMethodCall(GDBusConnection* connection,
+    const gchar* sender, const gchar* /* object_path */,
     const gchar* /* interface_name */, const gchar* method_name,
     GVariant* parameters, GDBusMethodInvocation* invocation,
     gpointer /* user_data */) {
@@ -190,7 +298,7 @@ void DBusService::HandleMethodCall(GDBusConnection* /* connection */,
     HandleSendRemoteAppControl(parameters, invocation);
     return;
   } else if (g_strcmp0("SendFile", method_name) == 0) {
-    HandleSendFile(parameters, invocation);
+    r = HandleSendFile(parameters, invocation, sender, connection);
     return;
   }
 
old mode 100644 (file)
new mode 100755 (executable)
index 12e4e82..f421764
@@ -32,10 +32,13 @@ class DBusService {
       std::function<int(const std::string&, const unsigned char*,
           size_t)> handler);
   static void RegisterSendFileHandler(const std::string& method,
-      std::function<bool(const std::string&, const std::string&)> handler);
+      std::function<int(const std::string&, const std::string&)> handler);
 
   static void SendAppControlReply(int msg_id, const unsigned char* data,
       size_t len);
+  static void SendFileResult(const std::string& file_path, int result);
+  static void SendFileProgress(const std::string& file_path,
+                        int64_t send_size, int64_t total_size);
 
  private:
   class DBusMethodHandler {
@@ -44,7 +47,7 @@ class DBusService {
     boost::signals2::signal<void()> on_event2;
     boost::signals2::signal<int(const std::string&, const unsigned char*,
         size_t)> send_app_control_event;
-    boost::signals2::signal<void(const std::string&,
+    boost::signals2::signal<int(const std::string&,
         const std::string&)> send_file_event;
   };
 
@@ -60,7 +63,8 @@ class DBusService {
   bool HandleSendRemoteAppControl(GVariant* params,
       GDBusMethodInvocation* invocation);
   bool HandleSendFile(GVariant* params,
-      GDBusMethodInvocation* invocation);
+      GDBusMethodInvocation* invocation, const gchar* sender,
+      GDBusConnection* connection);
 
   void HandleMethodCall(GDBusConnection* connection,
       const gchar* sender, const gchar* object_path,
old mode 100644 (file)
new mode 100755 (executable)
index 7c57bbc..b27d85f
@@ -71,19 +71,26 @@ void SendDataFinishCb(int result, mdg_device_h device, char* channel_id,
   capmgr::DBusService::SendAppControlReply(msg_id, data, len);
 }
 
-void SendFileProgressCb(const char* file_path, int64_t send_size,
+void SendFileProgressCb(const char* file_path_, int64_t send_size,
     int64_t total_size, int percent, void* user_data) {
+  std::string file_path = std::string(file_path_);
   LOG(INFO) << "SendFileProgressCb called. "
             << "file_path: " << file_path
             << "send_size: " << send_size
             << "total_size: " << total_size
             << "percent: " << percent;
+
+  capmgr::DBusService::SendFileProgress(file_path, send_size, total_size);
 }
 
 void SendFileFinishCb(int result, mdg_device_h device,
     void* user_data) {
+  std::string& file_path = *static_cast<std::string*>(user_data);
   LOG(INFO) << "SendFileFinishCb called. "
-            << "result: " << result;
+            << "\nresult: " << result
+            << "\npath: " << file_path;
+
+  capmgr::DBusService::SendFileResult(file_path, result);
 }
 
 std::string GetDeviceIdFromHandle(const mdg_device_h device) {
@@ -607,7 +614,7 @@ bool MDGManager::SendReplyData(const std::string& device_id, Command cmd,
   return true;
 }
 
-bool MDGManager::SendFile(const std::string& device_id,
+int MDGManager::SendFile(const std::string& device_id,
     const std::string& file_path) {
   LOG(INFO) << "SendFile to " << device_id;
   LOG(INFO) << "File: " << file_path;
@@ -615,17 +622,18 @@ bool MDGManager::SendFile(const std::string& device_id,
   mdg_device_h device = GetDeviceHandleFromId(device_id);
   if (!device) {
     LOG(ERROR) << "There is no such device in list!";
-    return false;
+    return -1;
   }
 
   int ret = mdg_device_send_file(mdg_handle_, device,
       const_cast<char*>(file_path.c_str()), SendFileProgressCb,
-      SendFileFinishCb, this);
+      SendFileFinishCb,
+      reinterpret_cast<void*>(const_cast<std::string*>(&file_path)));
 
   if (ret != MDG_ERROR_NONE)
     LOG(ERROR) << "Failed to send file: " << MDGErrorToString(ret);
 
-  return true;
+  return 0;
 }
 
 
old mode 100644 (file)
new mode 100755 (executable)
index d1d8bda..fe1bffa
@@ -32,6 +32,8 @@ class MDGManager : public ConnectionManager {
   void ExchangeCapabilities() override;
   int SendAppControl(const std::string& device_id,
       const unsigned char* appcontrol, size_t len) override;
+  int SendFile(const std::string& device_id,
+      const std::string& file_path) override;
 
  private:
   enum class Command : unsigned char {
@@ -53,7 +55,6 @@ class MDGManager : public ConnectionManager {
       const unsigned char* data, size_t len);
   bool SendReplyData(const std::string& device_id, Command cmd,
       const unsigned char* data, size_t len, int msg_id);
-  bool SendFile(const std::string& device_id, const std::string& file_path);
   mdg_device_h GetDeviceHandleFromId(const std::string& device_id);
 
   static void ReceiveDataCb(int result, char* device_id, char* channel_id,