mirror of
https://github.com/nodejs/node.git
synced 2024-11-29 15:06:33 +01:00
Remove error codes from file on_completion callbacks. Use file.onError.
The error codes still remain for the two general file system operations: rename and stat. Additionally I've removed the actionQueue for file system operations. They are sent directly into the thread pool.
This commit is contained in:
parent
58c13e5192
commit
5c2389fada
165
src/file.cc
165
src/file.cc
@ -12,55 +12,40 @@
|
||||
using namespace v8;
|
||||
using namespace node;
|
||||
|
||||
#define FD_SYMBOL v8::String::NewSymbol("fd")
|
||||
#define ACTION_QUEUE_SYMBOL v8::String::NewSymbol("_actionQueue")
|
||||
#define ENCODING_SYMBOL v8::String::NewSymbol("encoding")
|
||||
#define FD_SYMBOL String::NewSymbol("fd")
|
||||
#define ACTION_QUEUE_SYMBOL String::NewSymbol("_actionQueue")
|
||||
#define ENCODING_SYMBOL String::NewSymbol("encoding")
|
||||
#define CALLBACK_SYMBOL String::NewSymbol("callbaccallback")
|
||||
#define POLL_ACTIONS_SYMBOL String::NewSymbol("_pollActions")
|
||||
|
||||
#define UTF8_SYMBOL v8::String::NewSymbol("utf8")
|
||||
#define RAW_SYMBOL v8::String::NewSymbol("raw")
|
||||
|
||||
static void
|
||||
InitActionQueue (Handle<Object> handle)
|
||||
{
|
||||
handle->Set(ACTION_QUEUE_SYMBOL, Array::New());
|
||||
}
|
||||
|
||||
// This is the file system object which contains methods
|
||||
// for accessing the file system (like rename, mkdir, etC).
|
||||
// In javascript it is called "File".
|
||||
static Persistent<Object> fs;
|
||||
#define UTF8_SYMBOL String::NewSymbol("utf8")
|
||||
#define RAW_SYMBOL String::NewSymbol("raw")
|
||||
|
||||
void
|
||||
File::Initialize (Handle<Object> target)
|
||||
{
|
||||
if (!fs.IsEmpty())
|
||||
return;
|
||||
|
||||
HandleScope scope;
|
||||
|
||||
fs = Persistent<Object>::New(target);
|
||||
InitActionQueue(fs);
|
||||
|
||||
|
||||
// file system methods
|
||||
NODE_SET_METHOD(fs, "_ffi_rename", FileSystem::Rename);
|
||||
NODE_SET_METHOD(fs, "_ffi_stat", FileSystem::Stat);
|
||||
NODE_SET_METHOD(fs, "strerror", FileSystem::StrError);
|
||||
NODE_SET_METHOD(target, "rename", FileSystem::Rename);
|
||||
NODE_SET_METHOD(target, "stat", FileSystem::Stat);
|
||||
NODE_SET_METHOD(target, "strerror", FileSystem::StrError);
|
||||
|
||||
fs->Set(String::NewSymbol("STDIN_FILENO"), Integer::New(STDIN_FILENO));
|
||||
fs->Set(String::NewSymbol("STDOUT_FILENO"), Integer::New(STDOUT_FILENO));
|
||||
fs->Set(String::NewSymbol("STDERR_FILENO"), Integer::New(STDERR_FILENO));
|
||||
target->Set(String::NewSymbol("STDIN_FILENO"), Integer::New(STDIN_FILENO));
|
||||
target->Set(String::NewSymbol("STDOUT_FILENO"), Integer::New(STDOUT_FILENO));
|
||||
target->Set(String::NewSymbol("STDERR_FILENO"), Integer::New(STDERR_FILENO));
|
||||
|
||||
|
||||
Local<FunctionTemplate> file_template = FunctionTemplate::New(File::New);
|
||||
file_template->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
|
||||
// file methods
|
||||
NODE_SET_PROTOTYPE_METHOD(file_template, "_ffi_open", File::Open);
|
||||
NODE_SET_PROTOTYPE_METHOD(file_template, "_ffi_close", File::Close);
|
||||
NODE_SET_PROTOTYPE_METHOD(file_template, "_ffi_write", File::Write);
|
||||
NODE_SET_PROTOTYPE_METHOD(file_template, "_ffi_read", File::Read);
|
||||
file_template->InstanceTemplate()->SetAccessor(ENCODING_SYMBOL, File::GetEncoding, File::SetEncoding);
|
||||
fs->Set(String::NewSymbol("File"), file_template->GetFunction());
|
||||
target->Set(String::NewSymbol("File"), file_template->GetFunction());
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
@ -95,32 +80,15 @@ CallTopCallback (Handle<Object> handle, const int argc, Handle<Value> argv[])
|
||||
{
|
||||
HandleScope scope;
|
||||
|
||||
Local<Value> queue_value = handle->Get(ACTION_QUEUE_SYMBOL);
|
||||
assert(queue_value->IsArray());
|
||||
|
||||
Local<Array> queue = Local<Array>::Cast(queue_value);
|
||||
Local<Value> top_value = queue->Get(Integer::New(0));
|
||||
if (top_value->IsObject()) {
|
||||
Local<Object> top = top_value->ToObject();
|
||||
Local<Value> callback_value = top->Get(String::NewSymbol("callback"));
|
||||
if (callback_value->IsFunction()) {
|
||||
Handle<Function> callback = Handle<Function>::Cast(callback_value);
|
||||
|
||||
TryCatch try_catch;
|
||||
callback->Call(handle, argc, argv);
|
||||
if(try_catch.HasCaught()) {
|
||||
node::fatal_exception(try_catch);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// poll_actions
|
||||
Local<Value> poll_actions_value = handle->Get(String::NewSymbol("_pollActions"));
|
||||
Local<Value> poll_actions_value = handle->Get(POLL_ACTIONS_SYMBOL);
|
||||
assert(poll_actions_value->IsFunction());
|
||||
Handle<Function> poll_actions = Handle<Function>::Cast(poll_actions_value);
|
||||
|
||||
poll_actions->Call(handle, 0, NULL);
|
||||
TryCatch try_catch;
|
||||
poll_actions->Call(handle, argc, argv);
|
||||
if(try_catch.HasCaught())
|
||||
node::fatal_exception(try_catch);
|
||||
}
|
||||
|
||||
Handle<Value>
|
||||
@ -134,6 +102,13 @@ FileSystem::Rename (const Arguments& args)
|
||||
String::Utf8Value path(args[0]->ToString());
|
||||
String::Utf8Value new_path(args[1]->ToString());
|
||||
|
||||
Persistent<Function> *callback = NULL;
|
||||
if (args[2]->IsFunction()) {
|
||||
Local<Function> l = Local<Function>::Cast(args[2]);
|
||||
callback = new Persistent<Function>();
|
||||
*callback = Persistent<Function>::New(l);
|
||||
}
|
||||
|
||||
node::eio_warmup();
|
||||
eio_rename(*path, *new_path, EIO_PRI_DEFAULT, AfterRename, NULL);
|
||||
|
||||
@ -147,7 +122,18 @@ FileSystem::AfterRename (eio_req *req)
|
||||
const int argc = 1;
|
||||
Local<Value> argv[argc];
|
||||
argv[0] = Integer::New(req->errorno);
|
||||
CallTopCallback(fs, argc, argv);
|
||||
|
||||
if (req->data) {
|
||||
Persistent<Function> *callback = reinterpret_cast<Persistent<Function>*>(req->data);
|
||||
|
||||
TryCatch try_catch;
|
||||
(*callback)->Call(Context::GetCurrent()->Global(), argc, argv);
|
||||
if(try_catch.HasCaught())
|
||||
node::fatal_exception(try_catch);
|
||||
|
||||
free(callback);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -161,8 +147,15 @@ FileSystem::Stat (const Arguments& args)
|
||||
|
||||
String::Utf8Value path(args[0]->ToString());
|
||||
|
||||
Persistent<Function> *callback = NULL;
|
||||
if (args[1]->IsFunction()) {
|
||||
Local<Function> l = Local<Function>::Cast(args[1]);
|
||||
callback = new Persistent<Function>();
|
||||
*callback = Persistent<Function>::New(l);
|
||||
}
|
||||
|
||||
node::eio_warmup();
|
||||
eio_stat(*path, EIO_PRI_DEFAULT, AfterStat, NULL);
|
||||
eio_stat(*path, EIO_PRI_DEFAULT, AfterStat, callback);
|
||||
|
||||
return Undefined();
|
||||
}
|
||||
@ -180,7 +173,7 @@ FileSystem::AfterStat (eio_req *req)
|
||||
argv[1] = stats;
|
||||
|
||||
if (req->result == 0) {
|
||||
struct stat *s = static_cast<struct stat*>(req->ptr2);
|
||||
struct stat *s = reinterpret_cast<struct stat*>(req->ptr2);
|
||||
|
||||
/* ID of device containing file */
|
||||
stats->Set(NODE_SYMBOL("dev"), Integer::New(s->st_dev));
|
||||
@ -210,8 +203,17 @@ FileSystem::AfterStat (eio_req *req)
|
||||
stats->Set(NODE_SYMBOL("ctime"), Date::New(1000*static_cast<double>(s->st_ctime)));
|
||||
}
|
||||
|
||||
CallTopCallback(fs, argc, argv);
|
||||
|
||||
if (req->data) {
|
||||
Persistent<Function> *callback = reinterpret_cast<Persistent<Function>*>(req->data);
|
||||
|
||||
TryCatch try_catch;
|
||||
(*callback)->Call(Context::GetCurrent()->Global(), argc, argv);
|
||||
if(try_catch.HasCaught())
|
||||
node::fatal_exception(try_catch);
|
||||
|
||||
free(callback);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -237,7 +239,7 @@ File::File (Handle<Object> handle)
|
||||
{
|
||||
HandleScope scope;
|
||||
encoding_ = RAW;
|
||||
InitActionQueue(handle);
|
||||
handle->Set(ACTION_QUEUE_SYMBOL, Array::New());
|
||||
}
|
||||
|
||||
File::~File ()
|
||||
@ -277,7 +279,7 @@ File::Close (const Arguments& args)
|
||||
int
|
||||
File::AfterClose (eio_req *req)
|
||||
{
|
||||
File *file = static_cast<File*>(req->data);
|
||||
File *file = reinterpret_cast<File*>(req->data);
|
||||
|
||||
if (req->result == 0) {
|
||||
file->handle_->Delete(FD_SYMBOL);
|
||||
@ -338,7 +340,7 @@ File::Open (const Arguments& args)
|
||||
int
|
||||
File::AfterOpen (eio_req *req)
|
||||
{
|
||||
File *file = static_cast<File*>(req->data);
|
||||
File *file = reinterpret_cast<File*>(req->data);
|
||||
HandleScope scope;
|
||||
|
||||
if(req->result >= 0) {
|
||||
@ -364,6 +366,8 @@ File::Write (const Arguments& args)
|
||||
|
||||
File *file = NODE_UNWRAP(File, args.Holder());
|
||||
|
||||
off_t pos = args[1]->IntegerValue();
|
||||
|
||||
char *buf = NULL;
|
||||
size_t length = 0;
|
||||
|
||||
@ -371,14 +375,14 @@ File::Write (const Arguments& args)
|
||||
// utf8 encoding
|
||||
Local<String> string = args[0]->ToString();
|
||||
length = string->Utf8Length();
|
||||
buf = static_cast<char*>(malloc(length));
|
||||
buf = reinterpret_cast<char*>(malloc(length));
|
||||
string->WriteUtf8(buf, length);
|
||||
|
||||
} else if (args[0]->IsArray()) {
|
||||
// raw encoding
|
||||
Local<Array> array = Local<Array>::Cast(args[0]);
|
||||
length = array->Length();
|
||||
buf = static_cast<char*>(malloc(length));
|
||||
buf = reinterpret_cast<char*>(malloc(length));
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
Local<Value> int_value = array->Get(Integer::New(i));
|
||||
buf[i] = int_value->Int32Value();
|
||||
@ -389,8 +393,6 @@ File::Write (const Arguments& args)
|
||||
return Undefined();
|
||||
}
|
||||
|
||||
off_t pos = args[1]->IntegerValue();
|
||||
|
||||
if (file->handle_->Has(FD_SYMBOL) == false) {
|
||||
printf("trying to write to a bad fd!\n");
|
||||
return Undefined();
|
||||
@ -408,9 +410,9 @@ File::Write (const Arguments& args)
|
||||
int
|
||||
File::AfterWrite (eio_req *req)
|
||||
{
|
||||
File *file = static_cast<File*>(req->data);
|
||||
File *file = reinterpret_cast<File*>(req->data);
|
||||
|
||||
//char *buf = static_cast<char*>(req->ptr2);
|
||||
//char *buf = reinterpret_cast<char*>(req->ptr2);
|
||||
free(req->ptr2);
|
||||
ssize_t written = req->result;
|
||||
|
||||
@ -429,20 +431,22 @@ File::AfterWrite (eio_req *req)
|
||||
Handle<Value>
|
||||
File::Read (const Arguments& args)
|
||||
{
|
||||
if (args.Length() < 1) return Undefined();
|
||||
if (!args[0]->IsNumber()) return Undefined();
|
||||
if (!args[1]->IsNumber()) return Undefined();
|
||||
|
||||
HandleScope scope;
|
||||
|
||||
if (args.Length() < 1 || !args[0]->IsNumber() || !args[1]->IsNumber()) {
|
||||
return ThrowException(String::New("Bad parameter for _ffi_read()"));
|
||||
}
|
||||
|
||||
File *file = NODE_UNWRAP(File, args.Holder());
|
||||
size_t length = args[0]->IntegerValue();
|
||||
off_t pos = args[1]->IntegerValue();
|
||||
size_t len = args[0]->IntegerValue();
|
||||
off_t pos = args[1]->IntegerValue();
|
||||
|
||||
int fd = file->GetFD();
|
||||
assert(fd >= 0);
|
||||
|
||||
// NOTE: NULL pointer tells eio to allocate it itself
|
||||
// NOTE: 2nd param: NULL pointer tells eio to allocate it itself
|
||||
node::eio_warmup();
|
||||
eio_read(fd, NULL, length, pos, EIO_PRI_DEFAULT, File::AfterRead, file);
|
||||
eio_read(fd, NULL, len, pos, EIO_PRI_DEFAULT, File::AfterRead, file);
|
||||
|
||||
file->Attach();
|
||||
return Undefined();
|
||||
@ -451,32 +455,33 @@ File::Read (const Arguments& args)
|
||||
int
|
||||
File::AfterRead (eio_req *req)
|
||||
{
|
||||
File *file = static_cast<File*>(req->data);
|
||||
File *file = reinterpret_cast<File*>(req->data);
|
||||
HandleScope scope;
|
||||
|
||||
const int argc = 2;
|
||||
Local<Value> argv[argc];
|
||||
argv[0] = Integer::New(req->errorno);
|
||||
|
||||
char *buf = static_cast<char*>(req->ptr2);
|
||||
char *buf = reinterpret_cast<char*>(req->ptr2);
|
||||
|
||||
if(req->result == 0) {
|
||||
if (req->result == 0) {
|
||||
// eof
|
||||
argv[1] = Local<Value>::New(Null());
|
||||
} else {
|
||||
size_t length = req->result;
|
||||
size_t len = req->result;
|
||||
if (file->encoding_ == UTF8) {
|
||||
// utf8 encoding
|
||||
argv[1] = String::New(buf, req->result);
|
||||
} else {
|
||||
// raw encoding
|
||||
Local<Array> array = Array::New(length);
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
Local<Array> array = Array::New(len);
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
array->Set(Integer::New(i), Integer::New(buf[i]));
|
||||
}
|
||||
argv[1] = array;
|
||||
}
|
||||
}
|
||||
|
||||
CallTopCallback(file->handle_, argc, argv);
|
||||
|
||||
file->Detach();
|
||||
|
107
src/file.js
107
src/file.js
@ -1,13 +1,5 @@
|
||||
node.fs.rename = function (file1, file2, callback) {
|
||||
this._addAction("rename", [file1, file2], callback);
|
||||
};
|
||||
|
||||
node.fs.stat = function (path, callback) {
|
||||
this._addAction("stat", [path], callback);
|
||||
};
|
||||
|
||||
node.fs.exists = function (path, callback) {
|
||||
this._addAction("stat", [path], function (status) {
|
||||
node.fs.stat(path, function (status) {
|
||||
callback(status == 0);
|
||||
});
|
||||
}
|
||||
@ -16,16 +8,17 @@ node.fs.cat = function (path, encoding, callback) {
|
||||
var file = new node.fs.File();
|
||||
file.encoding = encoding;
|
||||
|
||||
var content = "";
|
||||
if (file.encoding == "raw") content = [];
|
||||
file.onError = function (method, errno, msg) {
|
||||
callback(-1);
|
||||
};
|
||||
|
||||
var content = (file.encoding == "raw" ? "" : []);
|
||||
var pos = 0;
|
||||
var chunkSize = 10*1024;
|
||||
|
||||
function readChunk () {
|
||||
file.read(chunkSize, pos, function (status, chunk) {
|
||||
file.read(chunkSize, pos, function (chunk) {
|
||||
if (chunk) {
|
||||
|
||||
if (chunk.constructor == String)
|
||||
content += chunk;
|
||||
else
|
||||
@ -40,22 +33,11 @@ node.fs.cat = function (path, encoding, callback) {
|
||||
});
|
||||
}
|
||||
|
||||
file.open(path, "r", function (status) {
|
||||
if (status == 0)
|
||||
readChunk();
|
||||
else
|
||||
callback (status);
|
||||
file.open(path, "r", function () {
|
||||
readChunk();
|
||||
});
|
||||
}
|
||||
|
||||
node.fs.File.prototype.puts = function (data, callback) {
|
||||
this.write(data + "\n", -1, callback);
|
||||
};
|
||||
|
||||
node.fs.File.prototype.print = function (data, callback) {
|
||||
this.write(data, -1, callback);
|
||||
};
|
||||
|
||||
node.fs.File.prototype.open = function (path, mode, callback) {
|
||||
this._addAction("open", [path, mode], callback);
|
||||
};
|
||||
@ -64,12 +46,20 @@ node.fs.File.prototype.close = function (callback) {
|
||||
this._addAction("close", [], callback);
|
||||
};
|
||||
|
||||
node.fs.File.prototype.read = function (length, pos, callback) {
|
||||
this._addAction("read", [length, pos], callback);
|
||||
};
|
||||
|
||||
node.fs.File.prototype.write = function (buf, pos, callback) {
|
||||
this._addAction("write", [buf, pos], callback);
|
||||
};
|
||||
|
||||
node.fs.File.prototype.read = function (length, pos, callback) {
|
||||
this._addAction("read", [length, pos], callback);
|
||||
node.fs.File.prototype.print = function (data, callback) {
|
||||
this.write(data, -1, callback);
|
||||
};
|
||||
|
||||
node.fs.File.prototype.puts = function (data, callback) {
|
||||
this.write(data + "\n", -1, callback);
|
||||
};
|
||||
|
||||
// Some explanation of the File binding.
|
||||
@ -84,38 +74,65 @@ node.fs.File.prototype.read = function (length, pos, callback) {
|
||||
// the member _actionQueue = []
|
||||
//
|
||||
// Any of the methods called on a file are put into this queue. When they
|
||||
// reach the head of the queue they will be executed. C++ calles the
|
||||
// reach the head of the queue they will be executed. C++ calls the
|
||||
// method _pollActions each time it becomes idle. If there is no action
|
||||
// currently being executed then _pollActions will not be called. Thus when
|
||||
// actions are added to an empty _actionQueue, they should be immediately
|
||||
// currently being executed then _pollActions will not be called. When
|
||||
// actions are added to an empty _actionQueue, they will be immediately
|
||||
// executed.
|
||||
//
|
||||
// When an action has completed, the C++ side is going to look at the first
|
||||
// When an action has completed, the C++ side is looks at the first
|
||||
// element of _actionQueue in order to get a handle on the callback
|
||||
// function. Only after that completion callback has been made can the
|
||||
// action be shifted out of the queue.
|
||||
//
|
||||
// See File::CallTopCallback() in file.cc to see the other side of the
|
||||
// binding.
|
||||
node.fs._addAction = node.fs.File.prototype._addAction = function (method, args, callback) {
|
||||
this._actionQueue.push({ method: method
|
||||
, callback: callback
|
||||
, args: args
|
||||
});
|
||||
if (this._actionQueue.length == 1) this._act();
|
||||
}
|
||||
// See File::CallTopCallback() in file.cc for the other side of the binding.
|
||||
|
||||
node.fs._act = node.fs.File.prototype._act = function () {
|
||||
|
||||
node.fs.File.prototype._addAction = function (method, args, callback) {
|
||||
// This adds a method to the queue.
|
||||
var action = { method: method
|
||||
, callback: callback
|
||||
, args: args
|
||||
};
|
||||
this._actionQueue.push(action);
|
||||
|
||||
// If the queue was empty, immediately call the method.
|
||||
if (this._actionQueue.length == 1) this._act();
|
||||
};
|
||||
|
||||
node.fs.File.prototype._act = function () {
|
||||
// peek at the head of the queue
|
||||
var action = this._actionQueue[0];
|
||||
if (action)
|
||||
// TODO FIXME what if the action throws an error?
|
||||
if (action) {
|
||||
// execute the c++ version of the method. the c++ version
|
||||
// is gotten by appending "_ffi_" to the method name.
|
||||
this["_ffi_" + action.method].apply(this, action.args);
|
||||
}
|
||||
};
|
||||
|
||||
// called from C++ after each action finishes
|
||||
// (i.e. when it returns from the thread pool)
|
||||
node.fs._pollActions = node.fs.File.prototype._pollActions = function () {
|
||||
node.fs.File.prototype._pollActions = function () {
|
||||
var action = this._actionQueue[0];
|
||||
|
||||
var errno = arguments[0];
|
||||
|
||||
if (errno < 0) {
|
||||
if (this.onError)
|
||||
this.onError(action.method, errno, node.fs.strerror(errno));
|
||||
this._actionQueue = []; // empty the queue.
|
||||
return;
|
||||
}
|
||||
|
||||
var rest = [];
|
||||
for (var i = 1; i < arguments.length; i++)
|
||||
rest.push(arguments[i]);
|
||||
|
||||
if (action.callback)
|
||||
action.callback.apply(this, rest);
|
||||
|
||||
this._actionQueue.shift();
|
||||
|
||||
this._act();
|
||||
};
|
||||
|
||||
|
@ -7,8 +7,11 @@ function onLoad () {
|
||||
var x = node.path.join(fixtures, "x.txt");
|
||||
|
||||
file = new node.fs.File;
|
||||
file.open(x, "r", function (status) {
|
||||
assertTrue(status == 0);
|
||||
file.onError = function (method, errno, msg) {
|
||||
assertTrue(false);
|
||||
};
|
||||
|
||||
file.open(x, "r", function () {
|
||||
assert_count += 1;
|
||||
file.close();
|
||||
});
|
||||
|
@ -80,11 +80,11 @@ a:hover { text-decoration: underline; }
|
||||
<ol>
|
||||
<li><a href="#benchmarks">Benchmarks</a></li>
|
||||
<li><a href="#download">Download</a></li>
|
||||
<li><a href="#install">Build</a></li>
|
||||
<li><a href="#build">Build</a></li>
|
||||
<li><a href="#api">API</a>
|
||||
<ol>
|
||||
<li><a href="#timers">Timers</a>
|
||||
<li><a href="#files">File System I/O</a>
|
||||
<li><a href="#files">File I/O</a>
|
||||
<li><a href="#tcp">TCP</a>
|
||||
<ol>
|
||||
<li><a href="#tcp_server">Server</a>
|
||||
@ -166,12 +166,15 @@ always have a capital first letter.
|
||||
|
||||
<dl>
|
||||
<dt><code class="sh_javascript">puts(string, callback)</code></dt>
|
||||
<dd>Outputs the <code>string</code> and a trailing new-line to <code>stdout</code>.
|
||||
<dd>
|
||||
Alias for <code class="sh_javascript">stdout.puts()</code>.
|
||||
|
||||
Outputs the <code>string</code> and a trailing new-line to <code>stdout</code>.
|
||||
<p>The <code>callback</code> argument is optional and mostly useless: it will
|
||||
notify the user when the operation has completed. Everything in node is
|
||||
asynchronous; <code>puts()</code> is no exception. This might seem ridiculous
|
||||
but, if for example, one is piping their output into an NFS'd file,
|
||||
<code>printf()</code> will block.
|
||||
but, if for example, one is piping <code>stdout</code> into an NFS file,
|
||||
<code>printf()</code> will block from network latency.
|
||||
There is an internal queue for <code>puts()</code> output, so you can be assured that
|
||||
output will be displayed in the order it was called.
|
||||
</dd>
|
||||
@ -204,45 +207,80 @@ always have a capital first letter.
|
||||
<dd> Stops a interval from triggering. </dd>
|
||||
</dl>
|
||||
|
||||
<h3 id="files">node.File</h3>
|
||||
<h3 id="files">node.fs</h3>
|
||||
|
||||
<p> File system I/O has always been tricky because there are not any portable
|
||||
non-blocking ways to do it. To get around this, Node uses <a
|
||||
<p>Because there are not non-blocking ways to do it, asynchronous file I/O is
|
||||
tricky. Node handles file I/O by employing <a
|
||||
href="http://software.schmorp.de/pkg/libeio.html">an internal thread pool</a>
|
||||
to execute file system calls asynchronously.
|
||||
to execute file system calls.
|
||||
|
||||
<p>Internal request queues exist for each file object so that multiple commands
|
||||
can be issued at once without worry that they will be executed out-of-order.
|
||||
Thus the following is safe:
|
||||
|
||||
<p>All file I/O calls are rather thin wrappers around standard POSIX functions.
|
||||
All calls have an optional last callback parameter
|
||||
|
||||
|
||||
|
||||
|
||||
<p>Internal request queues exist for each file object so multiple commands can
|
||||
be issued at once without worry that they will reach the file system out of
|
||||
order. Thus the following is safe:
|
||||
<pre class="sh_javascript">
|
||||
var file = new node.File();
|
||||
var file = new node.fs.File();
|
||||
file.open("/tmp/blah", "w+");
|
||||
file.write("hello ");
|
||||
file.write("hello");
|
||||
file.write("world");
|
||||
file.close();</pre>
|
||||
Additionally there is a process-wide queue for all commands which operate on
|
||||
the file system directory structure (like <code>rename</code> and
|
||||
<code>unlink</code>). It's important to understand that all of these request queues are
|
||||
distinct. If, for example, you do
|
||||
|
||||
<p>
|
||||
It's important to understand that the request queues are local to a single file.
|
||||
If one does
|
||||
<pre class="sh_javascript">fileA.write("hello");
|
||||
fileB.write("world");</pre>
|
||||
it could be that
|
||||
first <code>fileB</code> gets written to and then <code>fileA</code> gets written to.
|
||||
So if a certain operation order is needed involving multiple files, use the
|
||||
it could be that <code>fileB</code> gets written to before <code>fileA</code>
|
||||
is written to.
|
||||
If a certain operation order is needed involving multiple files, use the
|
||||
completion callbacks:
|
||||
<pre class="sh_javascript">fileA.write("hello", function () {
|
||||
fileB.write("world");
|
||||
});</pre>
|
||||
|
||||
<dl>
|
||||
<dt><code class="sh_javascript">node.File.rename()</code></dt>
|
||||
<dt><code class="sh_javascript">new node.fs.File</code></dt>
|
||||
<dd>Creates a new file object. </dd>
|
||||
|
||||
<dt><code class="sh_javascript">file.open(path, mode, on_completion)</code></dt>
|
||||
<dd>Opens the file at <code>path</code>.
|
||||
<p><code>mode</code> is a string:
|
||||
<code>"r"</code> open for reading and writing.
|
||||
<code>"r+"</code> open for only reading.
|
||||
<code>"w"</code> create a new file for reading and writing; if it
|
||||
already exists truncate it.
|
||||
<code>"w+"</code> create a new file for writing only; if it already
|
||||
exists truncate it.
|
||||
<code>"a"</code> create a new file for writing and reading. Writes
|
||||
append to the end of the file.
|
||||
<code>"a+"</code>
|
||||
<p>The <code>on_completion</code> is a callback that is made without
|
||||
arguments when the operation completes. It is optional
|
||||
If an error occurred the <code>on_completion</code> callback will not be
|
||||
called, but the <code>file.onError</code> will be called.
|
||||
</dd>
|
||||
|
||||
<dt><code class="sh_javascript">file.read(length, position, on_completion)</code></dt>
|
||||
<dd>
|
||||
</dd>
|
||||
|
||||
<dt><code class="sh_javascript">file.write(data, position, on_completion)</code></dt>
|
||||
<dd>
|
||||
</dd>
|
||||
|
||||
<dt><code class="sh_javascript">file.close(on_completion)</code></dt>
|
||||
<dd>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<h4>File System Operations</h4>
|
||||
|
||||
<dl>
|
||||
<dt><code class="sh_javascript">node.fs.rename(path1, path2, on_completion)</code></dt>
|
||||
<dd>
|
||||
</dd>
|
||||
|
||||
<dt><code class="sh_javascript">node.fs.stat(path1, on_completion)</code></dt>
|
||||
<dd>
|
||||
</dd>
|
||||
</dl>
|
||||
@ -250,6 +288,10 @@ completion callbacks:
|
||||
|
||||
<h3 id="tcp"><code>node.tcp</code></h3>
|
||||
|
||||
<h4 id="tcp_server"><code>node.tcp.Server</code></h4>
|
||||
|
||||
<h4 id="tcp_connection"><code>node.tcp.Connection</code></h4>
|
||||
|
||||
<h3 id="http"><code>node.http</code></h3>
|
||||
|
||||
<p> Node provides a web server and client interface. The interface is rather
|
||||
@ -410,10 +452,11 @@ res.sendHeader(200, [ ["Content-Length", body.length]
|
||||
|
||||
<h4 id="http_client"><code class="sh_javascript">node.http.Client</code></h4>
|
||||
|
||||
<p> An HTTP client is constructed with a server address as its argument, then
|
||||
the user issues one or more requests. Depending on the server connected to,
|
||||
the client might pipeline the requests or reestablish the connection after each
|
||||
connection. <i>Currently the client does not pipeline requests.</i>
|
||||
<p> An HTTP client is constructed with a server address as its argument, the
|
||||
returned handle is then used to issue one or more requests. Depending on the
|
||||
server connected to, the client might pipeline the requests or reestablish the
|
||||
connection after each connection.
|
||||
<i>Currently the implementation does not pipeline requests.</i>
|
||||
|
||||
<p> Example of connecting to <code>google.com</code>
|
||||
<pre class="sh_javascript">
|
||||
@ -441,7 +484,9 @@ request is issued.
|
||||
<dt><code class="sh_javascript">client.post(path, request_headers);</code></dt>
|
||||
<dt><code class="sh_javascript">client.del(path, request_headers);</code></dt>
|
||||
<dt><code class="sh_javascript">client.put(path, request_headers);</code></dt>
|
||||
<dd> Issues a request.
|
||||
<dd> Issues a request; if necessary establishes connection.
|
||||
|
||||
<p>
|
||||
<code>request_headers</code> is optional.
|
||||
<code>request_headers</code> should be an array of 2-element arrays.
|
||||
Additional request headers might be added internally by Node.
|
||||
@ -450,15 +495,18 @@ request is issued.
|
||||
<p>Important: the request is not complete. This method only sends the
|
||||
header of the request. One needs to call <code>req.finish()</code> to finalize
|
||||
the request and retrieve the response. (This sounds convoluted but it provides
|
||||
a chance for the user to stream a body to the server with
|
||||
<code>req.sendBody</code>. <code>GET</code> and <code>HEAD</code> requests
|
||||
normally are without bodies but HTTP does not forbid it, so neither do we.)
|
||||
a chance for the user to stream a body to the server with <code
|
||||
class="sh_javascript">req.sendBody()</code>.)
|
||||
|
||||
<p><i> <code>GET</code> and
|
||||
<code>HEAD</code> requests normally are without bodies but HTTP does not forbid
|
||||
it, so neither do we.</i>
|
||||
|
||||
</dl>
|
||||
|
||||
<h4 id="http_client_request"><code class="sh_javascript">node.http.ClientRequest</code></h4>
|
||||
|
||||
<p>This object created internally and returned from the request methods of a
|
||||
<p>This object is created internally and returned from the request methods of a
|
||||
<code>node.http.Client</code>. It represents an <i>in-progress</i> request
|
||||
whose header has already been sent.
|
||||
|
||||
@ -500,7 +548,7 @@ read.
|
||||
|
||||
<dl>
|
||||
<dt><code class="sh_javascript">res.statusCode</code></dt>
|
||||
<dd>The 3-digit HTTP response status code. (E.G. <code class="sh_javascript">404</code>.)</dd>
|
||||
<dd>The 3-digit HTTP response status code. E.G. <code class="sh_javascript">404</code>.</dd>
|
||||
|
||||
<dt><code class="sh_javascript">res.httpVersion</code></dt>
|
||||
<dd>The HTTP version of the connected-to server. Probably either
|
||||
@ -513,7 +561,7 @@ read.
|
||||
|
||||
<dt><code class="sh_javascript">res.onBody</code></dt>
|
||||
<dd>Callback. Should be set by the user to be informed of when a piece
|
||||
of the message body is received.
|
||||
of the response body is received.
|
||||
A chunk of the body is given as the single argument. The transfer-encoding
|
||||
has been removed.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user