|
|
|
#include "tty_wrap.h"
|
|
|
|
|
|
|
|
#include "env.h"
|
|
|
|
#include "env-inl.h"
|
|
|
|
#include "handle_wrap.h"
|
|
|
|
#include "node_buffer.h"
|
|
|
|
#include "node_wrap.h"
|
|
|
|
#include "req-wrap.h"
|
|
|
|
#include "req-wrap-inl.h"
|
|
|
|
#include "stream_wrap.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "util-inl.h"
|
|
|
|
|
|
|
|
namespace node {
|
|
|
|
|
|
|
|
using v8::Array;
|
|
|
|
using v8::Context;
|
|
|
|
using v8::Function;
|
|
|
|
using v8::FunctionCallbackInfo;
|
|
|
|
using v8::FunctionTemplate;
|
|
|
|
using v8::Handle;
|
|
|
|
using v8::Integer;
|
|
|
|
using v8::Local;
|
|
|
|
using v8::Object;
|
|
|
|
using v8::PropertyAttribute;
|
|
|
|
using v8::String;
|
|
|
|
using v8::Value;
|
|
|
|
|
|
|
|
|
|
|
|
void TTYWrap::Initialize(Handle<Object> target,
|
|
|
|
Handle<Value> unused,
|
|
|
|
Handle<Context> context) {
|
|
|
|
Environment* env = Environment::GetCurrent(context);
|
|
|
|
|
|
|
|
Local<FunctionTemplate> t = env->NewFunctionTemplate(New);
|
|
|
|
t->SetClassName(FIXED_ONE_BYTE_STRING(env->isolate(), "TTY"));
|
|
|
|
t->InstanceTemplate()->SetInternalFieldCount(1);
|
|
|
|
|
|
|
|
env->SetProtoMethod(t, "close", HandleWrap::Close);
|
|
|
|
env->SetProtoMethod(t, "unref", HandleWrap::Unref);
|
|
|
|
|
stream_base: introduce StreamBase
StreamBase is an improved way to write C++ streams. The class itself is
for separting `StreamWrap` (with the methods like `.writeAsciiString`,
`.writeBuffer`, `.writev`, etc) from the `HandleWrap` class, making
possible to write abstract C++ streams that are not bound to any uv
socket.
The following methods are important part of the abstraction (which
mimics libuv's stream API):
* Events:
* `OnAlloc(size_t size, uv_buf_t*)`
* `OnRead(ssize_t nread, const uv_buf_t*, uv_handle_type pending)`
* `OnAfterWrite(WriteWrap*)`
* Wrappers:
* `DoShutdown(ShutdownWrap*)`
* `DoTryWrite(uv_buf_t** bufs, size_t* count)`
* `DoWrite(WriteWrap*, uv_buf_t*, size_t count, uv_stream_t* handle)`
* `Error()`
* `ClearError()`
The implementation should provide all of these methods, thus providing
the access to the underlying resource (be it uv handle, TLS socket, or
anything else).
A C++ stream may consume the input of another stream by replacing the
event callbacks and proxying the writes. This kind of API is actually
used now for the TLSWrap implementation, making it possible to wrap TLS
stream into another TLS stream. Thus legacy API calls are no longer
required in `_tls_wrap.js`.
PR-URL: https://github.com/iojs/io.js/pull/840
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
Reviewed-By: Chris Dickinson <christopher.s.dickinson@gmail.com>
10 years ago
|
|
|
StreamWrap::AddMethods(env, t);
|
|
|
|
|
|
|
|
env->SetProtoMethod(t, "getWindowSize", TTYWrap::GetWindowSize);
|
|
|
|
env->SetProtoMethod(t, "setRawMode", SetRawMode);
|
|
|
|
|
|
|
|
env->SetMethod(target, "isTTY", IsTTY);
|
|
|
|
env->SetMethod(target, "guessHandleType", GuessHandleType);
|
|
|
|
|
|
|
|
target->Set(FIXED_ONE_BYTE_STRING(env->isolate(), "TTY"), t->GetFunction());
|
|
|
|
env->set_tty_constructor_template(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
uv_tty_t* TTYWrap::UVHandle() {
|
|
|
|
return &handle_;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TTYWrap::GuessHandleType(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
int fd = args[0]->Int32Value();
|
|
|
|
CHECK_GE(fd, 0);
|
|
|
|
|
|
|
|
uv_handle_type t = uv_guess_handle(fd);
|
|
|
|
const char* type = nullptr;
|
|
|
|
|
|
|
|
switch (t) {
|
|
|
|
case UV_TCP: type = "TCP"; break;
|
|
|
|
case UV_TTY: type = "TTY"; break;
|
|
|
|
case UV_UDP: type = "UDP"; break;
|
|
|
|
case UV_FILE: type = "FILE"; break;
|
|
|
|
case UV_NAMED_PIPE: type = "PIPE"; break;
|
|
|
|
case UV_UNKNOWN_HANDLE: type = "UNKNOWN"; break;
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
args.GetReturnValue().Set(OneByteString(env->isolate(), type));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TTYWrap::IsTTY(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
int fd = args[0]->Int32Value();
|
|
|
|
CHECK_GE(fd, 0);
|
|
|
|
bool rc = uv_guess_handle(fd) == UV_TTY;
|
|
|
|
args.GetReturnValue().Set(rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TTYWrap::GetWindowSize(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
|
|
|
|
TTYWrap* wrap = Unwrap<TTYWrap>(args.Holder());
|
|
|
|
CHECK(args[0]->IsArray());
|
|
|
|
|
|
|
|
int width, height;
|
|
|
|
int err = uv_tty_get_winsize(&wrap->handle_, &width, &height);
|
|
|
|
|
|
|
|
if (err == 0) {
|
|
|
|
Local<v8::Array> a = args[0].As<Array>();
|
|
|
|
a->Set(0, Integer::New(env->isolate(), width));
|
|
|
|
a->Set(1, Integer::New(env->isolate(), height));
|
|
|
|
}
|
|
|
|
|
|
|
|
args.GetReturnValue().Set(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TTYWrap::SetRawMode(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
TTYWrap* wrap = Unwrap<TTYWrap>(args.Holder());
|
|
|
|
int err = uv_tty_set_mode(&wrap->handle_, args[0]->IsTrue());
|
|
|
|
args.GetReturnValue().Set(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TTYWrap::New(const FunctionCallbackInfo<Value>& args) {
|
|
|
|
Environment* env = Environment::GetCurrent(args);
|
|
|
|
|
|
|
|
// This constructor should not be exposed to public javascript.
|
|
|
|
// Therefore we assert that we are not trying to call this as a
|
|
|
|
// normal function.
|
|
|
|
CHECK(args.IsConstructCall());
|
|
|
|
|
|
|
|
int fd = args[0]->Int32Value();
|
|
|
|
CHECK_GE(fd, 0);
|
|
|
|
|
|
|
|
TTYWrap* wrap = new TTYWrap(env, args.This(), fd, args[1]->IsTrue());
|
|
|
|
wrap->UpdateWriteQueueSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TTYWrap::TTYWrap(Environment* env, Handle<Object> object, int fd, bool readable)
|
|
|
|
: StreamWrap(env,
|
|
|
|
object,
|
|
|
|
reinterpret_cast<uv_stream_t*>(&handle_),
|
|
|
|
AsyncWrap::PROVIDER_TTYWRAP) {
|
|
|
|
uv_tty_init(env->event_loop(), &handle_, fd, readable);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace node
|
|
|
|
|
|
|
|
NODE_MODULE_CONTEXT_AWARE_BUILTIN(tty_wrap, node::TTYWrap::Initialize)
|