Skip to content

Commit

Permalink
fs: add FSReqPromise
Browse files Browse the repository at this point in the history
PR-URL: #18297
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
  • Loading branch information
jasnell committed Feb 6, 2018
1 parent df34029 commit 7154bc0
Show file tree
Hide file tree
Showing 4 changed files with 138 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/async_wrap.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ namespace node {
V(DNSCHANNEL) \
V(FSEVENTWRAP) \
V(FSREQWRAP) \
V(FSREQPROMISE) \
V(GETADDRINFOREQWRAP) \
V(GETNAMEINFOREQWRAP) \
V(HTTP2SESSION) \
Expand Down
2 changes: 2 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -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") \
Expand All @@ -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") \
Expand Down
108 changes: 82 additions & 26 deletions src/node_file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -127,30 +128,75 @@ void FSReqWrap::Resolve(Local<Value> 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<Value>& args) {
CHECK(args.IsConstructCall());
Environment* env = Environment::GetCurrent(args.GetIsolate());
new FSReqWrap(env, args.This());
}

FSReqPromise::FSReqPromise(Environment* env, Local<Object> req)
: FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQPROMISE) {
auto resolver = Promise::Resolver::New(env->context()).ToLocalChecked();
req->Set(env->context(), env->promise_string(),
resolver.As<Promise>()).FromJust();

Local<ArrayBuffer> 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<Value> reject) {
finished_ = true;
InternalCallbackScope callback_scope(this);
HandleScope scope(env()->isolate());
Local<Value> value =
object()->Get(env()->context(),
env()->promise_string()).ToLocalChecked();
CHECK(value->IsPromise());
Local<Promise> promise = value.As<Promise>();
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
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> value) {
finished_ = true;
InternalCallbackScope callback_scope(this);
HandleScope scope(env()->isolate());
Local<Value> val =
object()->Get(env()->context(),
env()->promise_string()).ToLocalChecked();
CHECK(val->IsPromise());
Local<Promise> promise = val.As<Promise>();
Local<Promise::Resolver> resolver = promise.As<Promise::Resolver>();
resolver->Resolve(env()->context(), value);
}

void NewFSReqPromise(const FunctionCallbackInfo<Value>& 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()),
Expand Down Expand Up @@ -190,15 +236,15 @@ bool FSReqAfterScope::Proceed() {
}

void AfterNoArgs(uv_fs_t* req) {
FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
FSReqBase* req_wrap = static_cast<FSReqBase*>(req->data);
FSReqAfterScope after(req_wrap, req);

if (after.Proceed())
req_wrap->Resolve(Undefined(req_wrap->env()->isolate()));
}

void AfterStat(uv_fs_t* req) {
FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
FSReqBase* req_wrap = static_cast<FSReqBase*>(req->data);
FSReqAfterScope after(req_wrap, req);

if (after.Proceed()) {
Expand All @@ -208,15 +254,15 @@ void AfterStat(uv_fs_t* req) {
}

void AfterInteger(uv_fs_t* req) {
FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
FSReqBase* req_wrap = static_cast<FSReqBase*>(req->data);
FSReqAfterScope after(req_wrap, req);

if (after.Proceed())
req_wrap->Resolve(Integer::New(req_wrap->env()->isolate(), req->result));
}

void AfterStringPath(uv_fs_t* req) {
FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
FSReqBase* req_wrap = static_cast<FSReqBase*>(req->data);
FSReqAfterScope after(req_wrap, req);

MaybeLocal<Value> link;
Expand All @@ -235,7 +281,7 @@ void AfterStringPath(uv_fs_t* req) {
}

void AfterStringPtr(uv_fs_t* req) {
FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
FSReqBase* req_wrap = static_cast<FSReqBase*>(req->data);
FSReqAfterScope after(req_wrap, req);

MaybeLocal<Value> link;
Expand All @@ -254,7 +300,7 @@ void AfterStringPtr(uv_fs_t* req) {
}

void AfterScanDir(uv_fs_t* req) {
FSReqWrap* req_wrap = static_cast<FSReqWrap*>(req->data);
FSReqBase* req_wrap = static_cast<FSReqBase*>(req->data);
FSReqAfterScope after(req_wrap, req);

if (after.Proceed()) {
Expand Down Expand Up @@ -318,12 +364,12 @@ class fs_req_wrap {
};

template <typename Func, typename... Args>
inline FSReqWrap* AsyncDestCall(Environment* env,
inline FSReqBase* AsyncDestCall(Environment* env,
const FunctionCallbackInfo<Value>& args,
const char* syscall, const char* dest, size_t len,
enum encoding enc, uv_fs_cb after, Func fn, Args... fn_args) {
Local<Object> req = args[args.Length() - 1].As<Object>();
FSReqWrap* req_wrap = Unwrap<FSReqWrap>(req);
FSReqBase* req_wrap = Unwrap<FSReqBase>(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);
Expand All @@ -343,7 +389,7 @@ inline FSReqWrap* AsyncDestCall(Environment* env,
}

template <typename Func, typename... Args>
inline FSReqWrap* AsyncCall(Environment* env,
inline FSReqBase* AsyncCall(Environment* env,
const FunctionCallbackInfo<Value>& args,
const char* syscall, enum encoding enc,
uv_fs_cb after, Func fn, Args... fn_args) {
Expand Down Expand Up @@ -1396,6 +1442,16 @@ void InitFs(Local<Object> target,
FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqWrap");
fst->SetClassName(wrapString);
target->Set(context, wrapString, fst->GetFunction()).FromJust();

// Create Function Template for FSReqPromise
Local<FunctionTemplate> fpt =
FunctionTemplate::New(env->isolate(), NewFSReqPromise);
fpt->InstanceTemplate()->SetInternalFieldCount(1);
AsyncWrap::AddWrapMethods(env, fpt);
Local<String> promiseString =
FIXED_ONE_BYTE_STRING(env->isolate(), "FSReqPromise");
fpt->SetClassName(promiseString);
target->Set(context, promiseString, fpt->GetFunction()).FromJust();
}

} // namespace fs
Expand Down
64 changes: 53 additions & 11 deletions src/node_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,37 @@ using v8::Value;

namespace fs {

class FSReqWrap : public ReqWrap<uv_fs_t> {
class FSReqBase : public ReqWrap<uv_fs_t> {
public:
FSReqWrap(Environment* env, Local<Object> req)
: ReqWrap(env, req, AsyncWrap::PROVIDER_FSREQWRAP) {
FSReqBase(Environment* env, Local<Object> 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<Value> reject);
virtual void Resolve(Local<Value> value);
virtual void ResolveStat();
virtual void FillStatsArray(const uv_stat_t* stat) = 0;
virtual void Reject(Local<Value> reject) = 0;
virtual void Resolve(Local<Value> value) = 0;
virtual void ResolveStat() = 0;

const char* syscall() const { return syscall_; }
const char* data() const { return data_; }
Expand All @@ -51,20 +62,51 @@ class FSReqWrap : public ReqWrap<uv_fs_t> {
const char* data_ = nullptr;
MaybeStackBuffer<char> buffer_;

DISALLOW_COPY_AND_ASSIGN(FSReqBase);
};

class FSReqWrap : public FSReqBase {
public:
FSReqWrap(Environment* env, Local<Object> req)
: FSReqBase(env, req, AsyncWrap::PROVIDER_FSREQWRAP) { }

void FillStatsArray(const uv_stat_t* stat) override;
void Reject(Local<Value> reject) override;
void Resolve(Local<Value> value) override;
void ResolveStat() override;

private:
DISALLOW_COPY_AND_ASSIGN(FSReqWrap);
};

class FSReqPromise : public FSReqBase {
public:
FSReqPromise(Environment* env, Local<Object> req);

~FSReqPromise() override;

void FillStatsArray(const uv_stat_t* stat) override;
void Reject(Local<Value> reject) override;
void Resolve(Local<Value> 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();

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_;
Expand Down

0 comments on commit 7154bc0

Please sign in to comment.