Browse Source

Stat::Callback has 2 arguments for callback: current stat info and previous stat info

http://groups.google.com/group/nodejs/msg/f8e51a8e0c74bd85
v0.7.4-release
choonkeat 15 years ago
committed by Ryan Dahl
parent
commit
44d5f212fe
  1. 12
      doc/api.txt
  2. 18
      lib/posix.js
  3. 72
      src/node.cc
  4. 4
      src/node.h
  5. 69
      src/node_file.cc
  6. 5
      src/node_stat.cc
  7. 3
      test/mjsunit/test-stat-handler.js

12
doc/api.txt

@ -137,6 +137,18 @@ The second argument is optional. The +options+ if provided should be an
object containing two members a boolean, +persistent+, and +interval+, a object containing two members a boolean, +persistent+, and +interval+, a
polling value in milliseconds. The default is +{persistent: true, interval: polling value in milliseconds. The default is +{persistent: true, interval:
0}+. 0}+.
+
The +listener+ gets two arguments the current stat object and the previous
stat object:
+
-------------------------
process.watchFile(f, function (curr, prev) {
sys.puts("the current mtime is: " + curr.mtime);
sys.puts("the previous mtime was: " + prev.mtime);
});
-------------------------
+
These stat objects are instances of +posix.Stat+.
+process.unwatchFile(filename)+:: +process.unwatchFile(filename)+::
Stop watching for changes on +filename+. Stop watching for changes on +filename+.

18
lib/posix.js

@ -1,35 +1,37 @@
process.fs.Stats.prototype._checkModeProperty = function (property) { process.Stats.prototype._checkModeProperty = function (property) {
return ((this.mode & property) === property); return ((this.mode & property) === property);
}; };
process.fs.Stats.prototype.isDirectory = function () { process.Stats.prototype.isDirectory = function () {
return this._checkModeProperty(process.S_IFDIR); return this._checkModeProperty(process.S_IFDIR);
}; };
process.fs.Stats.prototype.isFile = function () { process.Stats.prototype.isFile = function () {
return this._checkModeProperty(process.S_IFREG); return this._checkModeProperty(process.S_IFREG);
}; };
process.fs.Stats.prototype.isBlockDevice = function () { process.Stats.prototype.isBlockDevice = function () {
return this._checkModeProperty(process.S_IFBLK); return this._checkModeProperty(process.S_IFBLK);
}; };
process.fs.Stats.prototype.isCharacterDevice = function () { process.Stats.prototype.isCharacterDevice = function () {
return this._checkModeProperty(process.S_IFCHR); return this._checkModeProperty(process.S_IFCHR);
}; };
process.fs.Stats.prototype.isSymbolicLink = function () { process.Stats.prototype.isSymbolicLink = function () {
return this._checkModeProperty(process.S_IFLNK); return this._checkModeProperty(process.S_IFLNK);
}; };
process.fs.Stats.prototype.isFIFO = function () { process.Stats.prototype.isFIFO = function () {
return this._checkModeProperty(process.S_IFIFO); return this._checkModeProperty(process.S_IFIFO);
}; };
process.fs.Stats.prototype.isSocket = function () { process.Stats.prototype.isSocket = function () {
return this._checkModeProperty(process.S_IFSOCK); return this._checkModeProperty(process.S_IFSOCK);
}; };
exports.Stats = process.Stats;
for (var key in process.fs) { for (var key in process.fs) {
if (process.fs.hasOwnProperty(key)) exports[key] = process.fs[key]; if (process.fs.hasOwnProperty(key)) exports[key] = process.fs[key];
} }

72
src/node.cc

@ -160,6 +160,71 @@ ssize_t DecodeWrite(char *buf, size_t buflen,
return buflen; return buflen;
} }
#define DEV_SYMBOL String::NewSymbol("dev")
#define INO_SYMBOL String::NewSymbol("ino")
#define MODE_SYMBOL String::NewSymbol("mode")
#define NLINK_SYMBOL String::NewSymbol("nlink")
#define UID_SYMBOL String::NewSymbol("uid")
#define GID_SYMBOL String::NewSymbol("gid")
#define RDEV_SYMBOL String::NewSymbol("rdev")
#define SIZE_SYMBOL String::NewSymbol("size")
#define BLKSIZE_SYMBOL String::NewSymbol("blksize")
#define BLOCKS_SYMBOL String::NewSymbol("blocks")
#define ATIME_SYMBOL String::NewSymbol("atime")
#define MTIME_SYMBOL String::NewSymbol("mtime")
#define CTIME_SYMBOL String::NewSymbol("ctime")
static Persistent<FunctionTemplate> stats_constructor_template;
Local<Object> BuildStatsObject(struct stat * s) {
HandleScope scope;
Local<Object> stats =
stats_constructor_template->GetFunction()->NewInstance();
/* ID of device containing file */
stats->Set(DEV_SYMBOL, Integer::New(s->st_dev));
/* inode number */
stats->Set(INO_SYMBOL, Integer::New(s->st_ino));
/* protection */
stats->Set(MODE_SYMBOL, Integer::New(s->st_mode));
/* number of hard links */
stats->Set(NLINK_SYMBOL, Integer::New(s->st_nlink));
/* user ID of owner */
stats->Set(UID_SYMBOL, Integer::New(s->st_uid));
/* group ID of owner */
stats->Set(GID_SYMBOL, Integer::New(s->st_gid));
/* device ID (if special file) */
stats->Set(RDEV_SYMBOL, Integer::New(s->st_rdev));
/* total size, in bytes */
stats->Set(SIZE_SYMBOL, Integer::New(s->st_size));
/* blocksize for filesystem I/O */
stats->Set(BLKSIZE_SYMBOL, Integer::New(s->st_blksize));
/* number of blocks allocated */
stats->Set(BLOCKS_SYMBOL, Integer::New(s->st_blocks));
/* time of last access */
stats->Set(ATIME_SYMBOL, NODE_UNIXTIME_V8(s->st_atime));
/* time of last modification */
stats->Set(MTIME_SYMBOL, NODE_UNIXTIME_V8(s->st_mtime));
/* time of last status change */
stats->Set(CTIME_SYMBOL, NODE_UNIXTIME_V8(s->st_ctime));
return scope.Close(stats);
}
// Extracts a C str from a V8 Utf8Value. // Extracts a C str from a V8 Utf8Value.
const char* ToCString(const v8::String::Utf8Value& value) { const char* ToCString(const v8::String::Utf8Value& value) {
return *value ? *value : "<str conversion failed>"; return *value ? *value : "<str conversion failed>";
@ -726,6 +791,13 @@ static Local<Object> Load(int argc, char *argv[]) {
process->Set(String::NewSymbol("EventEmitter"), process->Set(String::NewSymbol("EventEmitter"),
EventEmitter::constructor_template->GetFunction()); EventEmitter::constructor_template->GetFunction());
// Initialize the stats object
Local<FunctionTemplate> stat_templ = FunctionTemplate::New();
stats_constructor_template = Persistent<FunctionTemplate>::New(stat_templ);
process->Set(String::NewSymbol("Stats"),
stats_constructor_template->GetFunction());
// Initialize the C++ modules..................filename of module // Initialize the C++ modules..................filename of module
Promise::Initialize(process); // events.cc Promise::Initialize(process); // events.cc
Stdio::Initialize(process); // stdio.cc Stdio::Initialize(process); // stdio.cc

4
src/node.h

@ -6,6 +6,8 @@
#include <eio.h> #include <eio.h>
#include <v8.h> #include <v8.h>
#include <evcom.h> #include <evcom.h>
#include <sys/types.h> /* struct stat */
#include <sys/stat.h>
#include <node_object_wrap.h> #include <node_object_wrap.h>
@ -51,6 +53,8 @@ ssize_t DecodeWrite(char *buf,
v8::Handle<v8::Value>, v8::Handle<v8::Value>,
enum encoding encoding = BINARY); enum encoding encoding = BINARY);
v8::Local<v8::Object> BuildStatsObject(struct stat * s);
} // namespace node } // namespace node
#endif // SRC_NODE_H_ #endif // SRC_NODE_H_

69
src/node_file.cc

@ -13,20 +13,7 @@ namespace node {
using namespace v8; using namespace v8;
#define DEV_SYMBOL String::NewSymbol("dev") #define BAD_ARGUMENTS Exception::TypeError(String::New("Bad argument"))
#define INO_SYMBOL String::NewSymbol("ino")
#define MODE_SYMBOL String::NewSymbol("mode")
#define NLINK_SYMBOL String::NewSymbol("nlink")
#define UID_SYMBOL String::NewSymbol("uid")
#define GID_SYMBOL String::NewSymbol("gid")
#define RDEV_SYMBOL String::NewSymbol("rdev")
#define SIZE_SYMBOL String::NewSymbol("size")
#define BLKSIZE_SYMBOL String::NewSymbol("blksize")
#define BLOCKS_SYMBOL String::NewSymbol("blocks")
#define ATIME_SYMBOL String::NewSymbol("atime")
#define MTIME_SYMBOL String::NewSymbol("mtime")
#define CTIME_SYMBOL String::NewSymbol("ctime")
#define BAD_ARGUMENTS Exception::TypeError(String::New("Bad argument"))
void EIOPromise::Attach(void) { void EIOPromise::Attach(void) {
ev_ref(EV_DEFAULT_UC); ev_ref(EV_DEFAULT_UC);
@ -58,55 +45,6 @@ EIOPromise* EIOPromise::Create() {
return ObjectWrap::Unwrap<EIOPromise>(handle); return ObjectWrap::Unwrap<EIOPromise>(handle);
} }
static Persistent<FunctionTemplate> stats_constructor_template;
static Local<Object> BuildStatsObject(struct stat * s) {
HandleScope scope;
Local<Object> stats =
stats_constructor_template->GetFunction()->NewInstance();
/* ID of device containing file */
stats->Set(DEV_SYMBOL, Integer::New(s->st_dev));
/* inode number */
stats->Set(INO_SYMBOL, Integer::New(s->st_ino));
/* protection */
stats->Set(MODE_SYMBOL, Integer::New(s->st_mode));
/* number of hard links */
stats->Set(NLINK_SYMBOL, Integer::New(s->st_nlink));
/* user ID of owner */
stats->Set(UID_SYMBOL, Integer::New(s->st_uid));
/* group ID of owner */
stats->Set(GID_SYMBOL, Integer::New(s->st_gid));
/* device ID (if special file) */
stats->Set(RDEV_SYMBOL, Integer::New(s->st_rdev));
/* total size, in bytes */
stats->Set(SIZE_SYMBOL, Integer::New(s->st_size));
/* blocksize for filesystem I/O */
stats->Set(BLKSIZE_SYMBOL, Integer::New(s->st_blksize));
/* number of blocks allocated */
stats->Set(BLOCKS_SYMBOL, Integer::New(s->st_blocks));
/* time of last access */
stats->Set(ATIME_SYMBOL, NODE_UNIXTIME_V8(s->st_atime));
/* time of last modification */
stats->Set(MTIME_SYMBOL, NODE_UNIXTIME_V8(s->st_mtime));
/* time of last status change */
stats->Set(CTIME_SYMBOL, NODE_UNIXTIME_V8(s->st_ctime));
return scope.Close(stats);
}
int EIOPromise::After(eio_req *req) { int EIOPromise::After(eio_req *req) {
HandleScope scope; HandleScope scope;
@ -388,11 +326,6 @@ void File::Initialize(Handle<Object> target) {
NODE_SET_METHOD(target, "unlink", Unlink); NODE_SET_METHOD(target, "unlink", Unlink);
NODE_SET_METHOD(target, "write", Write); NODE_SET_METHOD(target, "write", Write);
Local<FunctionTemplate> t = FunctionTemplate::New();
stats_constructor_template = Persistent<FunctionTemplate>::New(t);
target->Set(String::NewSymbol("Stats"),
stats_constructor_template->GetFunction());
Local<FunctionTemplate> t2 = FunctionTemplate::New(EIOPromise::New); Local<FunctionTemplate> t2 = FunctionTemplate::New(EIOPromise::New);
EIOPromise::constructor_template = Persistent<FunctionTemplate>::New(t2); EIOPromise::constructor_template = Persistent<FunctionTemplate>::New(t2);

5
src/node_stat.cc

@ -32,7 +32,10 @@ void Stat::Callback(EV_P_ ev_stat *watcher, int revents) {
Stat *handler = static_cast<Stat*>(watcher->data); Stat *handler = static_cast<Stat*>(watcher->data);
assert(watcher == &handler->watcher_); assert(watcher == &handler->watcher_);
HandleScope scope; HandleScope scope;
handler->Emit("change", 0, NULL); Handle<Value> argv[2];
argv[0] = Handle<Value>(BuildStatsObject(&watcher->attr));
argv[1] = Handle<Value>(BuildStatsObject(&watcher->prev));
handler->Emit("change", 2, argv);
} }

3
test/mjsunit/test-stat-handler.js

@ -8,9 +8,10 @@ var f2 = path.join(fixturesDir, "x2.txt");
puts("watching for changes of " + f); puts("watching for changes of " + f);
var changes = 0; var changes = 0;
process.watchFile(f, function () { process.watchFile(f, function (curr, prev) {
puts(f + " change"); puts(f + " change");
changes++; changes++;
assertTrue(curr.mtime != prev.mtime);
process.unwatchFile(f); process.unwatchFile(f);
}); });

Loading…
Cancel
Save