Implement FormData.
In this pull request, FormData Web API and it's qjs binding is implmented.
For prototype, see below:
type FormDataPart={}
export interface FormData {
new():FormData;
append(name: string, value: BlobPart, fileName?: string): void;
// This method name is a placeholder of **delete** method to avoid using C++ keyword
// and will be replaced to **delete** when installing in MemberInstaller::InstallFunctions.
form_data_delete(name: string): void;
get(name: string): BlobPart
getAll(name: string): BlobPart[];
has(name: string): boolean;
set(name: string, value: BlobPart, fileName?: string): void;
forEach(callbackfn: Function, thisArg?: any): void;
keys():string[]
values():BlobPart[]
entries():FormDataPart[]
}
Todo: Making FetchModule support FormData body.
Todo: Should using fileName parameter in append/set implementation, we do NOT using it currently.
@linsmod
The binding from C++ to Dart with FormData class finished
The binding from C++ to Dart with FormData class finished
Got! Awesome job!
The implementation of Chrome's FormData support is an good reference.
https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/html/forms/form_data.h
绑定到Dart的代码,是否可以通过直接传递entries的引用/指针来简化?因为FormData已经在C++层面实现了,如果再通过dart实现就重复了。
我就想投机取巧一下: 比如C++一边createBindingObject传递entries_:
FormData::FormData(JSContext* ctx) : BindingObject(ctx) {
GetExecutingContext()->dartMethodPtr()->createBindingObject(GetExecutingContext()->isDedicated(),
GetExecutingContext()->contextId(), bindingObject(),
CreateBindingObjectType::kCreateFormData, &entries_, 0);
}
private:
std::vector<std::shared_ptr<FormDataEntry>> entries_;
Dart一边在某种构造函数内把C++传递的entries_指针取出来, 伪代码如下:
class FormData extends DynamicBindingObject {
List<FormDataEntry> entries = [];
FormData(BindingContext context, List<dynamic> domMatrixInit): super(context){
entries=context.args;
}
关于创建绑定,还有一个疑问。我看到有一个创建绑定的初始化函数,但是没有看到被调用方的具体实现,只有测试代码中有一个空函数, 从Dart创建NativeBindingObject不是必要的吗?: void TEST_CreateBindingObject(double context_id, void* native_binding_object, int32_t type, void* args, int32_t argc) {}
绑定到Dart的代码,是否可以通过直接传递entries的引用/指针来简化?因为FormData已经在C++层面实现了,如果再通过dart实现就重复了。
我就想投机取巧一下: 比如C++一边createBindingObject传递entries_:
FormData::FormData(JSContext* ctx) : BindingObject(ctx) { GetExecutingContext()->dartMethodPtr()->createBindingObject(GetExecutingContext()->isDedicated(), GetExecutingContext()->contextId(), bindingObject(), CreateBindingObjectType::kCreateFormData, &entries_, 0); } private: std::vector<std::shared_ptr<FormDataEntry>> entries_;Dart一边在某种构造函数内把C++传递的entries_指针取出来, 伪代码如下:
class FormData extends DynamicBindingObject { List<FormDataEntry> entries = []; FormData(BindingContext context, List<dynamic> domMatrixInit): super(context){ entries=context.args; }关于创建绑定,还有一个疑问。我看到有一个创建绑定的初始化函数,但是没有看到被调用方的具体实现,只有测试代码中有一个空函数, 从Dart创建NativeBindingObject不是必要的吗?: void TEST_CreateBindingObject(double context_id, void* native_binding_object, int32_t type, void* args, int32_t argc) {}
这么搞的话,问题可多了。跨线程问题,跨 VM 内存管理,Dart FFI 本身的性能问题,内存回收问题。
别瞎想了,再写一遍吧
js 里面 new FormData()并添加数据, 在 dart 里面成了空的Map。
readonly forEach: JSArrayProtoMethod; 被改成这样了之后我就不会了,没有找到任何具体实现例子。
我理解如果要实现JSArrayProtoMethod是缺少一个Iterator的模板的,如果有那个模板,那么代码生成那里改一下,让生成的代码去调用目标的Converter::ToIterator,是不是就行了。
因为我现在想在js那边直接把FormData转成普通JS对象,也就是dart里面的Map,为什么想这么做?因为js传递的FormData在fetch.dart里面就变成了一个空Map,即使js那边添加了数据,在Dart那边看也是空的,那不如将计就计直接用JS对象{}。如果要转{}就需要遍历内容,但因为现在改成了readonly forEach: JSArrayProtoMethod; 我在js那边forEach就取不到内容,空空如也。
(PS:注意到你们似乎在移植blink,那个能搞完,就省很多实现Web标准的功夫了)
估计哪里搞错了,预期 new FormData 传到 dart 是会变成昨天搞的 FormData Dart 对象的,我来看看为啥
readonly forEach: JSArrayProtoMethod; 被改成这样了之后我就不会了,没有找到任何具体实现例子。
我理解如果要实现JSArrayProtoMethod是缺少一个Iterator的模板的,如果有那个模板,那么代码生成那里改一下,让生成的代码去调用目标的Converter::ToIterator,是不是就行了。
因为我现在想在js那边直接把FormData转成普通JS对象,也就是dart里面的Map,为什么想这么做?因为js传递的FormData在fetch.dart里面就变成了一个空Map,即使js那边添加了数据,在Dart那边看也是空的,那不如将计就计直接用JS对象{}。如果要转{}就需要遍历内容,但因为现在改成了readonly forEach: JSArrayProtoMethod; 我在js那边forEach就取不到内容,空空如也。
(PS:注意到你们似乎在移植blink,那个能搞完,就省很多实现Web标准的功夫了)
你说的没错,是得单独写个 iterator 才能完整实现这个。readonly forEach: JSArrayProtoMethod; 依赖了 quickjs 自身的特定,类数组的对象能 work,但是对于 FormData 就不凑效了
@linsmod 重写了 FormData,并重新实现了 Iterator 功能,现在 Foreach 和返回 interator 的函数都 work 了。
估计哪里搞错了,预期 new FormData 传到 dart 是会变成昨天搞的 FormData Dart 对象的,我来看看为啥
现在把 formData 传给 fetch API 已经能在 C++ 那边收到了,接下来就是把这个 FormData 当成指针传递给 Dart。
绑定到Dart的代码,是否可以通过直接传递entries的引用/指针来简化?因为FormData已经在C++层面实现了,如果再通过dart实现就重复了。
这个我想了一下,是可以通过一种简单的方式实现的,Dart FormData 只需要实现一个功能 —— 反向通过 Dart FFI 把 FormData 的 bytes 读回 Dart 环境,然后再这个 bytes 传给 http 模块,这样就搞定了。
所以接下来的任务是:
- 将 FormData 转成 NativeValue,然后发送到 Dart 那边,这里需要调整 invokeModule 这个函数
- 实现 Dart --> C++ FormData 的通道,实现 HandleCallFromDartSide 函数即可。
- 实现 FormData 的 encoding 逻辑,需要将 FormData 的数据结构编码成 MultiPart byte 格式,这里可以参考 blink 的代码:1, 2
- 由于 Dart 和 C++ 是运行在两个线程内,从 Dart 里通过 FFI 读取 bytes,再回到 Dart 属于跨线程调用逻辑,需要处理同步问题
@linsmod 接下来就交给你了,我得去搞别人的事情了,加油。
出差了,得过段时间。
编译不过,好像是改动了这里原因:
NativeValue* invokeModule(bool is_dedicated,
void* callback_context,
double context_id,
int64_t profile_link_id,
SharedNativeString* moduleName,
SharedNativeString* method,
NativeValue* params,
uint32_t argc,
AsyncModuleCallback callback);
dart_methods.h:143:16: note: candidate expects 9 arguments, 8 provided
/home/wulin/webf_copy/bridge/core/frame/module_manager.cc:186:52: error: no matching function for call to ‘webf::DartMethodPointer::invokeModule(bool, std::nullptr_t, double, int64_t, std::unique_ptr<webf::SharedNativeString>::pointer, std::unique_ptr<webf::SharedNativeString>::pointer, webf::NativeValue*, webf::NativeValue* (&)(void*, double, const char*, webf::NativeValue*, Dart_Handle, webf::InvokeModuleResultCallback))’
186 | result = context->dartMethodPtr()->invokeModule(
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
187 | context->isDedicated(), nullptr, context->contextId(), context->dartIsolateContext()->profiler()->link_id(),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
188 | module_name_string.get(), method_name_string.get(), ¶ms, handleInvokeModuleUnexpectedCallback);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/wulin/webf_copy/bridge/core/dart_isolate_context.h:11,
from /home/wulin/webf_copy/bridge/core/executing_context.h:26,
from /home/wulin/webf_copy/bridge/bindings/qjs/qjs_interface_bridge.h:9,
from /home/wulin/webf_copy/bridge/bindings/qjs/generated_code_helper.h:11,
from /home/wulin/webf_copy/bridge/out/qjs_module_manager_options.h:9,
from /home/wulin/webf_copy/bridge/core/frame/module_manager.h:12,
from /home/wulin/webf_copy/bridge/core/frame/module_manager.cc:5:
Migrated to enterprise