Add Send File Function
authorDaeheyon Jung <darrenh.jung@samsung.com>
Thu, 30 Aug 2018 09:57:52 +0000 (18:57 +0900)
committer정대현/Tizen Platform Lab(SR)/Staff Engineer/삼성전자 <darrenh.jung@samsung.com>
Thu, 4 Oct 2018 06:52:19 +0000 (15:52 +0900)
Change-Id: I5765d48ad50e0aac545e0dd6a7660f6e6af0f8b1
Signed-off-by: Daeheyon Jung <darrenh.jung@samsung.com>
include/capability-manager_internal.h [new file with mode: 0755]
packaging/capi-appfw-capmgr.spec
src/client_internal.cc [new file with mode: 0755]
src/dbus.cc [changed mode: 0644->0755]
src/dbus.h [changed mode: 0644->0755]
src/dbus_signal.h [new file with mode: 0755]
tools/capmgr_test.cc [changed mode: 0644->0755]

diff --git a/include/capability-manager_internal.h b/include/capability-manager_internal.h
new file mode 100755 (executable)
index 0000000..ff3afdc
--- /dev/null
@@ -0,0 +1,75 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef INCLUDE_CAPABILITY_MANAGER_INTERNAL_H_
+#define INCLUDE_CAPABILITY_MANAGER_INTERNAL_H_
+
+#include "include/capability-manager.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef struct capmgr_file_s* capmgr_file_h;
+
+typedef int (*capmgr_file_finish_cb)(capmgr_file_h file,
+    int result, void* user_data);
+
+typedef int (*capmgr_file_progress_cb)(
+    capmgr_file_h file, int64_t sent_size, int64_t total_size,
+    void* user_data);
+
+/**
+ * @brief
+ */
+int capmgr_file_create(capmgr_file_h* file);
+
+/**
+ * @brief
+ */
+int capmgr_file_destroy(capmgr_file_h file);
+
+/**
+ * @brief
+ */
+int capmgr_file_set_device(capmgr_file_h file,
+    const capmgr_device_h device);
+
+/**
+ * @brief
+ */
+int capmgr_file_set_path(capmgr_file_h file,
+    const char* file_path);
+
+/**
+ * @brief
+ */
+int capmgr_file_set_finish_cb(capmgr_file_h file,
+    capmgr_file_finish_cb cb, void* user_data);
+
+/**
+ * @brief
+ */
+int capmgr_file_set_progress_cb(capmgr_file_h file,
+    capmgr_file_progress_cb cb, void* user_data);
+
+/**
+ * @brief
+ */
+int capmgr_file_send(capmgr_file_h file);
+
+/* TODO(darrenh.jung)
+int capmgr_file_abort(capmgr_file_h file);
+
+int capmgr_file_cleanup(capmgr_file_h file);
+
+int capmgr_file_resume(capmgr_file_h file);
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // INCLUDE_CAPABILITY_MANAGER_INTERNAL_H_
index b33eae08eb3af592053b96c4d32f551feee628b1..37a23238cb53f24a50fc0d4f343ac3bbe93b26d7 100644 (file)
@@ -54,5 +54,6 @@ MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
 
 %files devel
 %{_includedir}/capability-manager.h
+%{_includedir}/capability-manager_internal.h
 %{_libdir}/pkgconfig/%{name}.pc
 %{_libdir}/lib%{name}.so
diff --git a/src/client_internal.cc b/src/client_internal.cc
new file mode 100755 (executable)
index 0000000..c6ba05e
--- /dev/null
@@ -0,0 +1,199 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#include <glib.h>
+
+#include <cstring>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "include/capability-manager.h"
+#include "include/capability-manager_internal.h"
+#include "src/dbus.h"
+#include "src/dbus_signal.h"
+#include "src/utils/logging.h"
+
+#define API __attribute__((visibility("default")))
+
+struct capmgr_finish_cb_s {
+  int (*callback)(capmgr_file_h, int, void*);
+  void* user_data;
+};
+
+struct capmgr_progress_cb_s {
+  int (*callback)(capmgr_file_h, int64_t, int64_t, void*);
+  void* user_data;
+};
+
+struct capmgr_file_s {
+  capmgr_device_h device;
+  char* path;
+  capmgr::DBusSignal* ds;
+  capmgr_finish_cb_s finish_cb;
+  capmgr_progress_cb_s progress_cb;
+};
+
+int __default_finish_cb(capmgr_file_h file, int result, void *user_data) {
+    LOG(DEBUG) << "finished with: " << result;
+    return 0;
+}
+
+int __default_progress_cb(capmgr_file_h file, int64_t sent_size,
+    int64_t total_size, void *user_data) {
+    LOG(DEBUG) << "progress: " << sent_size << "/" << total_size;
+    return 0;
+}
+
+API int capmgr_file_create(capmgr_file_h* file) {
+  if (!file)
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+
+  try {
+    capmgr_file_s* f = new capmgr_file_s();
+    capmgr_file_set_finish_cb(f, __default_finish_cb, nullptr);
+    capmgr_file_set_progress_cb(f, __default_progress_cb, nullptr);
+
+    *file = f;
+  } catch (const std::bad_alloc& e) {
+    LOG(ERROR) << e.what();
+    return CAPMGR_ERROR_OUT_OF_MEMORY;
+  }
+
+  return CAPMGR_ERROR_NONE;
+}
+
+API int capmgr_file_destroy(capmgr_file_h file) {
+  if (!file)
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+
+  capmgr_device_destroy(file->device);
+  free(file->path);
+  delete file->ds;
+  delete file;
+
+  return CAPMGR_ERROR_NONE;
+}
+
+API int capmgr_file_set_device(capmgr_file_h file,
+    const capmgr_device_h device) {
+  if (!file || !device)
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+
+  if (file->device)
+    capmgr_device_destroy(file->device);
+
+  int ret = capmgr_device_clone(device, &file->device);
+  if (ret != CAPMGR_ERROR_NONE)
+    return CAPMGR_ERROR_OUT_OF_MEMORY;
+
+  return CAPMGR_ERROR_NONE;
+}
+
+API int capmgr_file_set_path(capmgr_file_h file,
+    const char* path) {
+  if (!file || !path)
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+
+  if (file->path)
+      free(file->path);
+
+  file->path = strdup(path);
+  if (!file->path)
+    return CAPMGR_ERROR_OUT_OF_MEMORY;
+
+  return CAPMGR_ERROR_NONE;
+}
+
+API int capmgr_file_set_finish_cb(capmgr_file_h file,
+    capmgr_file_finish_cb cb, void *user_data) {
+  if (!file)
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+
+  file->finish_cb.callback = cb;
+  file->finish_cb.user_data = user_data;
+
+  return CAPMGR_ERROR_NONE;
+}
+
+API int capmgr_file_set_progress_cb(capmgr_file_h file,
+    capmgr_file_progress_cb cb, void *user_data) {
+  if (!file)
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+
+  file->progress_cb.callback = cb;
+  file->progress_cb.user_data = user_data;
+
+  return CAPMGR_ERROR_NONE;
+}
+
+void capmgr_send_file_callback(GVariant* result, void* user_data) {
+  capmgr_file_h file = reinterpret_cast<capmgr_file_h>(user_data);
+  LOG(INFO) << "Send File Callback called: " << file->path;
+  delete file->ds;
+  file->ds = nullptr;
+
+  int r = 0;
+  g_variant_get(result, "(i)", &r);
+  LOG(DEBUG) << "result:" << r;
+  if (file->finish_cb.callback)
+    file->finish_cb.callback(file, r, file->finish_cb.user_data);
+}
+
+void capmgr_progress_callback(GVariant* param, void* user_data) {
+  capmgr_file_h file = reinterpret_cast<capmgr_file_h>(user_data);
+
+  gchar* file_path;
+  int64_t sent_size;
+  int64_t total_size;
+
+  g_variant_get(param, "(sxx)", &file_path, &sent_size, &total_size);
+  // file_path may key for search handlers for multiple file handling.
+
+  if (file->progress_cb.callback) {
+    file->progress_cb.callback(file, sent_size, total_size,
+      file->progress_cb.user_data);
+  }
+}
+
+API int capmgr_file_send(capmgr_file_h file) {
+  if (!file || !file->device || !file->path)
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+
+  int ret;
+  char* device_id;
+  ret = capmgr_device_get_device_id(file->device, &device_id);
+  if (ret != CAPMGR_ERROR_NONE) {
+    LOG(ERROR) << "Failed to get device id";
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+  }
+
+  GVariant* gv = g_variant_new("(&s&s)", device_id, file->path);
+  if (!gv) {
+    LOG(ERROR) << "Failed to create GVariant";
+    free(device_id);
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+  }
+
+  file->ds = new capmgr::DBusSignal("SendFileProgressChanged");
+  file->ds->RegisterHandler(capmgr_progress_callback, file);
+  file->ds->Subscribe();
+
+  if (!capmgr::ProxyCallAsync("SendFile", gv, capmgr_send_file_callback,
+      file)) {
+    LOG(ERROR) << "Failed to dbus method call";
+    g_variant_unref(gv);
+    delete file->ds;
+    file->ds = nullptr;
+    free(device_id);
+    // errcode?
+    return CAPMGR_ERROR_INVALID_PARAMETER;
+  }
+
+  g_variant_unref(gv);
+  free(device_id);
+
+  return CAPMGR_ERROR_NONE;
+}
old mode 100644 (file)
new mode 100755 (executable)
index edd3138..8b3c3f1
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 #include "src/dbus.h"
+#include "src/dbus_signal.h"
 
 #include <glib.h>
 #include <gio/gio.h>
@@ -37,25 +38,93 @@ void MethodCallback(GObject* source_object, GAsyncResult* res,
   delete cbdata;
 }
 
-}  // namespace
+void SignalCallback(GDBusProxy* proxy, gchar* sender_name, gchar* signal_name,
+    GVariant* parameters, gpointer user_data) {
+  capmgr::DBusSignal* ds = reinterpret_cast<capmgr::DBusSignal*>(user_data);
 
-namespace capmgr {
+  LOG(INFO) << "Signal recieved " << signal_name;
+  if (g_strcmp0(ds->GetSignalName(), signal_name) == 0) {
+    LOG(INFO) << "progress callback called";
+    ds->Emit(parameters);
+  }
+}
 
-bool ProxyCallAsync(const char* method, GVariant* params, DBusCallback cb,
-    void* user_data) {
+bool InitDBusProxy(GDBusConnection** connection, GDBusProxy** proxy) {
   GError* error = nullptr;
   GDBusConnection* conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
-  if (!conn || error) {
+  if (!conn) {
     LOG(ERROR) << "g_bus_get_sync() failed: " << error->message;
+    g_object_unref(error);
     return false;
   }
-  GDBusProxy* proxy = g_dbus_proxy_new_sync(conn,
+
+  GDBusProxy* p = g_dbus_proxy_new_sync(conn,
       G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES, nullptr,
       kDBusServiceName, kDBusObjectPath, kDBusInterfaceName, nullptr,
       &error);
-  if (!proxy || error) {
+  if (!p) {
     LOG(ERROR) << "g_dbus_proxy_new_sync() failed: " << error->message;
+    g_object_unref(error);
+    g_object_unref(conn);
+    return false;
+  }
+
+  *connection = conn;
+  *proxy = p;
+  return true;
+}
+
+void DisposeDBusProxy(GDBusConnection* conn, GDBusProxy* proxy) {
+  if (proxy)
+    g_object_unref(proxy);
+  if (conn) {
+    g_dbus_connection_flush_sync(conn, nullptr, nullptr);
     g_object_unref(conn);
+  }
+}
+
+}  // namespace
+
+namespace capmgr {
+
+DBusSignal::DBusSignal(const std::string& signal_name)
+    : signal_name_ { signal_name } {}
+
+DBusSignal::~DBusSignal() {
+  DisposeDBusProxy(this->conn_, this->proxy_);
+}
+
+void DBusSignal::RegisterHandler(DBusCallback cb, void* user_data) {
+  this->cb_ = cb;
+  this->user_data_ = user_data;
+}
+
+void DBusSignal::Emit(GVariant* param) {
+  this->cb_(param, this->user_data_);
+}
+
+bool DBusSignal::Subscribe() {
+  if (!InitDBusProxy(&this->conn_, &this->proxy_)) {
+    LOG(ERROR) << "DBus initilization failed";
+    return false;
+  }
+
+  g_signal_connect(this->proxy_, "g-signal", G_CALLBACK(SignalCallback), this);
+
+  return true;
+}
+
+const char* DBusSignal::GetSignalName() {
+  return this->signal_name_.c_str();
+}
+
+bool ProxyCallAsync(const char* method, GVariant* params, DBusCallback cb,
+    void* user_data) {
+  GDBusConnection* conn = nullptr;
+  GDBusProxy* proxy = nullptr;
+
+  if (!InitDBusProxy(&conn, &proxy)) {
+    LOG(ERROR) << "DBus initilization failed";
     return false;
   }
 
@@ -67,9 +136,7 @@ bool ProxyCallAsync(const char* method, GVariant* params, DBusCallback cb,
   g_dbus_proxy_call(proxy, method,
       params, G_DBUS_CALL_FLAGS_NONE, -1, nullptr, MethodCallback, cbdata);
 
-  g_object_unref(proxy);
-  g_dbus_connection_flush_sync(conn, nullptr, nullptr);
-  g_object_unref(conn);
+  DisposeDBusProxy(conn, proxy);
 
   return true;
 }
old mode 100644 (file)
new mode 100755 (executable)
index 5520488..83336a3
@@ -6,6 +6,9 @@
 #define DBUS_H_
 
 #include <glib.h>
+#include <gio/gio.h>
+
+#include <string>
 
 #include "include/capability-manager.h"
 
diff --git a/src/dbus_signal.h b/src/dbus_signal.h
new file mode 100755 (executable)
index 0000000..ea78cbf
--- /dev/null
@@ -0,0 +1,36 @@
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by a apache 2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef DBUS_SIGNAL_H_
+#define DBUS_SIGNAL_H_
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include <string>
+
+#include "src/dbus.h"
+
+namespace capmgr {
+
+class DBusSignal {
+ public:
+    explicit DBusSignal(const std::string& signal_name);
+    ~DBusSignal();
+    void RegisterHandler(DBusCallback cb, void* user_data);
+    bool Subscribe();
+    const char* GetSignalName();
+    void Emit(GVariant* param);
+
+ private:
+    std::string signal_name_;
+    DBusCallback cb_;
+    void* user_data_;
+    GDBusProxy* proxy_;
+    GDBusConnection* conn_;
+};
+
+}  // namespace capmgr
+
+#endif  // DBUS_SIGNAL_H_
old mode 100644 (file)
new mode 100755 (executable)
index 76dcb79..d57b732
@@ -10,6 +10,7 @@
 #include <iostream>
 
 #include "include/capability-manager.h"
+#include "include/capability-manager_internal.h"
 
 namespace bpo = boost::program_options;
 
@@ -43,6 +44,10 @@ class Client {
       const capmgr_app_control_h reply, capmgr_app_control_result_e result,
       void* user_data);
 
+  static int FileFinishCb(capmgr_file_h file, int result, void* user_data);
+  static int FileProgressCb(capmgr_file_h file,
+    int64_t sent_size, int64_t total_size, void* user_data);
+
   GMainLoop* loop_;
   GDBusConnection* conn_;
   GDBusProxy* proxy_;
@@ -213,24 +218,71 @@ void Client::SendFile(const std::string& device_id,
     return;
   }
 
-  if (file_path.empty()) {
-    std::cout << "File path is missing!" << std::endl;
+  capmgr_device_h device = nullptr;
+  struct cbdata cbdata = {&device, device_id};
+  int ret = capmgr_device_foreach_devices(DeviceForeachCb, &cbdata);
+  if (ret != CAPMGR_ERROR_NONE) {
+    std::cout << "capmgr_device_foreach_devices() failed: " << ret
+              << std::endl;
+    return;
+  }
+
+  if (*cbdata.device == nullptr) {
+    std::cout << "There is no such device!" << std::endl;
+    return;
+  }
+
+  capmgr_file_h file;
+  ret = capmgr_file_create(&file);
+  if (ret != CAPMGR_ERROR_NONE) {
+    std::cout << "capmgr_file_create() failed: " << ret << std::endl;
+    capmgr_device_destroy(device);
+    return;
+  }
+
+  ret = capmgr_file_set_device(file, device);
+  if (ret != CAPMGR_ERROR_NONE) {
+    std::cout << "capmgr_file_set_device() failed: " << ret
+              << std::endl;
+    capmgr_device_destroy(device);
+    capmgr_file_destroy(file);
+    return;
+  }
+
+  ret = capmgr_file_set_path(file, file_path.c_str());
+  if (ret != CAPMGR_ERROR_NONE) {
+    std::cout << "capmgr_file_set_path() failed: " << ret
+              << std::endl;
+    capmgr_device_destroy(device);
+    capmgr_file_destroy(file);
     return;
   }
 
-  std::cout << "Send file " << file_path << " to " << device_id << std::endl;
+  ret = capmgr_file_set_finish_cb(file, FileFinishCb, this);
+  if (ret != CAPMGR_ERROR_NONE) {
+    std::cout << "capmgr_file_set_finish_cb() failed: " << ret
+              << std::endl;
+    capmgr_device_destroy(device);
+    capmgr_file_destroy(file);
+    return;
+  }
 
-  GVariant* params = g_variant_new("(ss)", device_id.c_str(),
-                       file_path.c_str());
-  if (!params) {
-    std::cout << "out of memory" << std::endl;
+  ret = capmgr_file_set_progress_cb(file, FileProgressCb, this);
+  if (ret != CAPMGR_ERROR_NONE) {
+    std::cout << "capmgr_file_set_progress_cb() failed: " << ret
+              << std::endl;
+    capmgr_device_destroy(device);
+    capmgr_file_destroy(file);
     return;
   }
 
-  GVariant* ret = ProxyCallSync("SendFile", params);
+  ret = capmgr_file_send(file);
+  if (ret != CAPMGR_ERROR_NONE)
+    std::cout << "capmgr_file_send failed: " << ret
+              << std::endl;
 
-  g_object_unref(params);
-  g_object_unref(ret);
+  capmgr_device_destroy(device);
+  WaitForResult();
 }
 
 GVariant* Client::ProxyCallSync(const char* method, GVariant* params) {
@@ -252,6 +304,25 @@ void Client::Quit() {
   g_main_loop_quit(loop_);
 }
 
+int Client::FileFinishCb(capmgr_file_h file,
+    int result, void* user_data) {
+  std::cout << "FileFinishCb called: " << result << std::endl;
+
+  capmgr_file_destroy(file);
+
+  Client* client = static_cast<Client*>(user_data);
+  client->Quit();
+  return 0;
+}
+
+int Client::FileProgressCb(capmgr_file_h file, int64_t sent_size,
+    int64_t total_size, void* user_data) {
+  std::cout << "FileProgressCb called ("
+      << sent_size << "/" << total_size << ")bytes sent" << std::endl;
+
+  return 0;
+}
+
 int Client::AppControlCb(const capmgr_app_control_h request,
     const capmgr_app_control_h reply, capmgr_app_control_result_e result,
     void* user_data) {