mirror of https://github.com/nodejs/node.git
Add process.watchFile() process.unwatchFile()
This is an interface to libev's ev_stat watcher.pull/22966/head
parent
55f9fdd6b5
commit
8d2f9e83a4
|
@ -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.
|
||||
|
|
|
@ -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
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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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_
|
||||
|
|
@ -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);
|
||||
});
|
Loading…
Reference in New Issue