diff --git a/src/async_wrap.h b/src/async_wrap.h index 091224f5708df5..286cf12dd6643f 100644 --- a/src/async_wrap.h +++ b/src/async_wrap.h @@ -38,6 +38,7 @@ namespace node { V(DNSCHANNEL) \ V(FSEVENTWRAP) \ V(FSREQWRAP) \ + V(FSREQPROMISE) \ V(GETADDRINFOREQWRAP) \ V(GETNAMEINFOREQWRAP) \ V(HTTP2SESSION) \ diff --git a/src/env.h b/src/env.h index 7e0152916161bf..614bf315502aef 100644 --- a/src/env.h +++ b/src/env.h @@ -220,6 +220,7 @@ class ModuleWrap; V(preference_string, "preference") \ V(priority_string, "priority") \ V(produce_cached_data_string, "produceCachedData") \ + V(promise_string, "promise") \ V(raw_string, "raw") \ V(read_host_object_string, "_readHostObject") \ V(readable_string, "readable") \ @@ -241,6 +242,7 @@ class ModuleWrap; V(sni_context_string, "sni_context") \ V(stack_string, "stack") \ V(status_string, "status") \ + V(statfields_string, "statFields") \ V(stdio_string, "stdio") \ V(subject_string, "subject") \ V(subjectaltname_string, "subjectaltname") \ diff --git a/src/node_file.cc b/src/node_file.cc index 93f54aed23f728..b72f19d07d8e11 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -97,6 +97,7 @@ using v8::Local; using v8::MaybeLocal; using v8::Number; using v8::Object; +using v8::Promise; using v8::String; using v8::Undefined; using v8::Value; @@ -127,30 +128,75 @@ void FSReqWrap::Resolve(Local value) { MakeCallback(env()->oncomplete_string(), arraysize(argv), argv); } -void FSReqWrap::Init(const char* syscall, - const char* data, - size_t len, - enum encoding encoding) { - syscall_ = syscall; - encoding_ = encoding; - - if (data != nullptr) { - CHECK_EQ(data_, nullptr); - buffer_.AllocateSufficientStorage(len + 1); - buffer_.SetLengthAndZeroTerminate(len); - memcpy(*buffer_, data, len); - data_ = *buffer_; - } -} - void NewFSReqWrap(const FunctionCallbackInfo& args) { CHECK(args.IsConstructCall()); Environment* env = Environment::GetCurrent(args.GetIsolate()); new FSReqWrap(env, args.This()); } +FSReqPromise::FSReqPromise(Environment* env, Local req) + : FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQPROMISE) { + auto resolver = Promise::Resolver::New(env->context()).ToLocalChecked(); + req->Set(env->context(), env->promise_string(), + resolver.As()).FromJust(); + + Local ab = + ArrayBuffer::New(env->isolate(), statFields_, + sizeof(double) * 14, + v8::ArrayBufferCreationMode::kInternalized); + object()->Set(env->context(), + env->statfields_string(), + Float64Array::New(ab, 0, 14)).FromJust(); +} + +FSReqPromise::~FSReqPromise() { + // Validate that the promise was explicitly resolved or rejected. + CHECK(finished_); +} + +void FSReqPromise::Reject(Local reject) { + finished_ = true; + InternalCallbackScope callback_scope(this); + HandleScope scope(env()->isolate()); + Local value = + object()->Get(env()->context(), + env()->promise_string()).ToLocalChecked(); + CHECK(value->IsPromise()); + Local promise = value.As(); + Local resolver = promise.As(); + resolver->Reject(env()->context(), reject); +} + +void FSReqPromise::FillStatsArray(const uv_stat_t* stat) { + node::FillStatsArray(statFields_, stat); +} -FSReqAfterScope::FSReqAfterScope(FSReqWrap* wrap, uv_fs_t* req) +void FSReqPromise::ResolveStat() { + Resolve( + object()->Get(env()->context(), + env()->statfields_string()).ToLocalChecked()); +} + +void FSReqPromise::Resolve(Local value) { + finished_ = true; + InternalCallbackScope callback_scope(this); + HandleScope scope(env()->isolate()); + Local val = + object()->Get(env()->context(), + env()->promise_string()).ToLocalChecked(); + CHECK(val->IsPromise()); + Local promise = val.As(); + Local resolver = promise.As(); + resolver->Resolve(env()->context(), value); +} + +void NewFSReqPromise(const FunctionCallbackInfo& args) { + CHECK(args.IsConstructCall()); + Environment* env = Environment::GetCurrent(args.GetIsolate()); + new FSReqPromise(env, args.This()); +} + +FSReqAfterScope::FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req) : wrap_(wrap), req_(req), handle_scope_(wrap->env()->isolate()), @@ -190,7 +236,7 @@ bool FSReqAfterScope::Proceed() { } void AfterNoArgs(uv_fs_t* req) { - FSReqWrap* req_wrap = static_cast(req->data); + FSReqBase* req_wrap = static_cast(req->data); FSReqAfterScope after(req_wrap, req); if (after.Proceed()) @@ -198,7 +244,7 @@ void AfterNoArgs(uv_fs_t* req) { } void AfterStat(uv_fs_t* req) { - FSReqWrap* req_wrap = static_cast(req->data); + FSReqBase* req_wrap = static_cast(req->data); FSReqAfterScope after(req_wrap, req); if (after.Proceed()) { @@ -208,7 +254,7 @@ void AfterStat(uv_fs_t* req) { } void AfterInteger(uv_fs_t* req) { - FSReqWrap* req_wrap = static_cast(req->data); + FSReqBase* req_wrap = static_cast(req->data); FSReqAfterScope after(req_wrap, req); if (after.Proceed()) @@ -216,7 +262,7 @@ void AfterInteger(uv_fs_t* req) { } void AfterStringPath(uv_fs_t* req) { - FSReqWrap* req_wrap = static_cast(req->data); + FSReqBase* req_wrap = static_cast(req->data); FSReqAfterScope after(req_wrap, req); MaybeLocal link; @@ -235,7 +281,7 @@ void AfterStringPath(uv_fs_t* req) { } void AfterStringPtr(uv_fs_t* req) { - FSReqWrap* req_wrap = static_cast(req->data); + FSReqBase* req_wrap = static_cast(req->data); FSReqAfterScope after(req_wrap, req); MaybeLocal link; @@ -254,7 +300,7 @@ void AfterStringPtr(uv_fs_t* req) { } void AfterScanDir(uv_fs_t* req) { - FSReqWrap* req_wrap = static_cast(req->data); + FSReqBase* req_wrap = static_cast(req->data); FSReqAfterScope after(req_wrap, req); if (after.Proceed()) { @@ -318,12 +364,12 @@ class fs_req_wrap { }; template -inline FSReqWrap* AsyncDestCall(Environment* env, +inline FSReqBase* AsyncDestCall(Environment* env, const FunctionCallbackInfo& args, const char* syscall, const char* dest, size_t len, enum encoding enc, uv_fs_cb after, Func fn, Args... fn_args) { Local req = args[args.Length() - 1].As(); - FSReqWrap* req_wrap = Unwrap(req); + FSReqBase* req_wrap = Unwrap(req); CHECK_NE(req_wrap, nullptr); req_wrap->Init(syscall, dest, len, enc); int err = fn(env->event_loop(), req_wrap->req(), fn_args..., after); @@ -343,7 +389,7 @@ inline FSReqWrap* AsyncDestCall(Environment* env, } template -inline FSReqWrap* AsyncCall(Environment* env, +inline FSReqBase* AsyncCall(Environment* env, const FunctionCallbackInfo& args, const char* syscall, enum encoding enc, uv_fs_cb after, Func fn, Args... fn_args) { @@ -1396,6 +1442,16 @@ void InitFs(Local target, FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap"); fst->SetClassName(wrapString); target->Set(context, wrapString, fst->GetFunction()).FromJust(); + + // Create Function Template for FSReqPromise + Local fpt = + FunctionTemplate::New(env->isolate(), NewFSReqPromise); + fpt->InstanceTemplate()->SetInternalFieldCount(1); + AsyncWrap::AddWrapMethods(env, fpt); + Local promiseString = + FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqPromise"); + fpt->SetClassName(promiseString); + target->Set(context, promiseString, fpt->GetFunction()).FromJust(); } } // namespace fs diff --git a/src/node_file.h b/src/node_file.h index 878d02c8ba4989..7e2046130943ce 100644 --- a/src/node_file.h +++ b/src/node_file.h @@ -17,26 +17,37 @@ using v8::Value; namespace fs { -class FSReqWrap : public ReqWrap { +class FSReqBase : public ReqWrap { public: - FSReqWrap(Environment* env, Local req) - : ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP) { + FSReqBase(Environment* env, Local req, AsyncWrap::ProviderType type) + : ReqWrap(env, req, type) { Wrap(object(), this); } - virtual ~FSReqWrap() { + virtual ~FSReqBase() { ClearWrap(object()); } void Init(const char* syscall, const char* data = nullptr, size_t len = 0, - enum encoding encoding = UTF8); + enum encoding encoding = UTF8) { + syscall_ = syscall; + encoding_ = encoding; + + if (data != nullptr) { + CHECK_EQ(data_, nullptr); + buffer_.AllocateSufficientStorage(len + 1); + buffer_.SetLengthAndZeroTerminate(len); + memcpy(*buffer_, data, len); + data_ = *buffer_; + } + } - virtual void FillStatsArray(const uv_stat_t* stat); - virtual void Reject(Local reject); - virtual void Resolve(Local value); - virtual void ResolveStat(); + virtual void FillStatsArray(const uv_stat_t* stat) = 0; + virtual void Reject(Local reject) = 0; + virtual void Resolve(Local value) = 0; + virtual void ResolveStat() = 0; const char* syscall() const { return syscall_; } const char* data() const { return data_; } @@ -51,12 +62,43 @@ class FSReqWrap : public ReqWrap { const char* data_ = nullptr; MaybeStackBuffer buffer_; + DISALLOW_COPY_AND_ASSIGN(FSReqBase); +}; + +class FSReqWrap : public FSReqBase { + public: + FSReqWrap(Environment* env, Local req) + : FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQWRAP) { } + + void FillStatsArray(const uv_stat_t* stat) override; + void Reject(Local reject) override; + void Resolve(Local value) override; + void ResolveStat() override; + + private: DISALLOW_COPY_AND_ASSIGN(FSReqWrap); }; +class FSReqPromise : public FSReqBase { + public: + FSReqPromise(Environment* env, Local req); + + ~FSReqPromise() override; + + void FillStatsArray(const uv_stat_t* stat) override; + void Reject(Local reject) override; + void Resolve(Local value) override; + void ResolveStat() override; + + private: + bool finished_ = false; + double statFields_[14] {}; + DISALLOW_COPY_AND_ASSIGN(FSReqPromise); +}; + class FSReqAfterScope { public: - FSReqAfterScope(FSReqWrap* wrap, uv_fs_t* req); + FSReqAfterScope(FSReqBase* wrap, uv_fs_t* req); ~FSReqAfterScope(); bool Proceed(); @@ -64,7 +106,7 @@ class FSReqAfterScope { void Reject(uv_fs_t* req); private: - FSReqWrap* wrap_ = nullptr; + FSReqBase* wrap_ = nullptr; uv_fs_t* req_ = nullptr; HandleScope handle_scope_; Context::Scope context_scope_;