Browse Source

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.
v0.7.4-release
Ryan 16 years ago
parent
commit
5c2389fada
  1. 159
      src/file.cc
  2. 99
      src/file.js
  3. 7
      test/test-file-open.js
  4. 124
      website/node.html

159
src/file.cc

@ -12,55 +12,40 @@
using namespace v8; using namespace v8;
using namespace node; using namespace node;
#define FD_SYMBOL v8::String::NewSymbol("fd") #define FD_SYMBOL String::NewSymbol("fd")
#define ACTION_QUEUE_SYMBOL v8::String::NewSymbol("_actionQueue") #define ACTION_QUEUE_SYMBOL String::NewSymbol("_actionQueue")
#define ENCODING_SYMBOL v8::String::NewSymbol("encoding") #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 UTF8_SYMBOL String::NewSymbol("utf8")
#define RAW_SYMBOL v8::String::NewSymbol("raw") #define RAW_SYMBOL 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;
void void
File::Initialize (Handle<Object> target) File::Initialize (Handle<Object> target)
{ {
if (!fs.IsEmpty())
return;
HandleScope scope; HandleScope scope;
fs = Persistent<Object>::New(target);
InitActionQueue(fs);
// file system methods // file system methods
NODE_SET_METHOD(fs, "_ffi_rename", FileSystem::Rename); NODE_SET_METHOD(target, "rename", FileSystem::Rename);
NODE_SET_METHOD(fs, "_ffi_stat", FileSystem::Stat); NODE_SET_METHOD(target, "stat", FileSystem::Stat);
NODE_SET_METHOD(fs, "strerror", FileSystem::StrError); NODE_SET_METHOD(target, "strerror", FileSystem::StrError);
fs->Set(String::NewSymbol("STDIN_FILENO"), Integer::New(STDIN_FILENO)); target->Set(String::NewSymbol("STDIN_FILENO"), Integer::New(STDIN_FILENO));
fs->Set(String::NewSymbol("STDOUT_FILENO"), Integer::New(STDOUT_FILENO)); target->Set(String::NewSymbol("STDOUT_FILENO"), Integer::New(STDOUT_FILENO));
fs->Set(String::NewSymbol("STDERR_FILENO"), Integer::New(STDERR_FILENO)); target->Set(String::NewSymbol("STDERR_FILENO"), Integer::New(STDERR_FILENO));
Local<FunctionTemplate> file_template = FunctionTemplate::New(File::New); Local<FunctionTemplate> file_template = FunctionTemplate::New(File::New);
file_template->InstanceTemplate()->SetInternalFieldCount(1); file_template->InstanceTemplate()->SetInternalFieldCount(1);
// file methods // file methods
NODE_SET_PROTOTYPE_METHOD(file_template, "_ffi_open", File::Open); 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_close", File::Close);
NODE_SET_PROTOTYPE_METHOD(file_template, "_ffi_write", File::Write); NODE_SET_PROTOTYPE_METHOD(file_template, "_ffi_write", File::Write);
NODE_SET_PROTOTYPE_METHOD(file_template, "_ffi_read", File::Read); NODE_SET_PROTOTYPE_METHOD(file_template, "_ffi_read", File::Read);
file_template->InstanceTemplate()->SetAccessor(ENCODING_SYMBOL, File::GetEncoding, File::SetEncoding); 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> Handle<Value>
@ -95,32 +80,15 @@ CallTopCallback (Handle<Object> handle, const int argc, Handle<Value> argv[])
{ {
HandleScope scope; 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 // 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()); assert(poll_actions_value->IsFunction());
Handle<Function> poll_actions = Handle<Function>::Cast(poll_actions_value); 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> Handle<Value>
@ -134,6 +102,13 @@ FileSystem::Rename (const Arguments& args)
String::Utf8Value path(args[0]->ToString()); String::Utf8Value path(args[0]->ToString());
String::Utf8Value new_path(args[1]->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(); node::eio_warmup();
eio_rename(*path, *new_path, EIO_PRI_DEFAULT, AfterRename, NULL); eio_rename(*path, *new_path, EIO_PRI_DEFAULT, AfterRename, NULL);
@ -147,7 +122,18 @@ FileSystem::AfterRename (eio_req *req)
const int argc = 1; const int argc = 1;
Local<Value> argv[argc]; Local<Value> argv[argc];
argv[0] = Integer::New(req->errorno); 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; return 0;
} }
@ -161,8 +147,15 @@ FileSystem::Stat (const Arguments& args)
String::Utf8Value path(args[0]->ToString()); 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(); node::eio_warmup();
eio_stat(*path, EIO_PRI_DEFAULT, AfterStat, NULL); eio_stat(*path, EIO_PRI_DEFAULT, AfterStat, callback);
return Undefined(); return Undefined();
} }
@ -180,7 +173,7 @@ FileSystem::AfterStat (eio_req *req)
argv[1] = stats; argv[1] = stats;
if (req->result == 0) { 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 */ /* ID of device containing file */
stats->Set(NODE_SYMBOL("dev"), Integer::New(s->st_dev)); stats->Set(NODE_SYMBOL("dev"), Integer::New(s->st_dev));
@ -210,7 +203,16 @@ FileSystem::AfterStat (eio_req *req)
stats->Set(NODE_SYMBOL("ctime"), Date::New(1000*static_cast<double>(s->st_ctime))); 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; return 0;
} }
@ -237,7 +239,7 @@ File::File (Handle<Object> handle)
{ {
HandleScope scope; HandleScope scope;
encoding_ = RAW; encoding_ = RAW;
InitActionQueue(handle); handle->Set(ACTION_QUEUE_SYMBOL, Array::New());
} }
File::~File () File::~File ()
@ -277,7 +279,7 @@ File::Close (const Arguments& args)
int int
File::AfterClose (eio_req *req) File::AfterClose (eio_req *req)
{ {
File *file = static_cast<File*>(req->data); File *file = reinterpret_cast<File*>(req->data);
if (req->result == 0) { if (req->result == 0) {
file->handle_->Delete(FD_SYMBOL); file->handle_->Delete(FD_SYMBOL);
@ -338,7 +340,7 @@ File::Open (const Arguments& args)
int int
File::AfterOpen (eio_req *req) File::AfterOpen (eio_req *req)
{ {
File *file = static_cast<File*>(req->data); File *file = reinterpret_cast<File*>(req->data);
HandleScope scope; HandleScope scope;
if(req->result >= 0) { if(req->result >= 0) {
@ -364,6 +366,8 @@ File::Write (const Arguments& args)
File *file = NODE_UNWRAP(File, args.Holder()); File *file = NODE_UNWRAP(File, args.Holder());
off_t pos = args[1]->IntegerValue();
char *buf = NULL; char *buf = NULL;
size_t length = 0; size_t length = 0;
@ -371,14 +375,14 @@ File::Write (const Arguments& args)
// utf8 encoding // utf8 encoding
Local<String> string = args[0]->ToString(); Local<String> string = args[0]->ToString();
length = string->Utf8Length(); length = string->Utf8Length();
buf = static_cast<char*>(malloc(length)); buf = reinterpret_cast<char*>(malloc(length));
string->WriteUtf8(buf, length); string->WriteUtf8(buf, length);
} else if (args[0]->IsArray()) { } else if (args[0]->IsArray()) {
// raw encoding // raw encoding
Local<Array> array = Local<Array>::Cast(args[0]); Local<Array> array = Local<Array>::Cast(args[0]);
length = array->Length(); length = array->Length();
buf = static_cast<char*>(malloc(length)); buf = reinterpret_cast<char*>(malloc(length));
for (unsigned int i = 0; i < length; i++) { for (unsigned int i = 0; i < length; i++) {
Local<Value> int_value = array->Get(Integer::New(i)); Local<Value> int_value = array->Get(Integer::New(i));
buf[i] = int_value->Int32Value(); buf[i] = int_value->Int32Value();
@ -389,8 +393,6 @@ File::Write (const Arguments& args)
return Undefined(); return Undefined();
} }
off_t pos = args[1]->IntegerValue();
if (file->handle_->Has(FD_SYMBOL) == false) { if (file->handle_->Has(FD_SYMBOL) == false) {
printf("trying to write to a bad fd!\n"); printf("trying to write to a bad fd!\n");
return Undefined(); return Undefined();
@ -408,9 +410,9 @@ File::Write (const Arguments& args)
int int
File::AfterWrite (eio_req *req) 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); free(req->ptr2);
ssize_t written = req->result; ssize_t written = req->result;
@ -429,20 +431,22 @@ File::AfterWrite (eio_req *req)
Handle<Value> Handle<Value>
File::Read (const Arguments& args) 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; 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()); File *file = NODE_UNWRAP(File, args.Holder());
size_t length = args[0]->IntegerValue(); size_t len = args[0]->IntegerValue();
off_t pos = args[1]->IntegerValue(); off_t pos = args[1]->IntegerValue();
int fd = file->GetFD(); 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(); 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(); file->Attach();
return Undefined(); return Undefined();
@ -451,32 +455,33 @@ File::Read (const Arguments& args)
int int
File::AfterRead (eio_req *req) File::AfterRead (eio_req *req)
{ {
File *file = static_cast<File*>(req->data); File *file = reinterpret_cast<File*>(req->data);
HandleScope scope; HandleScope scope;
const int argc = 2; const int argc = 2;
Local<Value> argv[argc]; Local<Value> argv[argc];
argv[0] = Integer::New(req->errorno); 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 // eof
argv[1] = Local<Value>::New(Null()); argv[1] = Local<Value>::New(Null());
} else { } else {
size_t length = req->result; size_t len = req->result;
if (file->encoding_ == UTF8) { if (file->encoding_ == UTF8) {
// utf8 encoding // utf8 encoding
argv[1] = String::New(buf, req->result); argv[1] = String::New(buf, req->result);
} else { } else {
// raw encoding // raw encoding
Local<Array> array = Array::New(length); Local<Array> array = Array::New(len);
for (unsigned int i = 0; i < length; i++) { for (unsigned int i = 0; i < len; i++) {
array->Set(Integer::New(i), Integer::New(buf[i])); array->Set(Integer::New(i), Integer::New(buf[i]));
} }
argv[1] = array; argv[1] = array;
} }
} }
CallTopCallback(file->handle_, argc, argv); CallTopCallback(file->handle_, argc, argv);
file->Detach(); file->Detach();

99
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) { node.fs.exists = function (path, callback) {
this._addAction("stat", [path], function (status) { node.fs.stat(path, function (status) {
callback(status == 0); callback(status == 0);
}); });
} }
@ -16,16 +8,17 @@ node.fs.cat = function (path, encoding, callback) {
var file = new node.fs.File(); var file = new node.fs.File();
file.encoding = encoding; file.encoding = encoding;
var content = ""; file.onError = function (method, errno, msg) {
if (file.encoding == "raw") content = []; callback(-1);
};
var content = (file.encoding == "raw" ? "" : []);
var pos = 0; var pos = 0;
var chunkSize = 10*1024; var chunkSize = 10*1024;
function readChunk () { function readChunk () {
file.read(chunkSize, pos, function (status, chunk) { file.read(chunkSize, pos, function (chunk) {
if (chunk) { if (chunk) {
if (chunk.constructor == String) if (chunk.constructor == String)
content += chunk; content += chunk;
else else
@ -40,22 +33,11 @@ node.fs.cat = function (path, encoding, callback) {
}); });
} }
file.open(path, "r", function (status) { file.open(path, "r", function () {
if (status == 0)
readChunk(); readChunk();
else
callback (status);
}); });
} }
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) { node.fs.File.prototype.open = function (path, mode, callback) {
this._addAction("open", [path, mode], callback); this._addAction("open", [path, mode], callback);
}; };
@ -64,12 +46,20 @@ node.fs.File.prototype.close = function (callback) {
this._addAction("close", [], 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) { node.fs.File.prototype.write = function (buf, pos, callback) {
this._addAction("write", [buf, pos], callback); this._addAction("write", [buf, pos], callback);
}; };
node.fs.File.prototype.read = function (length, pos, callback) { node.fs.File.prototype.print = function (data, callback) {
this._addAction("read", [length, pos], 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. // Some explanation of the File binding.
@ -84,38 +74,65 @@ node.fs.File.prototype.read = function (length, pos, callback) {
// the member _actionQueue = [] // the member _actionQueue = []
// //
// Any of the methods called on a file are put into this queue. When they // 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 // method _pollActions each time it becomes idle. If there is no action
// currently being executed then _pollActions will not be called. Thus when // currently being executed then _pollActions will not be called. When
// actions are added to an empty _actionQueue, they should be immediately // actions are added to an empty _actionQueue, they will be immediately
// executed. // 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 // element of _actionQueue in order to get a handle on the callback
// function. Only after that completion callback has been made can the // function. Only after that completion callback has been made can the
// action be shifted out of the queue. // action be shifted out of the queue.
// //
// See File::CallTopCallback() in file.cc to see the other side of the // See File::CallTopCallback() in file.cc for the other side of the binding.
// binding.
node.fs._addAction = node.fs.File.prototype._addAction = function (method, args, callback) {
this._actionQueue.push({ method: method node.fs.File.prototype._addAction = function (method, args, callback) {
// This adds a method to the queue.
var action = { method: method
, callback: callback , callback: callback
, args: args , args: args
}); };
this._actionQueue.push(action);
// If the queue was empty, immediately call the method.
if (this._actionQueue.length == 1) this._act(); if (this._actionQueue.length == 1) this._act();
} };
node.fs._act = node.fs.File.prototype._act = function () { node.fs.File.prototype._act = function () {
// peek at the head of the queue
var action = this._actionQueue[0]; var action = this._actionQueue[0];
if (action) if (action) {
// TODO FIXME what if the action throws an error? // 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); this["_ffi_" + action.method].apply(this, action.args);
}
}; };
// called from C++ after each action finishes // called from C++ after each action finishes
// (i.e. when it returns from the thread pool) // (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._actionQueue.shift();
this._act(); this._act();
}; };

7
test/test-file-open.js

@ -7,8 +7,11 @@ function onLoad () {
var x = node.path.join(fixtures, "x.txt"); var x = node.path.join(fixtures, "x.txt");
file = new node.fs.File; file = new node.fs.File;
file.open(x, "r", function (status) { file.onError = function (method, errno, msg) {
assertTrue(status == 0); assertTrue(false);
};
file.open(x, "r", function () {
assert_count += 1; assert_count += 1;
file.close(); file.close();
}); });

124
website/node.html

@ -80,11 +80,11 @@ a:hover { text-decoration: underline; }
<ol> <ol>
<li><a href="#benchmarks">Benchmarks</a></li> <li><a href="#benchmarks">Benchmarks</a></li>
<li><a href="#download">Download</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> <li><a href="#api">API</a>
<ol> <ol>
<li><a href="#timers">Timers</a> <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> <li><a href="#tcp">TCP</a>
<ol> <ol>
<li><a href="#tcp_server">Server</a> <li><a href="#tcp_server">Server</a>
@ -166,12 +166,15 @@ always have a capital first letter.
<dl> <dl>
<dt><code class="sh_javascript">puts(string, callback)</code></dt> <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 <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 notify the user when the operation has completed. Everything in node is
asynchronous; <code>puts()</code> is no exception. This might seem ridiculous 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, but, if for example, one is piping <code>stdout</code> into an NFS file,
<code>printf()</code> will block. <code>printf()</code> will block from network latency.
There is an internal queue for <code>puts()</code> output, so you can be assured that 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. output will be displayed in the order it was called.
</dd> </dd>
@ -204,45 +207,80 @@ always have a capital first letter.
<dd> Stops a interval from triggering. </dd> <dd> Stops a interval from triggering. </dd>
</dl> </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 <p>Because there are not non-blocking ways to do it, asynchronous file I/O is
non-blocking ways to do it. To get around this, Node uses <a tricky. Node handles file I/O by employing <a
href="http://software.schmorp.de/pkg/libeio.html">an internal thread pool</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>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 that multiple commands
can be issued at once without worry that they will be executed out-of-order.
Thus the following is safe:
<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"> <pre class="sh_javascript">
var file = new node.File(); var file = new node.fs.File();
file.open("/tmp/blah", "w+"); file.open("/tmp/blah", "w+");
file.write("hello"); file.write("hello");
file.write("world"); file.write("world");
file.close();</pre> 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 <p>
<code>unlink</code>). It's important to understand that all of these request queues are It's important to understand that the request queues are local to a single file.
distinct. If, for example, you do If one does
<pre class="sh_javascript">fileA.write("hello"); <pre class="sh_javascript">fileA.write("hello");
fileB.write("world");</pre> fileB.write("world");</pre>
it could be that it could be that <code>fileB</code> gets written to before <code>fileA</code>
first <code>fileB</code> gets written to and then <code>fileA</code> gets written to. is written to.
So if a certain operation order is needed involving multiple files, use the If a certain operation order is needed involving multiple files, use the
completion callbacks: completion callbacks:
<pre class="sh_javascript">fileA.write("hello", function () { <pre class="sh_javascript">fileA.write("hello", function () {
fileB.write("world"); fileB.write("world");
});</pre> });</pre>
<dl> <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>
</dd> </dd>
</dl> </dl>
@ -250,6 +288,10 @@ completion callbacks:
<h3 id="tcp"><code>node.tcp</code></h3> <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> <h3 id="http"><code>node.http</code></h3>
<p> Node provides a web server and client interface. The interface is rather <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> <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 <p> An HTTP client is constructed with a server address as its argument, the
the user issues one or more requests. Depending on the server connected to, returned handle is then used to issue one or more requests. Depending on the
the client might pipeline the requests or reestablish the connection after each server connected to, the client might pipeline the requests or reestablish the
connection. <i>Currently the client does not pipeline requests.</i> connection after each connection.
<i>Currently the implementation does not pipeline requests.</i>
<p> Example of connecting to <code>google.com</code> <p> Example of connecting to <code>google.com</code>
<pre class="sh_javascript"> <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.post(path, request_headers);</code></dt>
<dt><code class="sh_javascript">client.del(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> <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> is optional.
<code>request_headers</code> should be an array of 2-element arrays. <code>request_headers</code> should be an array of 2-element arrays.
Additional request headers might be added internally by Node. 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 <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 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 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 a chance for the user to stream a body to the server with <code
<code>req.sendBody</code>. <code>GET</code> and <code>HEAD</code> requests class="sh_javascript">req.sendBody()</code>.)
normally are without bodies but HTTP does not forbid it, so neither do we.)
<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> </dl>
<h4 id="http_client_request"><code class="sh_javascript">node.http.ClientRequest</code></h4> <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 <code>node.http.Client</code>. It represents an <i>in-progress</i> request
whose header has already been sent. whose header has already been sent.
@ -500,7 +548,7 @@ read.
<dl> <dl>
<dt><code class="sh_javascript">res.statusCode</code></dt> <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> <dt><code class="sh_javascript">res.httpVersion</code></dt>
<dd>The HTTP version of the connected-to server. Probably either <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> <dt><code class="sh_javascript">res.onBody</code></dt>
<dd>Callback. Should be set by the user to be informed of when a piece <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 A chunk of the body is given as the single argument. The transfer-encoding
has been removed. has been removed.

Loading…
Cancel
Save