@mobrowser/native 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/cmake/MoBrowser.cmake +80 -0
- package/cmake/Platform.cmake +13 -0
- package/cmake/Protobuf.cmake +121 -0
- package/include/callback.h +152 -0
- package/include/rpc.h +14 -0
- package/include/service.h +98 -0
- package/internal/export.h +14 -0
- package/internal/rpc.cc +20 -0
- package/internal/transport.cc +66 -0
- package/internal/transport.h +52 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
This package contains the configuration files for MōBrowser native integration.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
message(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
|
2
|
+
|
|
3
|
+
include(${PROJECT_ROOT_DIR}/node_modules/@mobrowser/native/cmake/Platform.cmake)
|
|
4
|
+
|
|
5
|
+
# Configure project properties.
|
|
6
|
+
set(TARGET_NAME "app")
|
|
7
|
+
set(STATIC_LIB_NAME "mobrowser_lib")
|
|
8
|
+
set(SHARED_LIB_NAME "mobrowser_client")
|
|
9
|
+
set(DIST_DIR ${CMAKE_BINARY_DIR}/bin)
|
|
10
|
+
|
|
11
|
+
# Configure SDK directory.
|
|
12
|
+
if (OS_WIN)
|
|
13
|
+
set(MOBROWSER_SDK_DIR "${PROJECT_ROOT_DIR}/node_modules/@mobrowser/sdk-win-x64")
|
|
14
|
+
elseif (OS_MAC)
|
|
15
|
+
set(MOBROWSER_SDK_DIR "${PROJECT_ROOT_DIR}/node_modules/@mobrowser/sdk-darwin-arm64")
|
|
16
|
+
elseif (OS_LINUX)
|
|
17
|
+
set(MOBROWSER_SDK_DIR "${PROJECT_ROOT_DIR}/node_modules/@mobrowser/sdk-linux-x64")
|
|
18
|
+
endif ()
|
|
19
|
+
|
|
20
|
+
cmake_path(ABSOLUTE_PATH MOBROWSER_SDK_DIR NORMALIZE)
|
|
21
|
+
message(STATUS "MOBROWSER_SDK_DIR: ${MOBROWSER_SDK_DIR}")
|
|
22
|
+
set(MOBROWSER_SDK_NATIVE_DIR "${PROJECT_ROOT_DIR}/node_modules/@mobrowser/native")
|
|
23
|
+
cmake_path(ABSOLUTE_PATH MOBROWSER_SDK_NATIVE_DIR NORMALIZE)
|
|
24
|
+
|
|
25
|
+
if (MSVC)
|
|
26
|
+
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
|
27
|
+
add_compile_options(/MP)
|
|
28
|
+
# Suppress Protobuf warnings
|
|
29
|
+
add_compile_options(
|
|
30
|
+
/wd4065 # switch statement contains 'default' but no 'case' labels
|
|
31
|
+
/wd4047 # 'operator' : 'identifier1' differs in levels of indirection from 'identifier2'
|
|
32
|
+
/wd4146 # unary minus operator applied to unsigned type
|
|
33
|
+
/wd4244 # 'conversion' conversion from 'type1' to 'type2', possible loss of data
|
|
34
|
+
/wd4251 # 'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'
|
|
35
|
+
/wd4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data
|
|
36
|
+
/wd4305 # 'identifier' : truncation from 'type1' to 'type2'
|
|
37
|
+
/wd4307 # 'operator' : integral constant overflow
|
|
38
|
+
/wd4309 # 'conversion' : truncation of constant value
|
|
39
|
+
/wd4334 # 'operator' : result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)
|
|
40
|
+
/wd4355 # 'this' : used in base member initializer list
|
|
41
|
+
/wd4506 # no definition for inline function 'function'
|
|
42
|
+
/wd4800 # 'type' : forcing value to bool 'true' or 'false' (performance warning)
|
|
43
|
+
/wd4996 # The compiler encountered a deprecated declaration.
|
|
44
|
+
/wd4715 # 'function' : not all control paths return a value
|
|
45
|
+
/wd5287 # operands are different enum types
|
|
46
|
+
)
|
|
47
|
+
else ()
|
|
48
|
+
# Suppress Protobuf warnings for Clang/GCC
|
|
49
|
+
add_compile_options(
|
|
50
|
+
-Wno-deprecated-declarations
|
|
51
|
+
)
|
|
52
|
+
endif ()
|
|
53
|
+
|
|
54
|
+
# Suppress Protobuf linker warnings
|
|
55
|
+
if (APPLE)
|
|
56
|
+
add_link_options("-Wl,-no_warn_duplicate_libraries")
|
|
57
|
+
endif ()
|
|
58
|
+
|
|
59
|
+
if (OS_LINUX)
|
|
60
|
+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
|
61
|
+
endif ()
|
|
62
|
+
|
|
63
|
+
include(${PROJECT_ROOT_DIR}/node_modules/@mobrowser/native/cmake/Protobuf.cmake)
|
|
64
|
+
|
|
65
|
+
# Create the shared library mobrowser_client with MoBrowser runtime
|
|
66
|
+
add_library(${SHARED_LIB_NAME} SHARED
|
|
67
|
+
${GENERATED_SOURCES}
|
|
68
|
+
${MOBROWSER_SDK_NATIVE_DIR}/internal/rpc.cc
|
|
69
|
+
${MOBROWSER_SDK_NATIVE_DIR}/internal/transport.cc)
|
|
70
|
+
|
|
71
|
+
# Set up include paths for mobrowser_client
|
|
72
|
+
target_include_directories(${SHARED_LIB_NAME} PRIVATE
|
|
73
|
+
${protobuf_SOURCE_DIR}/src
|
|
74
|
+
${absl_SOURCE_DIR}
|
|
75
|
+
${PROJECT_SOURCE_DIR}/native/gen
|
|
76
|
+
${MOBROWSER_SDK_NATIVE_DIR}/include
|
|
77
|
+
${MOBROWSER_SDK_DIR}/include)
|
|
78
|
+
|
|
79
|
+
# Link mobrowser_lib into mobrowser_client
|
|
80
|
+
target_link_libraries(${SHARED_LIB_NAME} PRIVATE ${STATIC_LIB_NAME} libprotobuf)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
if (${CMAKE_SYSTEM_NAME} MATCHES Windows)
|
|
2
|
+
set(OS_WIN TRUE)
|
|
3
|
+
add_definitions(-DOS_WIN)
|
|
4
|
+
elseif (${CMAKE_SYSTEM_NAME} MATCHES Linux)
|
|
5
|
+
set(OS_LINUX TRUE)
|
|
6
|
+
add_definitions(-DOS_LINUX)
|
|
7
|
+
elseif (${CMAKE_SYSTEM_NAME} MATCHES Darwin)
|
|
8
|
+
set(OS_MAC TRUE)
|
|
9
|
+
add_definitions(-DOS_MAC)
|
|
10
|
+
# Set minimum macOS version to 12.0 for broader compatibility
|
|
11
|
+
# Use FORCE to ensure this overrides any cached value
|
|
12
|
+
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum macOS deployment version" FORCE)
|
|
13
|
+
endif ()
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
include(FetchContent)
|
|
2
|
+
|
|
3
|
+
set(FETCHCONTENT_QUIET OFF)
|
|
4
|
+
set(BUILD_TESTING OFF)
|
|
5
|
+
|
|
6
|
+
set(PROTOBUF_VERSION 33.2)
|
|
7
|
+
|
|
8
|
+
if (NOT DEFINED PROTO_DIR)
|
|
9
|
+
file(REAL_PATH "${PROJECT_ROOT_DIR}/src/native/proto" PROTO_DIR)
|
|
10
|
+
endif ()
|
|
11
|
+
|
|
12
|
+
# Replace backslashes with forward slashes to fix path issue
|
|
13
|
+
# when parsing the path with backslashes in CMake.
|
|
14
|
+
string(REPLACE "\\" "/" PROTO_DIR "${PROTO_DIR}")
|
|
15
|
+
|
|
16
|
+
message(STATUS "Proto dir: ${PROTO_DIR}")
|
|
17
|
+
|
|
18
|
+
file(GLOB_RECURSE PROTO_FILES CONFIGURE_DEPENDS "${PROTO_DIR}/*.proto")
|
|
19
|
+
|
|
20
|
+
# Ensure protobuf (and everything else) inherits the macOS deployment target
|
|
21
|
+
if (APPLE)
|
|
22
|
+
if (NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET)
|
|
23
|
+
set(CMAKE_OSX_DEPLOYMENT_TARGET "12.0" CACHE STRING "Minimum macOS deployment version")
|
|
24
|
+
endif ()
|
|
25
|
+
endif ()
|
|
26
|
+
|
|
27
|
+
# Verify C++17 or higher is set (required by Abseil).
|
|
28
|
+
if (NOT DEFINED CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 17)
|
|
29
|
+
message(FATAL_ERROR "CMAKE_CXX_STANDARD must be set to 17 or higher before including MoBrowser.cmake")
|
|
30
|
+
endif ()
|
|
31
|
+
|
|
32
|
+
# ##############################################################################
|
|
33
|
+
# Protobuf (with automatic Abseil fetching)
|
|
34
|
+
# ##############################################################################
|
|
35
|
+
message(CHECK_START "Fetching Protobuf")
|
|
36
|
+
list(APPEND CMAKE_MESSAGE_INDENT " ")
|
|
37
|
+
|
|
38
|
+
# Abseil options
|
|
39
|
+
set(ABSL_USE_SYSTEM_INCLUDES ON CACHE BOOL "Use system includes for Abseil")
|
|
40
|
+
set(ABSL_PROPAGATE_CXX_STD ON CACHE BOOL "Propagate C++ standard from consumers")
|
|
41
|
+
set(ABSL_ENABLE_INSTALL OFF CACHE BOOL "Enable install rules for Abseil")
|
|
42
|
+
set(ABSL_BUILD_TESTING OFF CACHE BOOL "Build Abseil tests")
|
|
43
|
+
set(ABSL_BUILD_TEST_HELPERS OFF CACHE BOOL "Build Abseil test helpers")
|
|
44
|
+
set(ABSL_USE_EXTERNAL_GOOGLETEST ON CACHE BOOL "Use external GTest when needed")
|
|
45
|
+
set(ABSL_FIND_GOOGLETEST OFF CACHE BOOL "Let Abseil find GTest on its own")
|
|
46
|
+
set(ABSL_MSVC_STATIC_RUNTIME ON CACHE BOOL "Use static runtime with MSVC")
|
|
47
|
+
|
|
48
|
+
# Protobuf options
|
|
49
|
+
set(protobuf_BUILD_TESTS OFF CACHE BOOL "Do not build Protobuf tests")
|
|
50
|
+
set(protobuf_BUILD_SHARED_LIBS OFF CACHE BOOL "Build Protobuf as static libs")
|
|
51
|
+
set(protobuf_BUILD_EXPORT OFF CACHE BOOL "Do not export Protobuf CMake targets")
|
|
52
|
+
set(protobuf_INSTALL OFF CACHE BOOL "Disable Protobuf install rules")
|
|
53
|
+
set(protobuf_BUILD_LIBUPB ON CACHE BOOL "Build libupb for Protobuf")
|
|
54
|
+
set(protobuf_MSVC_STATIC_RUNTIME ON CACHE BOOL "Use static runtime with MSVC")
|
|
55
|
+
set(protobuf_FORCE_FETCH_DEPENDENCIES ON CACHE BOOL "Let Protobuf fetch Abseil and utf8_range")
|
|
56
|
+
set(utf8_range_ENABLE_INSTALL OFF CACHE BOOL "Disable utf8_range install rules")
|
|
57
|
+
|
|
58
|
+
FetchContent_Declare(
|
|
59
|
+
Protobuf
|
|
60
|
+
GIT_REPOSITORY "https://github.com/protocolbuffers/protobuf.git"
|
|
61
|
+
GIT_TAG "v${PROTOBUF_VERSION}"
|
|
62
|
+
GIT_SHALLOW TRUE
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
FetchContent_MakeAvailable(Protobuf)
|
|
66
|
+
|
|
67
|
+
list(POP_BACK CMAKE_MESSAGE_INDENT)
|
|
68
|
+
message(CHECK_PASS "fetched")
|
|
69
|
+
|
|
70
|
+
# ##############################################################################
|
|
71
|
+
# Protobuf code generation
|
|
72
|
+
# ##############################################################################
|
|
73
|
+
|
|
74
|
+
# Ensure output directory exists
|
|
75
|
+
file(MAKE_DIRECTORY "${PROJECT_SOURCE_DIR}/src/native/gen")
|
|
76
|
+
|
|
77
|
+
# Set proto paths for protoc command
|
|
78
|
+
set(PROTOBUF_IMPORT_DIRS "${protobuf_SOURCE_DIR}/src" "${PROTO_DIR}")
|
|
79
|
+
|
|
80
|
+
set(GENERATED_SOURCES)
|
|
81
|
+
foreach (f IN LISTS PROTO_FILES)
|
|
82
|
+
# Get file name without extension: foo/bar/baz.proto -> baz
|
|
83
|
+
get_filename_component(proto_name "${f}" NAME_WE)
|
|
84
|
+
|
|
85
|
+
# Map proto path under .../proto/... to .../src/native/gen/...
|
|
86
|
+
# e.g. <root>/proto/foo/bar/baz.proto -> <root>/src/native/gen/foo/bar/baz.pb.cc
|
|
87
|
+
string(REGEX REPLACE ".*/proto/" "${PROJECT_SOURCE_DIR}/src/native/gen/" base_path_with_ext "${f}")
|
|
88
|
+
# Remove the .proto extension from base_path
|
|
89
|
+
string(REGEX REPLACE "\\.proto$" "" base_path "${base_path_with_ext}")
|
|
90
|
+
|
|
91
|
+
set(msg_header "${base_path}.pb.h")
|
|
92
|
+
set(msg_source "${base_path}.pb.cc")
|
|
93
|
+
set(rpc_header "${base_path}.rpc.h")
|
|
94
|
+
set(rpc_source "${base_path}.rpc.cc")
|
|
95
|
+
|
|
96
|
+
list(APPEND GENERATED_SOURCES
|
|
97
|
+
"${msg_header}" "${msg_source}"
|
|
98
|
+
"${rpc_header}" "${rpc_source}")
|
|
99
|
+
endforeach ()
|
|
100
|
+
|
|
101
|
+
# Build protoc command arguments
|
|
102
|
+
set(PROTOC_ARGS)
|
|
103
|
+
foreach(dir ${PROTOBUF_IMPORT_DIRS})
|
|
104
|
+
list(APPEND PROTOC_ARGS --proto_path=${dir})
|
|
105
|
+
endforeach()
|
|
106
|
+
|
|
107
|
+
set(CC_NATIVEGEN_PLUGIN "${MOBROWSER_SDK_DIR}/bin/cc_nativegen${CMAKE_EXECUTABLE_SUFFIX}")
|
|
108
|
+
|
|
109
|
+
add_custom_command(
|
|
110
|
+
OUTPUT ${GENERATED_SOURCES}
|
|
111
|
+
COMMAND $<TARGET_FILE:protoc>
|
|
112
|
+
${PROTOC_ARGS}
|
|
113
|
+
--cpp_out=${PROJECT_SOURCE_DIR}/src/native/gen
|
|
114
|
+
--plugin=protoc-gen-rpc=${CC_NATIVEGEN_PLUGIN}
|
|
115
|
+
--rpc_out=${PROJECT_SOURCE_DIR}/src/native/gen
|
|
116
|
+
${PROTO_FILES}
|
|
117
|
+
DEPENDS ${PROTO_FILES} protoc ${CC_NATIVEGEN_PLUGIN}
|
|
118
|
+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
|
119
|
+
COMMENT "Generating C++ sources from .proto files"
|
|
120
|
+
VERBATIM
|
|
121
|
+
)
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// Copyright (c) 2000-2026 TeamDev. All rights reserved.
|
|
2
|
+
// TeamDev PROPRIETARY and CONFIDENTIAL.
|
|
3
|
+
// Use is subject to license terms.
|
|
4
|
+
|
|
5
|
+
#ifndef MO_RPC_CALLBACK_H_
|
|
6
|
+
#define MO_RPC_CALLBACK_H_
|
|
7
|
+
|
|
8
|
+
#include <cstddef>
|
|
9
|
+
#include <functional>
|
|
10
|
+
#include <memory>
|
|
11
|
+
#include <mutex>
|
|
12
|
+
#include <string>
|
|
13
|
+
#include <utility>
|
|
14
|
+
|
|
15
|
+
#include "google/protobuf/message.h"
|
|
16
|
+
|
|
17
|
+
namespace mo::rpc {
|
|
18
|
+
|
|
19
|
+
template<class T>
|
|
20
|
+
concept ProtobufMessageType = std::is_base_of<google::protobuf::Message, T>::value;
|
|
21
|
+
|
|
22
|
+
// Type-erased callback handlers for RPC operations.
|
|
23
|
+
// These work with serialized protobuf data and are independent of message type.
|
|
24
|
+
using OnCompleteHandler = std::function<void(uint64_t id, const char* data, size_t size)>;
|
|
25
|
+
using OnRejectHandler = std::function<void(uint64_t id, const char* error)>;
|
|
26
|
+
|
|
27
|
+
// A move-only, one-shot RPC callback for completing or rejecting an
|
|
28
|
+
// asynchronous operation.
|
|
29
|
+
//
|
|
30
|
+
// Thread Safety:
|
|
31
|
+
// - All public methods are thread-safe and may be called from any thread.
|
|
32
|
+
// - Only one of Complete(), Reject(), or auto-cancel will fire; subsequent
|
|
33
|
+
// calls are no-ops.
|
|
34
|
+
//
|
|
35
|
+
// Usage:
|
|
36
|
+
// std::move(callback).Complete(response); // Success path
|
|
37
|
+
// std::move(callback).Reject("error"); // Failure path
|
|
38
|
+
// // Or let it destruct to auto-cancel
|
|
39
|
+
//
|
|
40
|
+
template <ProtobufMessageType T>
|
|
41
|
+
class Callback {
|
|
42
|
+
public:
|
|
43
|
+
// Constructs a callback with the given completion and rejection handlers.
|
|
44
|
+
Callback(uint64_t id, OnCompleteHandler on_complete, OnRejectHandler on_reject)
|
|
45
|
+
: id_(id),
|
|
46
|
+
on_complete_(std::move(on_complete)),
|
|
47
|
+
on_reject_(std::move(on_reject)),
|
|
48
|
+
is_pending_(true),
|
|
49
|
+
mutex_(std::make_unique<std::mutex>()) {}
|
|
50
|
+
|
|
51
|
+
// Non-copyable.
|
|
52
|
+
Callback(const Callback&) = delete;
|
|
53
|
+
Callback& operator=(const Callback&) = delete;
|
|
54
|
+
|
|
55
|
+
// Move constructor. The source callback becomes inert (already handled).
|
|
56
|
+
Callback(Callback&& other) noexcept : mutex_(std::make_unique<std::mutex>()) {
|
|
57
|
+
std::lock_guard<std::mutex> lock(*other.mutex_);
|
|
58
|
+
id_ = other.id_;
|
|
59
|
+
on_complete_ = std::move(other.on_complete_);
|
|
60
|
+
on_reject_ = std::move(other.on_reject_);
|
|
61
|
+
is_pending_ = other.is_pending_;
|
|
62
|
+
other.is_pending_ = false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Move assignment. Auto-cancels any pending operation on this callback
|
|
66
|
+
// before taking ownership from the source.
|
|
67
|
+
Callback& operator=(Callback&& other) noexcept {
|
|
68
|
+
if (this != &other) {
|
|
69
|
+
AutoCancelIfPending();
|
|
70
|
+
std::lock_guard<std::mutex> lock(*other.mutex_);
|
|
71
|
+
id_ = other.id_;
|
|
72
|
+
on_complete_ = std::move(other.on_complete_);
|
|
73
|
+
on_reject_ = std::move(other.on_reject_);
|
|
74
|
+
is_pending_ = other.is_pending_;
|
|
75
|
+
other.is_pending_ = false;
|
|
76
|
+
}
|
|
77
|
+
return *this;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Destructor. Auto-cancels if still pending.
|
|
81
|
+
~Callback() { AutoCancelIfPending(); }
|
|
82
|
+
|
|
83
|
+
// Completes the callback successfully with the given response.
|
|
84
|
+
//
|
|
85
|
+
// This is a one-shot operation; if already handled (completed, rejected, or
|
|
86
|
+
// moved-from), this call is a no-op.
|
|
87
|
+
//
|
|
88
|
+
// Note: The `&&` qualifier indicates this consumes the callback. Use with
|
|
89
|
+
// std::move: `std::move(callback).Complete(response);`
|
|
90
|
+
void Complete(T response) && {
|
|
91
|
+
std::unique_lock<std::mutex> lock(*mutex_);
|
|
92
|
+
if (!is_pending_) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
is_pending_ = false;
|
|
96
|
+
OnCompleteHandler handler = std::move(on_complete_);
|
|
97
|
+
on_reject_ = nullptr;
|
|
98
|
+
lock.unlock();
|
|
99
|
+
auto buffer = response.SerializeAsString();
|
|
100
|
+
handler(id_, buffer.data(), buffer.size());
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Rejects the callback with an error message.
|
|
104
|
+
//
|
|
105
|
+
// This is a one-shot operation; if already handled (completed, rejected, or
|
|
106
|
+
// moved-from), this call is a no-op.
|
|
107
|
+
//
|
|
108
|
+
// Note: The `&&` qualifier indicates this consumes the callback. Use with
|
|
109
|
+
// std::move: `std::move(callback).Reject("error message");`
|
|
110
|
+
void Reject(std::string error) && {
|
|
111
|
+
std::unique_lock<std::mutex> lock(*mutex_);
|
|
112
|
+
if (!is_pending_) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
is_pending_ = false;
|
|
116
|
+
OnRejectHandler handler = std::move(on_reject_);
|
|
117
|
+
on_complete_ = nullptr;
|
|
118
|
+
lock.unlock();
|
|
119
|
+
handler(id_, error.c_str());
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private:
|
|
123
|
+
// Auto-cancels the callback if still pending by invoking the rejection
|
|
124
|
+
// handler with a cancellation message.
|
|
125
|
+
void AutoCancelIfPending() {
|
|
126
|
+
std::unique_lock<std::mutex> lock(*mutex_);
|
|
127
|
+
if (!is_pending_ || !on_reject_) {
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
is_pending_ = false;
|
|
131
|
+
OnRejectHandler handler = std::move(on_reject_);
|
|
132
|
+
on_complete_ = nullptr;
|
|
133
|
+
lock.unlock();
|
|
134
|
+
handler(id_, "RPC canceled: callback destroyed without completion.");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
uint64_t id_;
|
|
138
|
+
OnCompleteHandler on_complete_;
|
|
139
|
+
OnRejectHandler on_reject_;
|
|
140
|
+
|
|
141
|
+
// True if neither Complete() nor Reject() has been called yet.
|
|
142
|
+
// Protected by mutex_.
|
|
143
|
+
bool is_pending_;
|
|
144
|
+
|
|
145
|
+
// Mutex protecting internal state.
|
|
146
|
+
// Stored as unique_ptr to ensure stable address across moves
|
|
147
|
+
std::unique_ptr<std::mutex> mutex_;
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
} // namespace mo::rpc
|
|
151
|
+
|
|
152
|
+
#endif // MO_RPC_CALLBACK_H_
|
package/include/rpc.h
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) 2000-2026 TeamDev. All rights reserved.
|
|
2
|
+
// TeamDev PROPRIETARY and CONFIDENTIAL.
|
|
3
|
+
// Use is subject to license terms.
|
|
4
|
+
|
|
5
|
+
#ifndef MO_RPC_H_
|
|
6
|
+
#define MO_RPC_H_
|
|
7
|
+
|
|
8
|
+
#include "service.h"
|
|
9
|
+
|
|
10
|
+
namespace mo::rpc {
|
|
11
|
+
void RegisterService(Service* service);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
#endif // MO_RPC_H_
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// Copyright (c) 2000-2026 TeamDev. All rights reserved.
|
|
2
|
+
// TeamDev PROPRIETARY and CONFIDENTIAL.
|
|
3
|
+
// Use is subject to license terms.
|
|
4
|
+
|
|
5
|
+
#ifndef MO_RPC_SERVICE_H_
|
|
6
|
+
#define MO_RPC_SERVICE_H_
|
|
7
|
+
|
|
8
|
+
#include <string>
|
|
9
|
+
|
|
10
|
+
#include "callback.h"
|
|
11
|
+
|
|
12
|
+
namespace google::protobuf {
|
|
13
|
+
class ServiceDescriptor;
|
|
14
|
+
class MethodDescriptor;
|
|
15
|
+
class Message;
|
|
16
|
+
} // namespace google::protobuf
|
|
17
|
+
|
|
18
|
+
namespace mo::rpc {
|
|
19
|
+
|
|
20
|
+
// Abstract base class for all generated RPC services.
|
|
21
|
+
//
|
|
22
|
+
// This class defines the interface that all generated services must implement.
|
|
23
|
+
// It allows for dynamic invocation of service methods through a generic
|
|
24
|
+
// interface.
|
|
25
|
+
class Service {
|
|
26
|
+
public:
|
|
27
|
+
inline Service() {}
|
|
28
|
+
|
|
29
|
+
Service(const Service&) = delete;
|
|
30
|
+
Service& operator=(const Service&) = delete;
|
|
31
|
+
virtual ~Service() = default;
|
|
32
|
+
|
|
33
|
+
// Returns the descriptor for this service.
|
|
34
|
+
//
|
|
35
|
+
// The ServiceDescriptor contains metadata about the service, including its
|
|
36
|
+
// name, the methods it implements, and their signatures. This is used for
|
|
37
|
+
// reflection and dynamic invocation.
|
|
38
|
+
//
|
|
39
|
+
// Returns:
|
|
40
|
+
// A pointer to the ServiceDescriptor for this service. The returned pointer
|
|
41
|
+
// is owned by the service and remains valid for the lifetime of the
|
|
42
|
+
// service.
|
|
43
|
+
virtual const ::google::protobuf::ServiceDescriptor* GetDescriptor() = 0;
|
|
44
|
+
|
|
45
|
+
// Invokes an RPC method on this service.
|
|
46
|
+
//
|
|
47
|
+
// This is the core method for executing RPC calls. The implementation should:
|
|
48
|
+
// 1. Validate that the method belongs to this service
|
|
49
|
+
// 2. Downcast the generic Message to the specific request type
|
|
50
|
+
// 3. Execute the method logic
|
|
51
|
+
// 4. Complete the callback with the response or reject it with an error
|
|
52
|
+
//
|
|
53
|
+
// Parameters:
|
|
54
|
+
// method - Descriptor of the method to invoke. Must be a method of this
|
|
55
|
+
// service (obtained via GetDescriptor()).
|
|
56
|
+
// request - The request message. Must be of the type expected by the method
|
|
57
|
+
// (as specified by GetRequestPrototype()).
|
|
58
|
+
// on_complete - Handler to invoke on successful completion with the
|
|
59
|
+
// serialized response data.
|
|
60
|
+
// on_reject - Handler to invoke on failure with an error message.
|
|
61
|
+
virtual void CallMethod(const ::google::protobuf::MethodDescriptor* method,
|
|
62
|
+
const ::google::protobuf::Message& request,
|
|
63
|
+
uint64_t request_id,
|
|
64
|
+
OnCompleteHandler on_complete,
|
|
65
|
+
OnRejectHandler on_reject) = 0;
|
|
66
|
+
|
|
67
|
+
// Returns the prototype (default instance) for request messages of a method.
|
|
68
|
+
//
|
|
69
|
+
// This is used for message deserialization and reflection. The returned
|
|
70
|
+
// prototype can be cloned to create new request messages of the correct type.
|
|
71
|
+
//
|
|
72
|
+
// Parameters:
|
|
73
|
+
// method - The method descriptor. Must be a method of this service.
|
|
74
|
+
//
|
|
75
|
+
// Returns:
|
|
76
|
+
// A const reference to the prototype request message for this method.
|
|
77
|
+
// The returned reference remains valid for the lifetime of the service.
|
|
78
|
+
virtual const ::google::protobuf::Message& GetRequestPrototype(
|
|
79
|
+
const ::google::protobuf::MethodDescriptor* method) const = 0;
|
|
80
|
+
|
|
81
|
+
// Returns the prototype (default instance) for response messages of a method.
|
|
82
|
+
//
|
|
83
|
+
// This is used for message deserialization and reflection. The returned
|
|
84
|
+
// prototype can be cloned to create new response messages of the correct type.
|
|
85
|
+
//
|
|
86
|
+
// Parameters:
|
|
87
|
+
// method - The method descriptor. Must be a method of this service.
|
|
88
|
+
//
|
|
89
|
+
// Returns:
|
|
90
|
+
// A const reference to the prototype response message for this method.
|
|
91
|
+
// The returned reference remains valid for the lifetime of the service.
|
|
92
|
+
virtual const ::google::protobuf::Message& GetResponsePrototype(
|
|
93
|
+
const ::google::protobuf::MethodDescriptor* method) const = 0;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
} // namespace mo::rpc
|
|
97
|
+
|
|
98
|
+
#endif // MO_RPC_SERVICE_H_
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) 2000-2026 TeamDev. All rights reserved.
|
|
2
|
+
// TeamDev PROPRIETARY and CONFIDENTIAL.
|
|
3
|
+
// Use is subject to license terms.
|
|
4
|
+
|
|
5
|
+
#ifndef MOBROWSER_EXPORT_H
|
|
6
|
+
#define MOBROWSER_EXPORT_H
|
|
7
|
+
|
|
8
|
+
#if defined(OS_WIN)
|
|
9
|
+
#define MOBROWSER_EXPORT __declspec(dllexport)
|
|
10
|
+
#else
|
|
11
|
+
#define MOBROWSER_EXPORT __attribute__((visibility("default")))
|
|
12
|
+
#endif
|
|
13
|
+
|
|
14
|
+
#endif // MOBROWSER_EXPORT_H
|
package/internal/rpc.cc
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Copyright (c) 2000-2026 TeamDev. All rights reserved.
|
|
2
|
+
// TeamDev PROPRIETARY and CONFIDENTIAL.
|
|
3
|
+
// Use is subject to license terms.
|
|
4
|
+
|
|
5
|
+
#include "../include/rpc.h"
|
|
6
|
+
#include "transport.h"
|
|
7
|
+
|
|
8
|
+
void launch();
|
|
9
|
+
|
|
10
|
+
extern "C" {
|
|
11
|
+
MOBROWSER_EXPORT void AppMain() {
|
|
12
|
+
launch();
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
namespace mo::rpc {
|
|
17
|
+
void RegisterService(Service* service) {
|
|
18
|
+
Transport::GetInstance()->RegisterService(service);
|
|
19
|
+
}
|
|
20
|
+
} // namespace mo::rpc
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// Copyright (c) 2000-2026 TeamDev. All rights reserved.
|
|
2
|
+
// TeamDev PROPRIETARY and CONFIDENTIAL.
|
|
3
|
+
// Use is subject to license terms.
|
|
4
|
+
|
|
5
|
+
#include "transport.h"
|
|
6
|
+
|
|
7
|
+
#include <shared_mutex>
|
|
8
|
+
#include <vector>
|
|
9
|
+
|
|
10
|
+
#include "../include/service.h"
|
|
11
|
+
|
|
12
|
+
#include "google/protobuf/arena.h"
|
|
13
|
+
#include "google/protobuf/descriptor.h"
|
|
14
|
+
#include "google/protobuf/message.h"
|
|
15
|
+
|
|
16
|
+
void invoke(uint64_t id,
|
|
17
|
+
const char* service_name,
|
|
18
|
+
const char* method_name,
|
|
19
|
+
const char* data,
|
|
20
|
+
size_t data_size,
|
|
21
|
+
reply_callback reply,
|
|
22
|
+
reject_callback reject) {
|
|
23
|
+
mo::rpc::Transport::GetInstance()->Invoke(id, service_name, method_name, data, data_size, reply, reject);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
namespace mo::rpc {
|
|
27
|
+
Transport::Transport() = default;
|
|
28
|
+
Transport::~Transport() = default;
|
|
29
|
+
|
|
30
|
+
Transport* Transport::GetInstance() {
|
|
31
|
+
static auto* instance = new Transport();
|
|
32
|
+
return instance;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
void Transport::RegisterService(Service* service) {
|
|
36
|
+
std::unique_lock lock(mutex_);
|
|
37
|
+
services_.emplace(service->GetDescriptor()->full_name(), service);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
void Transport::Invoke(uint64_t id,
|
|
41
|
+
const char* service_name,
|
|
42
|
+
const char* method_name,
|
|
43
|
+
const char* data,
|
|
44
|
+
size_t data_size,
|
|
45
|
+
reply_callback reply,
|
|
46
|
+
reject_callback reject) {
|
|
47
|
+
Service* service;
|
|
48
|
+
{
|
|
49
|
+
std::shared_lock lock(mutex_);
|
|
50
|
+
auto it = services_.find(service_name);
|
|
51
|
+
if (it == services_.end()) {
|
|
52
|
+
reject(id, "Service not found.");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
service = it->second;
|
|
56
|
+
}
|
|
57
|
+
auto method = service->GetDescriptor()->FindMethodByName(method_name);
|
|
58
|
+
if (!method) {
|
|
59
|
+
reject(id, "Method not found.");
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
auto* request = service->GetRequestPrototype(method).New();
|
|
63
|
+
request->ParseFromArray(data, data_size);
|
|
64
|
+
service->CallMethod(method, *request, id, reply, reject);
|
|
65
|
+
}
|
|
66
|
+
} // namespace mo::rpc
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Copyright (c) 2000-2026 TeamDev. All rights reserved.
|
|
2
|
+
// TeamDev PROPRIETARY and CONFIDENTIAL.
|
|
3
|
+
// Use is subject to license terms.
|
|
4
|
+
|
|
5
|
+
#ifndef MOBROWSER_TRANSPORT_H
|
|
6
|
+
#define MOBROWSER_TRANSPORT_H
|
|
7
|
+
|
|
8
|
+
#include <shared_mutex>
|
|
9
|
+
#include <string>
|
|
10
|
+
#include <unordered_map>
|
|
11
|
+
#include "export.h"
|
|
12
|
+
|
|
13
|
+
extern "C" {
|
|
14
|
+
typedef void (*reply_callback)(uint64_t id, const char* data, size_t data_size);
|
|
15
|
+
typedef void (*reject_callback)(uint64_t id, const char* error);
|
|
16
|
+
|
|
17
|
+
MOBROWSER_EXPORT void invoke(uint64_t id,
|
|
18
|
+
const char* service_name,
|
|
19
|
+
const char* method_name,
|
|
20
|
+
const char* data,
|
|
21
|
+
size_t data_size,
|
|
22
|
+
reply_callback reply,
|
|
23
|
+
reject_callback reject);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
namespace mo::rpc {
|
|
27
|
+
class Service;
|
|
28
|
+
|
|
29
|
+
class Transport {
|
|
30
|
+
public:
|
|
31
|
+
Transport();
|
|
32
|
+
~Transport();
|
|
33
|
+
|
|
34
|
+
static Transport* GetInstance();
|
|
35
|
+
|
|
36
|
+
void RegisterService(Service* service);
|
|
37
|
+
|
|
38
|
+
void Invoke(uint64_t id,
|
|
39
|
+
const char* service_name,
|
|
40
|
+
const char* method_name,
|
|
41
|
+
const char* data,
|
|
42
|
+
size_t data_size,
|
|
43
|
+
reply_callback reply,
|
|
44
|
+
reject_callback reject);
|
|
45
|
+
|
|
46
|
+
private:
|
|
47
|
+
std::shared_mutex mutex_;
|
|
48
|
+
std::unordered_map<std::string, Service*> services_;
|
|
49
|
+
};
|
|
50
|
+
} // namespace mo::rpc
|
|
51
|
+
|
|
52
|
+
#endif // MOBROWSER_TRANSPORT_H
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mobrowser/native",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Configuration files for MōBrowser native integration",
|
|
5
|
+
"main": "cmake/MoBrowser.cmake",
|
|
6
|
+
"files": [
|
|
7
|
+
"cmake/MoBrowser.cmake",
|
|
8
|
+
"cmake/Platform.cmake",
|
|
9
|
+
"cmake/Protobuf.cmake",
|
|
10
|
+
"include",
|
|
11
|
+
"internal"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mobrowser",
|
|
15
|
+
"native"
|
|
16
|
+
],
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/TeamDev-IP/MoBrowser.git"
|
|
20
|
+
},
|
|
21
|
+
"author": "TeamDev",
|
|
22
|
+
"license": "MŌBROWSER",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/TeamDev-IP/MoBrowser/issues"
|
|
25
|
+
},
|
|
26
|
+
"homepage": "https://teamdev.com/mobrowser"
|
|
27
|
+
}
|