Skip to content

Commit

Permalink
feat(tcp): add option to manage socket timeout dynamically
Browse files Browse the repository at this point in the history
  • Loading branch information
michaldziuba03 committed Aug 7, 2024
1 parent d7da07e commit 90849d2
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 2 deletions.
2 changes: 1 addition & 1 deletion core/js_internals.hh

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions core/tcp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ class TcpStream {

v8::Local<v8::FunctionTemplate> closeTemplate = v8::FunctionTemplate::New(isolate, TcpStream::close);
t->PrototypeTemplate()->Set(isolate, "close", closeTemplate);

v8::Local<v8::FunctionTemplate> setTimeoutTemplate = v8::FunctionTemplate::New(isolate, TcpStream::set_timeout);
t->PrototypeTemplate()->Set(isolate, "setTimeout", setTimeoutTemplate);

v8::Local<v8::Function> func = t->GetFunction(context).ToLocalChecked();
TcpStream::streamConstructor.Reset(isolate, func);
Expand Down Expand Up @@ -79,6 +82,21 @@ class TcpStream {
lx_close(stream->conn);
}

static void set_timeout(const v8::FunctionCallbackInfo<v8::Value> &args) {
v8::Isolate *isolate = args.GetIsolate();

if (args.Length() != 1 && !args[0]->IsNumber()) {
isolate->ThrowException(v8::Exception::Error(v8_str(isolate, "Expected timeout as number")));
return;
}

int64_t timeout = args[0].As<v8::Number>()->Value();
TcpStream *stream = static_cast<TcpStream*>(args.This()->GetAlignedPointerFromInternalField(0));

lx_timer_stop(&stream->timeout);
lx_timer_start(&stream->timeout, TcpStream::handle_timeout, timeout);
}

/* handlers for event loop */
static void handle_data(lx_connection_t *conn) {
TcpStream *stream = static_cast<TcpStream*>(conn->data);
Expand Down
10 changes: 10 additions & 0 deletions core/v8_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,16 @@ inline v8::Local<v8::String> v8_value(v8::Isolate *isolate, const std::string &s
return maybe_str.ToLocalChecked();
}

/* use it if v8::String is required explicitly */
inline v8::Local<v8::String> v8_str(v8::Isolate *isolate, const std::string &str) {
v8::MaybeLocal<v8::String> maybe_str = v8::String::NewFromUtf8(isolate, str.c_str(), v8::NewStringType::kNormal);
if (maybe_str.IsEmpty()) {
return v8::String::Empty(isolate);
}

return maybe_str.ToLocalChecked();
}

inline v8::Local<v8::Number> v8_value(v8::Isolate *isolate, double value) {
return v8::Number::New(isolate, value);
}
Expand Down
22 changes: 21 additions & 1 deletion js/net.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,33 @@ class Socket {
// otherwise - ignore and make it safe to call multiple times
}

setTimeout(delay) {
if (this._handle) {
this._handle.setTimeout(delay);
}
}

write(data) {
if (this._handle) {
this._handle.write(data);
}
}
}

function toPort(value) {
const port = Number(value);

if (!Number.isInteger(port)) {
throw new Error('Port must be an integer.');
}

if (port < 0 || port > 65535) {
throw new Error('Port must be in the range 0-65535.');
}

return port;
}

export const tcpListen = (callback, port) => {
net.tcpListen((handle) => {
const socket = new Socket(handle);
Expand All @@ -34,5 +54,5 @@ export const tcpListen = (callback, port) => {
handle.onread = (chunk) => {} // user should call socket.read() to overwrite this callback

callback(socket);
}, port);
}, toPort(port));
};
1 change: 1 addition & 0 deletions sample.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ console.log(`Url: ${import.meta.url}`);
tcpListen((socket) => {
console.log("Client connected");

socket.setTimeout(60 * 1000);
socket.read((chunk) => {
console.log(`Received data`);
const response = `<h1>${chunk}</h1>`; // echo HTTP request
Expand Down

0 comments on commit 90849d2

Please sign in to comment.