diff --git a/deps/node/src/lwnode/lwnode-public.cc b/deps/node/src/lwnode/lwnode-public.cc index fdf6886a24..1efd417e2d 100644 --- a/deps/node/src/lwnode/lwnode-public.cc +++ b/deps/node/src/lwnode/lwnode-public.cc @@ -64,19 +64,19 @@ Runtime::~Runtime() { delete internal_; } -std::pair Runtime::Init(int argc, - char** argv, - std::promise&& promise) { +int Runtime::Start(int argc, char** argv, std::promise&& promise) { internal_->runner_.SetInitPromise(std::move(promise)); - return internal_->Init(argc, argv); -} + std::pair init_result = internal_->Init(argc, argv); -void Runtime::Free() { - return internal_->Free(); -} + if (init_result.first) { + internal_->Free(); + return init_result.second; + } -int Runtime::Run() { - return internal_->Run(); + int result = internal_->Run(); + internal_->Free(); + + return result; } std::shared_ptr Runtime::GetPort() { diff --git a/deps/node/src/node_main_lw.cc b/deps/node/src/node_main_lw.cc index b7665a529f..1f19438812 100644 --- a/deps/node/src/node_main_lw.cc +++ b/deps/node/src/node_main_lw.cc @@ -72,7 +72,8 @@ int main(int argc, char* argv[]) { setvbuf(stderr, nullptr, _IONBF, 0); lwnode::Runtime runtime; - std::pair init_result; // early_return, exit_code + std::pair init_result; // early_return, exit_code + // FIXME: Fix Runtime::Init() call to ensure environment initialization // before running the loop, Runtime::Run(). This workaround passes a // promise directly to know when that is. @@ -82,20 +83,12 @@ int main(int argc, char* argv[]) { if (!lwnode::InitScriptRootPath()) { exit(-errno); } - char* args[] = {"", "index.js", nullptr}; - init_result = runtime.Init(2, args, std::move(promise)); - } else { - // started by command line - init_result = runtime.Init(argc, argv, std::move(promise)); - } - if (init_result.first) { - runtime.Free(); - return init_result.second; + char* args[] = { + const_cast(""), const_cast("index.js"), nullptr}; + return runtime.Start(2, args, std::move(promise)); } - int result = runtime.Run(); - runtime.Free(); - - return result; + // started by command line + return runtime.Start(argc, argv, std::move(promise)); } diff --git a/examples/tizen/message-port/.gitignore b/examples/tizen/message-port/.gitignore new file mode 100644 index 0000000000..c5c4b541b4 --- /dev/null +++ b/examples/tizen/message-port/.gitignore @@ -0,0 +1,6 @@ +out +lib/ +bin/ +include/ +packaging/*.p12 +.git diff --git a/examples/tizen/message-port/CMakeLists.txt b/examples/tizen/message-port/CMakeLists.txt new file mode 100644 index 0000000000..550ff0d664 --- /dev/null +++ b/examples/tizen/message-port/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.9.4) + +project(lwnode-example-messageport) + +find_library(LWNODE_LIB lwnode HINT lib) + +find_package(PkgConfig REQUIRED) +pkg_check_modules (TIZEN_PKGS REQUIRED dlog) + +set(SAMPLE_DEFINITIONS + -DNODE_ARCH=arm, + -DNODE_PLATFORM=linux, + -DNODE_WANT_INTERNALS=1, +) + +add_executable(${PROJECT_NAME} src/main.cc) +target_include_directories(${PROJECT_NAME} PRIVATE "include" ${TIZEN_PKGS_INCLUDE_DIRS}) +target_link_libraries(${PROJECT_NAME} PRIVATE ${LWNODE_LIB} ${TIZEN_PKGS_LIBRARIES} -pthread -Wl,-rpath='\$\$ORIGIN/../lib') +target_link_directories(${PROJECT_NAME} PRIVATE ${TIZEN_PKGS_LIBRARY_DIRS}) +target_compile_definitions(${PROJECT_NAME} PRIVATE ${SAMPLE_DEFINITIONS}) + diff --git a/examples/tizen/message-port/README.md b/examples/tizen/message-port/README.md new file mode 100644 index 0000000000..283afe4fa9 --- /dev/null +++ b/examples/tizen/message-port/README.md @@ -0,0 +1,43 @@ + +### Copy lightweight node header and library + - copy `liblwnode.so` to `lib` folder + - copy `libescargot.so` to `lib` folder + - copy `lwnode.dat` to `bin` folder + - copy `lwnode-public.h` to `include` folder + - copy `message-port.h` to `include` folder +```bash +cd +cp /out/tizen/arm/Release/lib/liblwnode.so ./lib/ +cp /out/tizen/arm/Release/gen/escargot/libescargot.so ./lib/ +cp /out/tizen/arm/Release/lwnode.dat ./bin/ +cp /include/lwnode/lwnode-public.h ./include/ +cp /include/lwnode/message-port.h ./include/ +``` + +### Copy certification profile files + - If you want to sign your app, copy some files to `packaging` folder. +```bash +cp tizen_author.p12 ./packaging/ +cp tizen-distributor-partner-manufacturer-signer.p12 ./packaging/ +``` + +### Edit packaging/lwnode-example-messageport.spec + - You should input signer url in spec file. + ``` + %define _signer_url http://x.x.x.x/kuep_net_signer.sh + ``` + +### Package tpk + - To package tpk, you should build gbs. +For example, +``` bash +gbs -c ~/gbs.conf build -A armv7l -B ~/GBS-ROOT/helloworld --incremental --include-all +``` +After build, you can find tpk file in `out` folder. + + +### Show log + - To view node console log, use `dlogutil lwnode` command. +``` bash +dlogutil lwnode +``` diff --git a/examples/tizen/message-port/packaging/lwnode-example-messageport.manifest b/examples/tizen/message-port/packaging/lwnode-example-messageport.manifest new file mode 100644 index 0000000000..a76fdbae7d --- /dev/null +++ b/examples/tizen/message-port/packaging/lwnode-example-messageport.manifest @@ -0,0 +1,5 @@ + + + + + diff --git a/examples/tizen/message-port/packaging/lwnode-example-messageport.spec b/examples/tizen/message-port/packaging/lwnode-example-messageport.spec new file mode 100644 index 0000000000..c7ae4ead15 --- /dev/null +++ b/examples/tizen/message-port/packaging/lwnode-example-messageport.spec @@ -0,0 +1,104 @@ +Name: lwnode-example-messageport +Summary: - +Version: 1.0.0 +Release: 1 +Group: System/Servers +License: MIT +Source: %{name}-%{version}.tar.gz +Source1001: lwnode-example-messageport.manifest + +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig + +%if ("%{tizen_version}" >= "7.0") +BuildRequires: sdk-core +BuildRequires: sdk-rootstraps +%else +BuildRequires: builtin-java +BuildRequires: builtin-tizensdk, builtin-tizensdk-rootstraps +BuildRequires: app-signer, python-xml +%endif + +BuildRequires: cmake, ninja +BuildRequires: rsync +BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(glib-2.0) +BuildRequires: pkgconfig(aul) +BuildRequires: pkgconfig(capi-appfw-app-common) + +%define _signer_url http://<>/kuep_net_signer.sh + +%description +sample + +# Configure + +# Initialize the variables +%define _output ./out +%define _native_out ./out/%{name} +%define _jsroot res +%define _lib_dist ./out/project/%{_jsroot}/lib +%define _native_dist ./out/project/%{_jsroot}/lib/build +%define _project ./out/project +%define _certi ./packaging + +%prep +%setup -q + +%build +mkdir -p %{_native_out} +cmake . -B%{_native_out} -H. -G Ninja +ninja -v -C %{_native_out} + +# project scaffolding +rm -rf %{_project} +mkdir -p %{_project}/%{_jsroot} + +# copy lwnode binary +cp -rf bin %{_project} +cp -rf lib %{_project} + +# copy JavaScript files +rsync -avm --include='*.js' -f 'hide,! */' ./%{_jsroot}/* %{_project}/%{_jsroot} +rsync -avm --include='*.node' -f 'hide,! */' ./%{_jsroot}/* %{_project}/%{_jsroot} +rsync -avm --include='*.json' -f 'hide,! */' ./%{_jsroot}/* %{_project}/%{_jsroot} +cp -rf tizen-manifest.xml %{_project} + +# copy exec file +cp -f %{_native_out}/%{name} %{_project}/bin + +# setup tizen certificate profile +tizen cli-config "profiles.path=%{_prefix}/tizen-studio-data/profile/profiles.xml" +tizen security-profiles add -n ABS -a %{_certi}/tizen_author.p12 -p \ + tizenauthor -d %{_certi}/tizen-distributor-partner-manufacturer-signer.p12 \ + -dp tizenpkcs12passfordsigner + +# signing +curl -o ./kuep_net_signer.sh %{_signer_url} && chmod +x ./kuep_net_signer.sh +./kuep_net_signer.sh -s -tizen_major_ver %{?tizen_version_major} %{_project}/lib/liblwnode.* +./kuep_net_signer.sh -s -tizen_major_ver %{?tizen_version_major} %{_project}/lib/libescargot.* +./kuep_net_signer.sh -s -tizen_major_ver %{?tizen_version_major} %{_project}/bin/%{name} + +# packaging +cd %{_project} +zip ../%{name}.tpk * -r +cd - > /dev/null +tizen package -t tpk -s ABS -- %{_output}/%{name}.tpk + +%install + +%clean +rm -f ./*.list +rm -f ./*.manifest +rm -rf %{_project} +rm -rf %{_native_out} +rm -f kuep_net_signer.sh + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%defattr(-,root,root,-) diff --git a/examples/tizen/message-port/res/index.js b/examples/tizen/message-port/res/index.js new file mode 100644 index 0000000000..2b6931b46e --- /dev/null +++ b/examples/tizen/message-port/res/index.js @@ -0,0 +1,21 @@ +console.log('[JS] started...'); + +const lwnode = process.lwnode; +const port = process.lwnode.port; + +// Keep the process alive until we receive a message. +// lwnode is not terminated until lwnode.unref() is called, which decreases the reference count. +lwnode.ref(); + +// Listen for messages from the native app. +port.onmessage = (event) => { + console.log(`[JS] receive ${event.data}`); + if (event.data == "ping") { + + // send a response back to the native app. (c -> js) + port.postMessage("pong"); + + // Unref the process. If you want to keep it alive, remove this line. + lwnode.unref(); + } +}; diff --git a/examples/tizen/message-port/src/main.cc b/examples/tizen/message-port/src/main.cc new file mode 100644 index 0000000000..afb22410a3 --- /dev/null +++ b/examples/tizen/message-port/src/main.cc @@ -0,0 +1,64 @@ +#include +#include +#include +#include + +#include "lwnode-public.h" + +#define APP_LOG_TAG "lwnode" + +int main(int argc, char* argv[]) { + dlog_print( + DLOG_INFO, APP_LOG_TAG, "[Native] message-port example app started..."); + + std::promise promise; + std::future init_future = promise.get_future(); + + auto runtime = std::make_shared(); + + std::thread t([&]() { + dlog_print(DLOG_INFO, APP_LOG_TAG, "[Native] start thread"); + + lwnode::SetDlogID(APP_LOG_TAG); // set dlog tag for lwnode + + std::string path = "/opt/usr/apps/lwnode-example-messageport/res/"; + + if (!lwnode::InitScriptRootPath(path)) { + dlog_print(DLOG_ERROR, + APP_LOG_TAG, + "[Native] fail to set script root path: %s", + path.c_str()); + + return; + } + + char* args[] = { + const_cast(""), const_cast("index.js"), nullptr}; + + dlog_print(DLOG_INFO, APP_LOG_TAG, "[Native] runtime.Start() called..."); + runtime->Start(2, args, std::move(promise)); + + dlog_print(DLOG_INFO, APP_LOG_TAG, "[Native] end thread"); + }); + + // Wait until the js script is initialized to get the port. + init_future.wait(); + + std::shared_ptr port = runtime->GetPort(); + + // Register a callback function to receive messages from the js script. + port->OnMessage([](const MessageEvent* event) { + dlog_print(DLOG_INFO, + APP_LOG_TAG, + "[Native] received message from js: %s", + event->data().c_str()); + }); + + // Send a message to the js script. The main script will send back a + // message. + port->PostMessage(MessageEvent::New("ping")); + + t.join(); + + return 0; +} diff --git a/examples/tizen/message-port/tizen-manifest.xml b/examples/tizen/message-port/tizen-manifest.xml new file mode 100644 index 0000000000..4d1e370e08 --- /dev/null +++ b/examples/tizen/message-port/tizen-manifest.xml @@ -0,0 +1,11 @@ + + + + + service.png + + + + + + diff --git a/include/lwnode/lwnode-public.h b/include/lwnode/lwnode-public.h index befb4665fd..014ca0b1bc 100644 --- a/include/lwnode/lwnode-public.h +++ b/include/lwnode/lwnode-public.h @@ -31,16 +31,20 @@ namespace lwnode { LWNODE_EXPORT bool ParseAULEvent(int argc, char** argv); -// Sets the path of the root directory of the JavaScript. If you do -// not put the path argument, the root path is the app's resource path by -// default on Tizen AUL mode. Be sure to call this function before lwnode::Start -// function. +/** + * Sets the path of the root directory of the JavaScript. If you do + * not put the path argument, the root path is the app's resource path by + * default on Tizen AUL mode. Be sure to call this function before lwnode::Start + * function. + **/ LWNODE_EXPORT bool InitScriptRootPath(const std::string path = ""); LWNODE_EXPORT int Start(int argc, char** argv); -// Sets the dlog tag id for debugging. This is only used on Tizen when not in -// AUL mode. +/** + * Sets the dlog tag id for debugging. This is only used on Tizen when not in + * AUL mode. + **/ LWNODE_EXPORT void SetDlogID(const std::string& appId); class LWNODE_EXPORT Runtime { @@ -48,18 +52,18 @@ class LWNODE_EXPORT Runtime { Runtime(); ~Runtime(); - // Initializes the runtime and returns true if it early termination and sets - // the exit code to the second return value. Otherwise, it returns false - // and you need call Run() to run the runtime. - std::pair Init(int argc, - char** argv, - std::promise&& promise); - - // Runs the runtime and returns the exit code. The runtime must be - // initialized. - int Run(); - - void Free(); + /** + * Start the runtime and returns the exit code. It initializes the runtime + * and runs it. When the runtime is initialized, the promise object is set. + * + * @param argc - Argument count. + * @param argv - Argument vector. The element should be the starting file + * name of the application. + * @param promise - Promise object. It will be set when the runtime + * initialization is complete. + * @return Returns the exit code of the runtime. + **/ + int Start(int argc, char** argv, std::promise&& promise); std::shared_ptr GetPort(); diff --git a/test/embedding/embedtest.cc b/test/embedding/embedtest.cc index 6947dec12f..0e55c50e22 100644 --- a/test/embedding/embedtest.cc +++ b/test/embedding/embedtest.cc @@ -42,9 +42,7 @@ TEST0(Embedtest, MessagePort2_Post_Many_JS_First) { std::thread worker = std::thread( [&](std::promise&& promise) mutable { - runtime->Init(COUNT_OF(args), args, std::move(promise)); - runtime->Run(); - runtime->Free(); + runtime->Start(COUNT_OF(args), args, std::move(promise)); }, std::move(promise)); diff --git a/test/embedding/example.cc b/test/embedding/example.cc index a5fa49412d..7caafe0d3c 100644 --- a/test/embedding/example.cc +++ b/test/embedding/example.cc @@ -22,9 +22,7 @@ int main(int argc, char* argv[]) { // FIXME: Fix Runtime::Init() call to ensure environment initialization // before running the loop, Runtime::Run(). This workaround passes a // promise directly to know when that is. - runtime->Init(COUNT_OF(args), args, std::move(promise)); - runtime->Run(); - runtime->Free(); + runtime->Start(COUNT_OF(args), args, std::move(promise)); }, std::move(promise));