Skip to content

Commit

Permalink
feat: support promise resolve of loadNativeLibrary
Browse files Browse the repository at this point in the history
  • Loading branch information
LeuisKen committed Feb 2, 2025
1 parent 6af73c9 commit acf84f1
Show file tree
Hide file tree
Showing 16 changed files with 189 additions and 55 deletions.
18 changes: 14 additions & 4 deletions bridge/core/api/executing_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -136,12 +136,22 @@ void ExecutingContextWebFMethods::ClearInterval(ExecutingContext* context,
WindowOrWorkerGlobalScope::clearInterval(context, interval_id, shared_exception_state->exception_state);
}

void ExecutingContextWebFMethods::SetRunRustFutureTasks(ExecutingContext* context,
WebFNativeFunctionContext* callback_context,
SharedExceptionState* shared_exception_state) {
void ExecutingContextWebFMethods::AddRustFutureTask(ExecutingContext* context,
WebFNativeFunctionContext* callback_context,
NativeLibrartMetaData* meta_data,
SharedExceptionState* shared_exception_state) {
auto callback_impl = WebFNativeFunction::Create(callback_context, shared_exception_state);

context->SetRunRustFutureTasks(callback_impl);
context->AddRustFutureTask(callback_impl, meta_data);
}

void ExecutingContextWebFMethods::RemoveRustFutureTask(ExecutingContext* context,
WebFNativeFunctionContext* callback_context,
NativeLibrartMetaData* meta_data,
SharedExceptionState* shared_exception_state) {
auto callback_impl = WebFNativeFunction::Create(callback_context, shared_exception_state);

context->RemoveRustFutureTask(callback_impl, meta_data);
}

} // namespace webf
5 changes: 4 additions & 1 deletion bridge/core/dart_methods.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <memory>
#include <thread>
#include "core/native/native_loader.h"
#include "foundation/native_string.h"
#include "foundation/native_value.h"
#include "include/dart_api.h"
Expand All @@ -36,8 +37,10 @@ using AsyncModuleCallback = NativeValue* (*)(void* callback_context,
Dart_PersistentHandle persistent_handle,
InvokeModuleResultCallback result_callback);

using PluginLibraryEntryPoint = void* (*)(WebFValue<ExecutingContext, ExecutingContextWebFMethods> handle_context);
using PluginLibraryEntryPoint = void* (*)(WebFValue<ExecutingContext, ExecutingContextWebFMethods> handle_context,
NativeLibrartMetaData* meta_data);
using LoadNativeLibraryCallback = void (*)(PluginLibraryEntryPoint entry_point,
NativeValue* lib_name,
void* initialize_data,
double context_id,
void* imported_data);
Expand Down
41 changes: 34 additions & 7 deletions bridge/core/executing_context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <utility>
#include "bindings/qjs/converter_impl.h"
#include "bindings/qjs/script_promise_resolver.h"
#include "built_in_string.h"
#include "core/dom/document.h"
#include "core/dom/mutation_observer.h"
Expand Down Expand Up @@ -392,16 +393,42 @@ void ExecutingContext::EnqueueMicrotask(MicrotaskCallback callback, void* data)
JS_FreeValue(ctx(), proxy_data);
}

void ExecutingContext::SetRunRustFutureTasks(const std::shared_ptr<WebFNativeFunction>& run_future_task) {
run_rust_future_tasks_ = run_future_task;
void ExecutingContext::AddRustFutureTask(const std::shared_ptr<WebFNativeFunction>& run_future_task,
NativeLibrartMetaData* meta_data) {
meta_data->callbacks.push_back(run_future_task);
}

void ExecutingContext::RemoveRustFutureTask(const std::shared_ptr<WebFNativeFunction>& run_future_task,
NativeLibrartMetaData* meta_data) {
// Add the callback to the removed_callbacks list to avoid removing the callback during the iteration.
meta_data->removed_callbacks.push_back(run_future_task);
}

void ExecutingContext::RunRustFutureTasks() {
if (run_rust_future_tasks_ == nullptr)
return;
dart_isolate_context_->profiler()->StartTrackAsyncEvaluation();
run_rust_future_tasks_->Invoke(this, 0, nullptr);
dart_isolate_context_->profiler()->FinishTrackAsyncEvaluation();
for (auto& meta_data : native_library_meta_data_contaner_) {
for (auto& callback : meta_data->callbacks) {
dart_isolate_context_->profiler()->StartTrackAsyncEvaluation();
callback->Invoke(this, 0, nullptr);
dart_isolate_context_->profiler()->FinishTrackAsyncEvaluation();
}
for (auto& removed_callback : meta_data->removed_callbacks) {
meta_data->callbacks.erase(std::remove_if(meta_data->callbacks.begin(), meta_data->callbacks.end(),
[&](const std::shared_ptr<WebFNativeFunction>& callback) {
return callback->Matches(removed_callback);
}),
meta_data->callbacks.end());
}
meta_data->removed_callbacks.clear();
if (meta_data->callbacks.empty() && meta_data->load_context != nullptr) {
meta_data->load_context->promise_resolver->Resolve(JS_NULL);
delete meta_data->load_context;
meta_data->load_context = nullptr;
}
}
}

void ExecutingContext::RegisterNativeLibraryMetaData(NativeLibrartMetaData* meta_data) {
native_library_meta_data_contaner_.push_back(meta_data);
}

void ExecutingContext::DrainPendingPromiseJobs() {
Expand Down
10 changes: 7 additions & 3 deletions bridge/core/executing_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,12 @@ class ExecutingContext {
void ReportError(JSValueConst error, char** rust_errmsg, uint32_t* rust_errmsg_length);
void DrainMicrotasks();
void EnqueueMicrotask(MicrotaskCallback callback, void* data = nullptr);
void SetRunRustFutureTasks(const std::shared_ptr<WebFNativeFunction>& run_rust_future_tasks);
static void AddRustFutureTask(const std::shared_ptr<WebFNativeFunction>& run_rust_future_tasks,
NativeLibrartMetaData* meta_data);
static void RemoveRustFutureTask(const std::shared_ptr<WebFNativeFunction>& run_rust_future_tasks,
NativeLibrartMetaData* meta_data);
void RunRustFutureTasks();
void RegisterNativeLibraryMetaData(NativeLibrartMetaData* meta_data);
void DefineGlobalProperty(const char* prop, JSValueConst value);
ExecutionContextData* contextData();
uint8_t* DumpByteCode(const char* code, uint32_t codeLength, const char* sourceURL, uint64_t* bytecodeLength);
Expand Down Expand Up @@ -228,8 +232,8 @@ class ExecutingContext {
// Rust methods ptr should keep alive when ExecutingContext is disposing.
const std::unique_ptr<ExecutingContextWebFMethods> public_method_ptr_ = nullptr;

// Rust future task queue run trigger
std::shared_ptr<WebFNativeFunction> run_rust_future_tasks_;
// Native library metadata
std::vector<NativeLibrartMetaData*> native_library_meta_data_contaner_;
};

class ObjectProperty {
Expand Down
4 changes: 4 additions & 0 deletions bridge/core/native/native_function.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class WebFNativeFunction : public Function {
return callback_context_->callback(callback_context_, argc, argv, shared_exception_state_);
}

[[nodiscard]] bool Matches(const std::shared_ptr<WebFNativeFunction>& other) {
return other && other->callback_context_ && other->callback_context_->callback == callback_context_->callback;
}

private:
WebFNativeFunctionContext* callback_context_;
SharedExceptionState* shared_exception_state_;
Expand Down
20 changes: 7 additions & 13 deletions bridge/core/native/native_loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,10 @@

namespace webf {

namespace {

struct NativeLibraryLoadContext {
ExecutingContext* context{nullptr};
std::shared_ptr<ScriptPromiseResolver> promise_resolver{nullptr};
};

} // namespace

NativeLoader::NativeLoader(webf::ExecutingContext* context) : ScriptWrappable(context->ctx()) {}

static void ExecuteNativeLibrary(PluginLibraryEntryPoint entry_point,
NativeValue* lib_name,
NativeLibraryLoadContext* native_library_load_context,
void* imported_data) {
// Encounter loading error.
Expand All @@ -33,17 +25,18 @@ static void ExecuteNativeLibrary(PluginLibraryEntryPoint entry_point,
native_library_load_context->promise_resolver->Reject(exception_value);
JS_FreeValue(context->ctx(), exception_value);
} else {
auto* meta_data = new NativeLibrartMetaData{lib_name, native_library_load_context};
auto entry_data = WebFValue<ExecutingContext, ExecutingContextWebFMethods>{
native_library_load_context->context, native_library_load_context->context->publicMethodPtr(),
native_library_load_context->context->status()};
void* result = entry_point(entry_data);
void* result = entry_point(entry_data, meta_data);
native_library_load_context->context->RegisterNativeLibraryMetaData(meta_data);
native_library_load_context->context->RunRustFutureTasks();
}

delete native_library_load_context;
}

static void HandleNativeLibraryLoad(PluginLibraryEntryPoint entry_point,
NativeValue* lib_name,
void* initialize_data_ptr,
double context_id,
void* imported_data) {
Expand All @@ -55,7 +48,8 @@ static void HandleNativeLibraryLoad(PluginLibraryEntryPoint entry_point,
return;

context->dartIsolateContext()->dispatcher()->PostToJs(context->isDedicated(), context_id, ExecuteNativeLibrary,
entry_point, p_native_library_load_context, imported_data);
entry_point, lib_name, p_native_library_load_context,
imported_data);
}

ScriptPromise NativeLoader::loadNativeLibrary(const AtomicString& lib_name,
Expand Down
15 changes: 15 additions & 0 deletions bridge/core/native/native_loader.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,21 @@

namespace webf {

class ScriptPromiseResolver;
class WebFNativeFunction;

struct NativeLibraryLoadContext {
ExecutingContext* context{nullptr};
std::shared_ptr<ScriptPromiseResolver> promise_resolver{nullptr};
};

struct NativeLibrartMetaData {
NativeValue* lib_name;
NativeLibraryLoadContext* load_context;
std::vector<std::shared_ptr<WebFNativeFunction>> callbacks;
std::vector<std::shared_ptr<WebFNativeFunction>> removed_callbacks;
};

class NativeLoader : public ScriptWrappable {
DEFINE_WRAPPERTYPEINFO();

Expand Down
27 changes: 19 additions & 8 deletions bridge/include/plugin_api/executing_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#define WEBF_CORE_RUST_API_EXECUTING_CONTEXT_H_

#include "core/native/native_function.h"
#include "core/native/native_loader.h"
#include "document.h"
#include "exception_state.h"
#include "foundation/native_value.h"
Expand Down Expand Up @@ -42,10 +43,14 @@ using PublicContextSetInterval = int32_t (*)(ExecutingContext*,
SharedExceptionState*);
using PublicContextClearTimeout = void (*)(ExecutingContext*, int32_t, SharedExceptionState*);
using PublicContextClearInterval = void (*)(ExecutingContext*, int32_t, SharedExceptionState*);
using PublicContextSetRunRustFutureTasks = void (*)(ExecutingContext*,
WebFNativeFunctionContext*,
SharedExceptionState*);

using PublicContextAddRustFutureTask = void (*)(ExecutingContext*,
WebFNativeFunctionContext*,
NativeLibrartMetaData*,
SharedExceptionState*);
using PublicContextRemoveRustFutureTask = void (*)(ExecutingContext*,
WebFNativeFunctionContext*,
NativeLibrartMetaData*,
SharedExceptionState*);
// Memory aligned and readable from WebF side.
// Only C type member can be included in this class, any C++ type and classes can is not allowed to use here.
struct ExecutingContextWebFMethods {
Expand Down Expand Up @@ -82,9 +87,14 @@ struct ExecutingContextWebFMethods {
static void ClearInterval(ExecutingContext* context,
int32_t interval_id,
SharedExceptionState* shared_exception_state);
static void SetRunRustFutureTasks(ExecutingContext* context,
WebFNativeFunctionContext* callback_context,
SharedExceptionState* shared_exception_state);
static void AddRustFutureTask(ExecutingContext* context,
WebFNativeFunctionContext* callback_context,
NativeLibrartMetaData* meta_data,
SharedExceptionState* shared_exception_state);
static void RemoveRustFutureTask(ExecutingContext* context,
WebFNativeFunctionContext* callback_context,
NativeLibrartMetaData* meta_data,
SharedExceptionState* shared_exception_state);

double version{1.0};
PublicContextGetDocument context_get_document{document};
Expand All @@ -101,7 +111,8 @@ struct ExecutingContextWebFMethods {
PublicContextSetInterval context_set_interval{SetInterval};
PublicContextClearTimeout context_clear_timeout{ClearTimeout};
PublicContextClearInterval context_clear_interval{ClearInterval};
PublicContextSetRunRustFutureTasks context_set_run_rust_future_tasks{SetRunRustFutureTasks};
PublicContextAddRustFutureTask context_add_rust_future_task{AddRustFutureTask};
PublicContextRemoveRustFutureTask context_remove_rust_future_task{RemoveRustFutureTask};
};

} // namespace webf
Expand Down
2 changes: 2 additions & 0 deletions bridge/rusty_webf_sys/src/dom/events/event_target.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ impl EventTarget {
let callback_context_data = Box::new(EventCallbackContextData {
executing_context_ptr: self.context().ptr,
executing_context_method_pointer: self.context().method_pointer(),
executing_context_meta_data: self.context().meta_data,
executing_context_status: self.context().status,
func: callback,
});
Expand Down Expand Up @@ -112,6 +113,7 @@ impl EventTarget {
let callback_context_data = Box::new(EventCallbackContextData {
executing_context_ptr: self.context().ptr,
executing_context_method_pointer: self.context().method_pointer(),
executing_context_meta_data: self.context().meta_data,
executing_context_status: self.context().status,
func: callback,
});
Expand Down
54 changes: 50 additions & 4 deletions bridge/rusty_webf_sys/src/executing_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@ pub struct ExecutingContextRustMethods {
pub set_interval: extern "C" fn(*const OpaquePtr, *const WebFNativeFunctionContext, c_int, *const OpaquePtr) -> c_int,
pub clear_timeout: extern "C" fn(*const OpaquePtr, c_int, *const OpaquePtr),
pub clear_interval: extern "C" fn(*const OpaquePtr, c_int, *const OpaquePtr),
pub set_run_rust_future_tasks: extern "C" fn(*const OpaquePtr, *const WebFNativeFunctionContext, *const OpaquePtr) -> c_void,
pub add_rust_future_task: extern "C" fn(*const OpaquePtr, *const WebFNativeFunctionContext, *const NativeLibraryMetaData, *const OpaquePtr) -> c_void,
pub remove_rust_future_task: extern "C" fn(*const OpaquePtr, *const WebFNativeFunctionContext, *const NativeLibraryMetaData, *const OpaquePtr) -> c_void,
}

pub type TimeoutCallback = Box<dyn Fn()>;
pub type IntervalCallback = Box<dyn Fn()>;
pub type RunRustFutureTasksCallback = Box<dyn Fn()>;

#[repr(C)]
pub struct NativeLibraryMetaData {
pub lib_name: *const NativeValue
}

/// An environment contains all the necessary running states of a web page.
///
/// For Flutter apps, there could be many web pages running in the same Dart environment,
Expand All @@ -49,14 +55,16 @@ pub struct ExecutingContext {
pub ptr: *const OpaquePtr,
// Methods available for export from the C++ world for use.
method_pointer: *const ExecutingContextRustMethods,
pub meta_data: *const NativeLibraryMetaData,
pub status: *const RustValueStatus,
}

impl ExecutingContext {
pub fn initialize(ptr: *const OpaquePtr, method_pointer: *const ExecutingContextRustMethods, status: *const RustValueStatus) -> ExecutingContext {
pub fn initialize(ptr: *const OpaquePtr, method_pointer: *const ExecutingContextRustMethods, meta_data: *const NativeLibraryMetaData, status: *const RustValueStatus) -> ExecutingContext {
ExecutingContext {
ptr,
method_pointer,
meta_data,
status
}
}
Expand Down Expand Up @@ -268,7 +276,44 @@ impl ExecutingContext {
}
}

pub fn set_run_rust_future_tasks(&self, callback: RunRustFutureTasksCallback, exception_state: &ExceptionState) -> Result<(), String> {
pub fn add_rust_future_task(&self, callback: RunRustFutureTasksCallback, exception_state: &ExceptionState) -> Result<(), String> {
let general_callback: WebFNativeFunction = Box::new(move |argc, argv| {
if argc != 0 {
println!("Invalid argument count for run rust future tasks callback");
return NativeValue::new_null();
}
callback();
NativeValue::new_null()
});

let callback_data = Box::new(WebFNativeFunctionContextData {
func: general_callback,
});
let callback_context_data_ptr = Box::into_raw(callback_data);
let callback_context = Box::new(WebFNativeFunctionContext {
callback: invoke_webf_native_function,
free_ptr: release_webf_native_function,
ptr: callback_context_data_ptr,
});
let callback_context_ptr = Box::into_raw(callback_context);

unsafe {
((*self.method_pointer).add_rust_future_task)(self.ptr, callback_context_ptr, self.meta_data, exception_state.ptr);
}

if exception_state.has_exception() {
unsafe {
let _ = Box::from_raw(callback_context_ptr);
let _ = Box::from_raw(callback_context_data_ptr);
}
return Err(exception_state.stringify(self));
}

Ok(())

}

pub fn remove_rust_future_task(&self, callback: RunRustFutureTasksCallback, exception_state: &ExceptionState) -> Result<(), String> {
let general_callback: WebFNativeFunction = Box::new(move |argc, argv| {
if argc != 0 {
println!("Invalid argument count for run rust future tasks callback");
Expand All @@ -290,7 +335,7 @@ impl ExecutingContext {
let callback_context_ptr = Box::into_raw(callback_context);

unsafe {
((*self.method_pointer).set_run_rust_future_tasks)(self.ptr, callback_context_ptr, exception_state.ptr);
((*self.method_pointer).remove_rust_future_task)(self.ptr, callback_context_ptr, self.meta_data, exception_state.ptr);
}

if exception_state.has_exception() {
Expand Down Expand Up @@ -323,6 +368,7 @@ impl Clone for ExecutingContext {
ExecutingContext {
ptr: self.ptr,
method_pointer: self.method_pointer,
meta_data: self.meta_data,
status: self.status,
}
}
Expand Down
4 changes: 2 additions & 2 deletions bridge/rusty_webf_sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ pub struct RustValue<T> {
pub status: *const RustValueStatus,
}

pub fn initialize_webf_api(value: RustValue<ExecutingContextRustMethods>) -> ExecutingContext {
ExecutingContext::initialize(value.value, value.method_pointer, value.status)
pub fn initialize_webf_api(value: RustValue<ExecutingContextRustMethods>, meta_data: *const NativeLibraryMetaData) -> ExecutingContext {
ExecutingContext::initialize(value.value, value.method_pointer, meta_data, value.status)
}

// This is the entrypoint when your rust app compiled as dynamic library and loaded & executed by WebF.
Expand Down
Loading

0 comments on commit acf84f1

Please sign in to comment.