Implement plugin-daemon logic
authorChanggyu Choi <changyu.choi@samsung.com>
Sun, 27 Apr 2025 07:59:05 +0000 (16:59 +0900)
committerChanggyu Choi <changyu.choi@samsung.com>
Mon, 12 May 2025 05:11:18 +0000 (14:11 +0900)
Signed-off-by: Changgyu Choi <changyu.choi@samsung.com>
src/common/utils/safe_json.hpp
src/plugin-daemon/CMakeLists.txt
src/plugin-daemon/main.cc
src/plugin-daemon/plugin.cc [new file with mode: 0644]
src/plugin-daemon/plugin.hh [new file with mode: 0644]

index b802b1d1922fc21f795438d0082d79a73473cfea..6f3bfe1e01d83fcc7be677d087fc2ee0765f49fd 100644 (file)
@@ -23,6 +23,8 @@
 
 #include "rapidjson/document.h"
 #include "rapidjson/error/en.h"
+#include "rapidjson/stringbuffer.h"
+#include "rapidjson/writer.h"
 
 namespace common {
 
@@ -111,6 +113,40 @@ class SafeJson {
     return get<T>(node, std::move(path));
   }
 
+  void set(std::vector<std::string> path, const std::string& value) {
+    rapidjson::Value* curr = &doc_;
+    for (auto it = path.begin(); it != path.end(); ++it) {
+      if (!curr->IsObject()) {
+        throw std::runtime_error("Expected object while traversing to set key");
+      }
+
+      auto memberIt = curr->FindMember(it->c_str());
+      if (memberIt == curr->MemberEnd()) {
+        rapidjson::Value key(it->c_str(), doc_.GetAllocator());
+        rapidjson::Value newObj(rapidjson::kObjectType);
+        curr->AddMember(key, newObj, doc_.GetAllocator());
+        memberIt = curr->FindMember(it->c_str());
+      }
+      if (std::next(it) == path.end()) {
+        memberIt->value.SetString(value.c_str(), doc_.GetAllocator());
+      } else {
+        curr = &memberIt->value;
+      }
+    }
+  }
+
+  void set(const std::string& dotPath, const std::string& value) {
+    std::vector<std::string> path = split(dotPath, '.');
+    set(std::move(path), value);
+  }
+
+  std::string stringify() const {
+    rapidjson::StringBuffer buffer;
+    rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+    doc_.Accept(writer);
+    return buffer.GetString();
+  }
+
  private:
   rapidjson::Document doc_;
 
index 26175596339037b80b45a069d814eb818db4dd6c..230cd1f2c144a1fb5aec0624906c04cee96b4130 100644 (file)
@@ -16,6 +16,7 @@ APPLY_PKG_CONFIG(${TARGET_TIZEN_ACTION_PLUGIN_DAEMON} PUBLIC
 )
 
 TARGET_LINK_LIBRARIES(${TARGET_TIZEN_ACTION_PLUGIN_DAEMON} PRIVATE ${TARGET_TIZEN_ACTION} ${TARGET_TIZEN_ACTION_COMMON})
+TARGET_INCLUDE_DIRECTORIES(${TARGET_TIZEN_ACTION_PLUGIN_DAEMON} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/../)
 
 INSTALL(TARGETS ${TARGET_TIZEN_ACTION_PLUGIN_DAEMON} DESTINATION bin)
 
index df2f3bbbfd8d72d64c05e7cc5d9355aef108c01f..e10e84f711bec99db4dbf8c93e5413bcddda81f2 100644 (file)
 #include <cstdio>
 #include <utility>
 
+#include "action/sqlite_db.hh"
+#include "common/action_schema.h"
 #include "common/utils/logging.hh"
+#include "common/utils/safe_json.hpp"
+#include "plugin.hh"
 #include "plugin_manager_stub.h"
 
+namespace {
+
+const char kActionFrameworkServiceAppId[] =
+    "org.tizen.action-framework.service";
+
+}  // namespace
+
 class PluginService
     : public rpc_port::plugin_manager_stub::stub::PluginManager::ServiceBase {
  public:
@@ -62,18 +73,34 @@ class PluginService
     std::string instance = GetInstance();
     LOG(INFO) << "PluginService execute. sender: " << sender
               << ", instance: " << instance;
-    PrintAction(action);
-    // TODO: find executable path;
 
-    if (true) {
-      LOG(ERROR) << "Executable parameter not found";
-      result_cb->Invoke("Fail");
+    if (sender != kActionFrameworkServiceAppId) {
+      LOG(ERROR) << "Invalid sender";
+      common::SafeJson result("{}");
+      result.set("error", "Permission denied");
+      result_cb->Invoke(result.stringify());
       return;
     }
 
-    // TODO: implement action execution
-
-    result_cb->Invoke("Success");
+    PrintAction(action);
+    std::string action_name = action.Getaction_id();
+    auto db = std::make_unique<action::SqliteDb>();
+    std::string schema_json = db->GetAction(action_name);
+    try {
+      common::ActionSchema schema(schema_json);
+      std::string plugin_path = schema.GetPluginPath();
+      LOG(INFO) << "Plugin path: " + plugin_path;
+      auto plugin = std::make_unique<Plugin>(plugin_path);
+      std::string result_json = plugin->Execute(action.Getjson());
+      common::SafeJson result("{}");
+      result.set("data", result_json);
+      result_cb->Invoke(result.stringify());
+    } catch (const std::runtime_error& e) {
+      LOG(ERROR) << "Exception occurred: " << e.what();
+      common::SafeJson result("{}");
+      result.set("error", e.what());
+      result_cb->Invoke(result.stringify());
+    }
   }
 
  private:
diff --git a/src/plugin-daemon/plugin.cc b/src/plugin-daemon/plugin.cc
new file mode 100644 (file)
index 0000000..03c7ef3
--- /dev/null
@@ -0,0 +1,35 @@
+#include "plugin.hh"
+
+#include <dlfcn.h>
+
+#include <stdexcept>
+#include <utility>
+
+#include "common/utils/logging.hh"
+
+Plugin::Plugin(std::string plugin_path) : plugin_path_(std::move(plugin_path)) {
+  handle_ = dlopen(plugin_path_.c_str(), RTLD_LAZY);
+  if (handle_ == nullptr) {
+    LOG(ERROR) << "Failed to open plugin: " << dlerror();
+    throw std::runtime_error("Invalid plugin");;
+  }
+
+  execute_function_ = reinterpret_cast<const char* (*)(const char*)>(
+      dlsym(handle_, "PLUGIN_EXECUTE"));
+  if (execute_function_ == nullptr) {
+    LOG(ERROR) << "Failed to find symbol: " << dlerror();
+    dlclose(handle_);
+    throw std::runtime_error("Invalid plugin");
+  }
+
+  LOG(INFO) << "Plugin loaded successfully";
+}
+
+Plugin::~Plugin() {
+  if (handle_)
+    dlclose(handle_);
+}
+
+std::string Plugin::Execute(std::string action_model_json) {
+  return execute_function_(action_model_json.c_str());
+}
diff --git a/src/plugin-daemon/plugin.hh b/src/plugin-daemon/plugin.hh
new file mode 100644 (file)
index 0000000..d9c87d2
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2025 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef PLUGIN_DAEMON_PLUGIN_HH_
+#define PLUGIN_DAEMON_PLUGIN_HH_
+
+#include <string>
+
+class Plugin {
+ public:
+  using PluginExecuteFunction = const char* (*)(const char*);
+  explicit Plugin(std::string plugin_path);
+  ~Plugin();
+  std::string Execute(std::string action_model_json);
+
+ private:
+  std::string plugin_path_;
+  void* handle_ = nullptr;
+  PluginExecuteFunction execute_function_;
+};
+
+#endif  // PLUGIN_DAEMON_PLUGIN_HH_