extensions/lua/LuaScriptEngine.cpp (114 lines of code) (raw):
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */
#include <memory>
#include <string>
#include <filesystem>
#include "LuaScriptEngine.h"
#include "LuaProcessSession.h"
#include "LuaScriptProcessContext.h"
#include "utils/StringUtils.h"
namespace org::apache::nifi::minifi::extensions::lua {
LuaScriptEngine::LuaScriptEngine() {
  lua_.open_libraries(sol::lib::base,
      sol::lib::os,
      sol::lib::coroutine,
      sol::lib::math,
      sol::lib::io,
      sol::lib::string,
      sol::lib::table,
      sol::lib::utf8,
      sol::lib::package);
  lua_.new_usertype<core::logging::Logger>(
      "Logger",
      "info", &core::logging::Logger::log_info<>);
  lua_.new_usertype<LuaProcessSession>(
      "ProcessSession",
      "create", static_cast<std::shared_ptr<LuaScriptFlowFile> (LuaProcessSession::*)()>(&LuaProcessSession::create),
      "get", &LuaProcessSession::get,
      "read", &LuaProcessSession::read,
      "write", &LuaProcessSession::write,
      "transfer", &LuaProcessSession::transfer,
      "remove", &LuaProcessSession::remove);
  lua_.new_usertype<LuaScriptFlowFile>(
      "FlowFile",
      "getAttribute", &LuaScriptFlowFile::getAttribute,
      "addAttribute", &LuaScriptFlowFile::addAttribute,
      "removeAttribute", &LuaScriptFlowFile::removeAttribute,
      "updateAttribute", &LuaScriptFlowFile::updateAttribute,
      "setAttribute", &LuaScriptFlowFile::setAttribute);
  lua_.new_usertype<LuaInputStream>(
      "InputStream",
      "read", &LuaInputStream::read);
  lua_.new_usertype<LuaOutputStream>(
      "OutputStream",
      "write", &LuaOutputStream::write);
  lua_.new_usertype<LuaScriptProcessContext>(
      "ProcessContext",
      "getStateManager", &LuaScriptProcessContext::getStateManager);
  lua_.new_usertype<LuaScriptStateManager>(
      "StateManager",
      "set", &LuaScriptStateManager::set,
      "get", &LuaScriptStateManager::get);
}
void LuaScriptEngine::executeScriptWithAppendedModulePaths(std::string& script) {
  for (const auto& module_path : module_paths_) {
    if (std::filesystem::is_regular_file(std::filesystem::status(module_path))) {
      script = utils::StringUtils::join_pack("package.path = package.path .. [[;", module_path.string(), "]]\n", script);
    } else {
      script = utils::StringUtils::join_pack("package.path = package.path .. [[;", module_path.string(), "/?.lua]]\n", script);
    }
  }
  lua_.script(script, sol::script_throw_on_error);
}
void LuaScriptEngine::eval(const std::string& script) {
  try {
    if (!module_paths_.empty()) {
      auto appended_script = script;
      executeScriptWithAppendedModulePaths(appended_script);
    } else {
      lua_.script(script, sol::script_throw_on_error);
    }
  } catch (std::exception& e) {
    throw LuaScriptException(e.what());
  }
}
void LuaScriptEngine::evalFile(const std::filesystem::path& file_name) {
  try {
    if (!module_paths_.empty()) {
      std::ifstream stream(file_name);
      std::string script((std::istreambuf_iterator<char>(stream)), std::istreambuf_iterator<char>());
      executeScriptWithAppendedModulePaths(script);
    } else {
      lua_.script_file(file_name.string(), sol::script_throw_on_error);
    }
  } catch (std::exception& e) {
    throw LuaScriptException(e.what());
  }
}
void LuaScriptEngine::initialize(const core::Relationship& success, const core::Relationship& failure, const std::shared_ptr<core::logging::Logger>& logger) {
  bind("log", logger);
  bind("REL_SUCCESS", success);
  bind("REL_FAILURE", failure);
}
namespace {
class TriggerSession {
 public:
  TriggerSession(std::shared_ptr<LuaScriptProcessContext> script_context,
      std::shared_ptr<LuaProcessSession> lua_session)
      : script_context_(std::move(script_context)),
      lua_session_(std::move(lua_session)) {
  }
  ~TriggerSession() {
    script_context_->releaseProcessContext();
    lua_session_->releaseCoreResources();
  }
 private:
  std::shared_ptr<LuaScriptProcessContext> script_context_;
  std::shared_ptr<LuaProcessSession> lua_session_;
};
}  // namespace
void LuaScriptEngine::onTrigger(const std::shared_ptr<core::ProcessContext>& context, const std::shared_ptr<core::ProcessSession>& session) {
  auto script_context = std::make_shared<LuaScriptProcessContext>(context, lua_);
  auto lua_session = std::make_shared<LuaProcessSession>(session);
  TriggerSession trigger_session(script_context, lua_session);
  call("onTrigger", script_context, lua_session);
}
}  // namespace org::apache::nifi::minifi::extensions::lua