Skip to content

Commit 170bc31

Browse files
committed
src: turn JS stream into a full duplex
Remove unused methods for reading data from `JSStream` and add those required for emitting data or an EOF event to the JS side, in essentially the same way that `LibuvStreamWrap` does it. PR-URL: #16269 Reviewed-By: Anatoli Papirovski <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent 127f83a commit 170bc31

File tree

3 files changed

+70
-35
lines changed

3 files changed

+70
-35
lines changed

src/js_stream.cc

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,55 @@ JSStream::JSStream(Environment* env, Local<Object> obj)
2727
StreamBase(env) {
2828
node::Wrap(obj, this);
2929
MakeWeak<JSStream>(this);
30+
31+
set_alloc_cb({ OnAllocImpl, this });
32+
set_read_cb({ OnReadImpl, this });
3033
}
3134

3235

3336
JSStream::~JSStream() {
3437
}
3538

3639

40+
void JSStream::OnAllocImpl(size_t size, uv_buf_t* buf, void* ctx) {
41+
buf->base = Malloc(size);
42+
buf->len = size;
43+
}
44+
45+
46+
void JSStream::OnReadImpl(ssize_t nread,
47+
const uv_buf_t* buf,
48+
uv_handle_type pending,
49+
void* ctx) {
50+
JSStream* wrap = static_cast<JSStream*>(ctx);
51+
CHECK_NE(wrap, nullptr);
52+
Environment* env = wrap->env();
53+
HandleScope handle_scope(env->isolate());
54+
Context::Scope context_scope(env->context());
55+
56+
if (nread < 0) {
57+
if (buf != nullptr && buf->base != nullptr)
58+
free(buf->base);
59+
wrap->EmitData(nread, Local<Object>(), Local<Object>());
60+
return;
61+
}
62+
63+
if (nread == 0) {
64+
if (buf->base != nullptr)
65+
free(buf->base);
66+
return;
67+
}
68+
69+
CHECK_LE(static_cast<size_t>(nread), buf->len);
70+
char* base = node::Realloc(buf->base, nread);
71+
72+
CHECK_EQ(pending, UV_UNKNOWN_HANDLE);
73+
74+
Local<Object> obj = Buffer::New(env, base, nread).ToLocalChecked();
75+
wrap->EmitData(nread, obj, Local<Object>());
76+
}
77+
78+
3779
void* JSStream::Cast() {
3880
return static_cast<void*>(this);
3981
}
@@ -134,37 +176,6 @@ void JSStream::New(const FunctionCallbackInfo<Value>& args) {
134176
}
135177

136178

137-
static void FreeCallback(char* data, void* hint) {
138-
// Intentional no-op
139-
}
140-
141-
142-
void JSStream::DoAlloc(const FunctionCallbackInfo<Value>& args) {
143-
JSStream* wrap;
144-
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
145-
146-
uv_buf_t buf;
147-
wrap->OnAlloc(args[0]->Int32Value(), &buf);
148-
Local<Object> vbuf = Buffer::New(
149-
wrap->env(),
150-
buf.base,
151-
buf.len,
152-
FreeCallback,
153-
nullptr).ToLocalChecked();
154-
return args.GetReturnValue().Set(vbuf);
155-
}
156-
157-
158-
void JSStream::DoRead(const FunctionCallbackInfo<Value>& args) {
159-
JSStream* wrap;
160-
ASSIGN_OR_RETURN_UNWRAP(&wrap, args.Holder());
161-
162-
CHECK(Buffer::HasInstance(args[1]));
163-
uv_buf_t buf = uv_buf_init(Buffer::Data(args[1]), Buffer::Length(args[1]));
164-
wrap->OnRead(args[0]->Int32Value(), &buf);
165-
}
166-
167-
168179
void JSStream::DoAfterWrite(const FunctionCallbackInfo<Value>& args) {
169180
JSStream* wrap;
170181
CHECK(args[0]->IsObject());
@@ -230,8 +241,6 @@ void JSStream::Initialize(Local<Object> target,
230241

231242
AsyncWrap::AddWrapMethods(env, t);
232243

233-
env->SetProtoMethod(t, "doAlloc", DoAlloc);
234-
env->SetProtoMethod(t, "doRead", DoRead);
235244
env->SetProtoMethod(t, "doAfterWrite", DoAfterWrite);
236245
env->SetProtoMethod(t, "finishWrite", Finish<WriteWrap>);
237246
env->SetProtoMethod(t, "finishShutdown", Finish<ShutdownWrap>);

src/js_stream.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,16 @@ class JSStream : public AsyncWrap, public StreamBase {
3838
AsyncWrap* GetAsyncWrap() override;
3939

4040
static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
41-
static void DoAlloc(const v8::FunctionCallbackInfo<v8::Value>& args);
42-
static void DoRead(const v8::FunctionCallbackInfo<v8::Value>& args);
4341
static void DoAfterWrite(const v8::FunctionCallbackInfo<v8::Value>& args);
4442
static void ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args);
4543
static void EmitEOF(const v8::FunctionCallbackInfo<v8::Value>& args);
4644

45+
static void OnAllocImpl(size_t size, uv_buf_t* buf, void* ctx);
46+
static void OnReadImpl(ssize_t nread,
47+
const uv_buf_t* buf,
48+
uv_handle_type pending,
49+
void* ctx);
50+
4751
template <class Wrap>
4852
static void Finish(const v8::FunctionCallbackInfo<v8::Value>& args);
4953
};
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const StreamWrap = require('_stream_wrap');
5+
const { PassThrough } = require('stream');
6+
const { Socket } = require('net');
7+
8+
{
9+
const wrap = new StreamWrap(new PassThrough());
10+
assert(wrap instanceof Socket);
11+
wrap.on('data', common.mustCall((d) => assert.strictEqual(`${d}`, 'foo')));
12+
wrap.on('end', common.mustNotCall());
13+
wrap.write('foo');
14+
}
15+
16+
{
17+
const wrap = new StreamWrap(new PassThrough());
18+
assert(wrap instanceof Socket);
19+
wrap.on('data', common.mustCall((d) => assert.strictEqual(`${d}`, 'foo')));
20+
wrap.on('end', common.mustCall());
21+
wrap.end('foo');
22+
}

0 commit comments

Comments
 (0)