Browse Source

Add process.watchFile() process.unwatchFile()

This is an interface to libev's ev_stat watcher.
v0.7.4-release
Ryan Dahl 15 years ago
parent
commit
8d2f9e83a4
  1. 7
      doc/api.txt
  2. 2
      src/node.cc
  3. 26
      src/node.js
  4. 95
      src/node_stat.cc
  5. 46
      src/node_stat.h
  6. 25
      test/mjsunit/test-stat-handler.js
  7. 1
      wscript

7
doc/api.txt

@ -124,6 +124,13 @@ Send a signal to a process. +pid+ is the process id and +signal+ is the
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.

2
src/node.cc

@ -16,6 +16,7 @@
#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>
@ -695,6 +696,7 @@ static Local<Object> Load(int argc, char *argv[]) {
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

26
src/node.js

@ -332,6 +332,32 @@ process.addListener("newListener", function (event) {
});
// 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

95
src/node_stat.cc

@ -0,0 +1,95 @@
// 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

46
src/node_stat.h

@ -0,0 +1,46 @@
// 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_

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

@ -0,0 +1,25 @@
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);
});

1
wscript

@ -321,6 +321,7 @@ def build(bld):
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
"""

Loading…
Cancel
Save