This is an interface to libev's ev_stat watcher.
signal to send; for example, "SIGINT" or "SIGUSR1". See kill(2) for more
information.
++process.watchFile(filename, listener)+::
+Watch for changes on +filename+. The callback +listener+ will be called each
+time the file changes.
+
++process.unwatchFile(filename)+::
+Stop watching for changes on +filename+.
+
+process.compile(source, scriptOrigin)+::
Just like +eval()+ except that you can specify a +scriptOrigin+ for better
error reporting.
#include <node_file.h>
#include <node_http.h>
#include <node_signal_handler.h>
+#include <node_stat.h>
#include <node_timer.h>
#include <node_child_process.h>
#include <node_constants.h>
Stdio::Initialize(process); // stdio.cc
Timer::Initialize(process); // timer.cc
SignalHandler::Initialize(process); // signal_handler.cc
+ Stat::Initialize(process); // stat.cc
ChildProcess::Initialize(process); // child_process.cc
DefineConstants(process); // constants.cc
// Create node.dns
});
+// Stat Change Watchers
+
+var statWatchers = {};
+
+process.watchFile = function (filename, listener) {
+ var stat;
+ if (filename in statWatchers) {
+ stat = statWatchers[filename];
+ } else {
+ statWatchers[filename] = new process.Stat();
+ stat = statWatchers[filename];
+ stat.start(filename, true);
+ }
+ stat.addListener("change", listener);
+ return stat;
+};
+
+process.unwatchFile = function (filename) {
+ if (filename in statWatchers) {
+ stat = statWatchers[filename];
+ stat.stop();
+ statWatchers[filename] = undefined;
+ }
+};
+
+
// Timers
--- /dev/null
+// Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
+#include <node_stat.h>
+
+#include <assert.h>
+#include <string.h>
+#include <stdlib.h>
+
+namespace node {
+
+using namespace v8;
+
+Persistent<FunctionTemplate> Stat::constructor_template;
+
+void Stat::Initialize(Handle<Object> target) {
+ HandleScope scope;
+
+ Local<FunctionTemplate> t = FunctionTemplate::New(Stat::New);
+ constructor_template = Persistent<FunctionTemplate>::New(t);
+ constructor_template->Inherit(EventEmitter::constructor_template);
+ constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
+ constructor_template->SetClassName(String::NewSymbol("Stat"));
+
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "start", Stat::Start);
+ NODE_SET_PROTOTYPE_METHOD(constructor_template, "stop", Stat::Stop);
+
+ target->Set(String::NewSymbol("Stat"), constructor_template->GetFunction());
+}
+
+
+void Stat::Callback(EV_P_ ev_stat *watcher, int revents) {
+ assert(revents == EV_STAT);
+ Stat *handler = static_cast<Stat*>(watcher->data);
+ assert(watcher == &handler->watcher_);
+ HandleScope scope;
+ handler->Emit("change", 0, NULL);
+}
+
+
+Handle<Value> Stat::New(const Arguments& args) {
+ HandleScope scope;
+ Stat *s = new Stat();
+ s->Wrap(args.Holder());
+ return args.This();
+}
+
+
+Handle<Value> Stat::Start(const Arguments& args) {
+ HandleScope scope;
+
+ if (args.Length() < 1 || !args[0]->IsString()) {
+ return ThrowException(Exception::TypeError(String::New("Bad arguments")));
+ }
+
+ Stat *handler = ObjectWrap::Unwrap<Stat>(args.Holder());
+ String::Utf8Value path(args[0]->ToString());
+
+ assert(handler->path_ == NULL);
+ handler->path_ = strdup(*path);
+
+ ev_stat_set(&handler->watcher_, handler->path_, 0.);
+ ev_stat_start(EV_DEFAULT_UC_ &handler->watcher_);
+
+ handler->persistent_ = args[1]->IsTrue();
+
+ if (!handler->persistent_) {
+ ev_unref(EV_DEFAULT_UC);
+ }
+
+ handler->Attach();
+
+ return Undefined();
+}
+
+
+Handle<Value> Stat::Stop(const Arguments& args) {
+ HandleScope scope;
+ Stat *handler = ObjectWrap::Unwrap<Stat>(args.Holder());
+ handler->Emit("stop", 0, NULL);
+ handler->Stop();
+ return Undefined();
+}
+
+
+void Stat::Stop () {
+ if (watcher_.active) {
+ if (!persistent_) ev_ref(EV_DEFAULT_UC);
+ ev_stat_stop(EV_DEFAULT_UC_ &watcher_);
+ free(path_);
+ path_ = NULL;
+ Detach();
+ }
+}
+
+
+} // namespace node
--- /dev/null
+// Copyright 2009 Ryan Dahl <ry@tinyclouds.org>
+#ifndef NODE_STAT_H_
+#define NODE_STAT_H_
+
+#include <node.h>
+#include <node_events.h>
+#include <ev.h>
+
+namespace node {
+
+class Stat : EventEmitter {
+ public:
+ static void Initialize(v8::Handle<v8::Object> target);
+
+ protected:
+ static v8::Persistent<v8::FunctionTemplate> constructor_template;
+
+ Stat() : EventEmitter() {
+ persistent_ = false;
+ path_ = NULL;
+ ev_init(&watcher_, Stat::Callback);
+ watcher_.data = this;
+ }
+
+ ~Stat() {
+ Stop();
+ assert(path_ == NULL);
+ }
+
+ static v8::Handle<v8::Value> New(const v8::Arguments& args);
+ static v8::Handle<v8::Value> Start(const v8::Arguments& args);
+ static v8::Handle<v8::Value> Stop(const v8::Arguments& args);
+
+ private:
+ static void Callback(EV_P_ ev_stat *watcher, int revents);
+
+ void Stop();
+
+ ev_stat watcher_;
+ bool persistent_;
+ char *path_;
+};
+
+} // namespace node
+#endif // NODE_STAT_H_
+
--- /dev/null
+process.mixin(require("./common"));
+
+var posix = require("posix");
+var path = require("path");
+
+var f = path.join(fixturesDir, "x.txt");
+var f2 = path.join(fixturesDir, "x2.txt");
+
+var changes = 0;
+process.watchFile(f, function () {
+ puts(f + " change");
+ changes++;
+});
+
+
+setTimeout(function () {
+ posix.rename(f, f2).wait();
+ posix.rename(f2, f).wait();
+ process.unwatchFile(f);
+}, 10);
+
+
+process.addListener("exit", function () {
+ assertTrue(changes > 0);
+});
src/node_http.cc
src/node_net.cc
src/node_signal_handler.cc
+ src/node_stat.cc
src/node_stdio.cc
src/node_timer.cc
"""