Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

first version published

  • Loading branch information...
commit 9faa73019dc985c51949cd477073fbdcb9852a8c 0 parents
Yarco authored
58 README.md
@@ -0,0 +1,58 @@
+Node Watchd
+============
+This is a nodejs module which contains a watchd server and a client.
+
+What's this used for
+--------------------
+Sometimes you need to watch some files change (normally, as a developer). For example, you have three javascripts, you would like to use `uglifyjs` to compile them into one. Certainly you could do it by hand:
+
+ uglifyjs *.js > my.js
+
+Then you include my.js in your html file.
+
+ <script src="my.js"></script>
+
+It is fine. But everytime you change the original file, you need to redo this work. That is really boring.
+
+There is also similar utilities, for example, you could use `compass` to watch .scss files.
+But what about a common server for doing this???
+
+So that's the idea!!!
+
+How to install
+--------------
+Cause it is a nodejs module, so you need to install nodejs first. And then install it by npm just like a normal nodejs module.
+
+ npm install node-watchd
+
+How to use
+-----------
+* start the server
+
+ $ watchd
+
+* use command line tool to add to the watch list, use -h to view help
+
+ $ watch -h
+
+Examples
+--------
+
+ yarco@me node-watchd$ ./bin/watch -l
+ Key File Action
+ yarco@me node-watchd$ ./bin/watch tmp.js tmp.txt -a 'cat tmp.js tmp.txt > all.txt'
+ Key File Action
+ 0 /Users/yarco/Sites/js/node-watchd/tmp.js cat tmp.js tmp.txt > all.txt
+ 1 /Users/yarco/Sites/js/node-watchd/tmp.txt cat tmp.js tmp.txt > all.txt
+ yarco@me node-watchd$ ./bin/watch -r 1
+ Key File Action
+ 0 /Users/yarco/Sites/js/node-watchd/tmp.js cat tmp.js tmp.txt > all.txt
+
+Sugguestion
+-----------
+You could contact <yarco.wang@gmail.com> for this extension.
+Or for programming related things, whatever.
+
+This guy currently works in Wiredcraft.com. So you could also get him by <yarco@wiredcraft.com>
+
+All rights reserved by human.
36 bin/watch
@@ -0,0 +1,36 @@
+#!/usr/bin/env node
+
+var path = require('path')
+ , program = require('commander')
+ , watch = require('../lib/watch');
+
+// load config
+var config = require(path.join(__dirname, '..', 'etc', path.basename(__filename) + '.json'));
+
+// command
+program.version('0.0.1')
+ .usage('[options] files...')
+ .option('-a, --add <action>', 'trigger action when files are changed. arguments files required')
+ .option('-l, --list', 'list current watchs')
+ .option('-r, --remove <key>', 'remove watch');
+
+program.on('--help', function() {
+ console.log(' Examples:\n' +
+ ' $ watch abc.js efg.js -a "cat abc.js efg.js > all.js"\n' +
+ '\n');
+});
+program.parse(process.argv);
+
+watch.setConfig(config);
+// actions
+if (program.list) {
+ watch.list();
+} else if (program.remove) {
+ watch.remove(program.remove);
+} else if (program.add) {
+ watch.add(program.args, program.add);
+} else {
+ console.log(program.helpInformation());
+ program.emit('--help');
+}
+
14 bin/watchd
@@ -0,0 +1,14 @@
+#!/usr/bin/env node
+
+var path = require('path')
+ , fs = require('fs')
+ , watchd = require('../lib/watchd');
+
+// load config
+var config = require(path.join(__dirname, '..', 'etc', path.basename(__filename) + '.json'));
+
+// start server
+watchd.start(config, function() {
+ console.log('Watchd listen on ' + config.host + ':' + config.port);
+});
+
1  etc/watch.json
6 etc/watchd.json
@@ -0,0 +1,6 @@
+{
+ "host": "localhost",
+ "port": 31415,
+ "user": "yarco",
+ "pass": "1234"
+}
50 lib/child.js
@@ -0,0 +1,50 @@
+/**
+ * @file child.js
+ * child process
+ *
+ * @author yarco <yarco.wang@gmail.com>
+ * @date 2012/11/15
+ */
+/* vim: set tabstop=2 shiftwidth=2 ai si noet: */
+
+var debug = require('debug')('child')
+ , exec = require('child_process').exec
+ , fs = require('fs');
+
+var fw;
+
+process.on('message', function(msg) {
+ debug('msg = %j', msg);
+
+ switch(msg.cmd) {
+ case 'add':
+ watch(msg);
+ break;
+ case 'remove':
+ if (fw) fw.close();
+ console.log('process %d quit', process.pid);
+ process.exit(0);
+ break;
+ default:
+ ;
+ }
+});
+
+function watch(msg)
+{
+ fw = fs.watch(msg.file);
+
+ fw.on('change', function(event) {
+ if (event === 'change') {
+ // execute action
+ exec(msg.action, {cwd: process.cwd()}, function(err, stdout, stderr) {
+ if (err !== null) {
+ console.error(err);
+ }
+ });
+ } else if (event === 'rename') {
+ fw.close();
+ watch(msg);
+ }
+ });
+}
133 lib/watch.js
@@ -0,0 +1,133 @@
+/**
+ * @file watch.js
+ * watchd client
+ *
+ * @author yarco <yarco.wang@gmail.com>
+ * @date 2012/11/13
+ */
+/* vim: set tabstop=2 shiftwidth=2 ai si noet: */
+
+var net = require('net')
+ , path = require('path')
+ , fs = require('fs')
+ , debug = require('debug')('watch');
+
+module.exports = new Watch;
+
+function Watch () {}
+
+(function() {
+ var client = new net.Socket;
+ var opts;
+
+ /** \brief set config
+ */
+ this.setConfig = function(options) {
+ opts = options;
+ };
+
+ /** \brief listing watched stuff {{{
+ */
+ this.list = function() {
+ var self = this;
+ var t = '';
+
+ client.connect(opts.port || 31415, opts.host || 'localhost', function() {
+ var cmd = {user: opts.user, pass: opts.pass, cmd: 'list'};
+ client.write(JSON.stringify(cmd));
+ });
+
+ client.on('data', function(data) {
+ t += data;
+ });
+
+ client.on('end', function() {
+ debug('list = %s', t);
+
+ self.parse(t);
+ client.destroy();
+ });
+ };
+ /*}}}*/
+
+ /** \brief add watch {{{
+ */
+ this.add = function(files, action) {
+ var self = this;
+ var t = '';
+
+ var l = [];
+ files.forEach(function(file) {
+ l.push(fs.realpathSync(path.normalize(file)));
+ });
+
+ client.connect(opts.port || 31415, opts.host || 'localhost', function() {
+ var cmd = {user: opts.user, pass: opts.pass, cmd: 'add', msg: {files: l, action: action, cwd: process.cwd()}};
+ debug('add cmd = %j', cmd);
+ client.write(JSON.stringify(cmd));
+ });
+
+ client.on('data', function(data) {
+ t += data;
+ });
+
+ client.on('end', function() {
+ debug('add = %s', t);
+
+ self.parse(t);
+ client.destroy();
+ });
+ }
+ /*}}}*/
+
+ /** \brief remove by key {{{*/
+ this.remove = function(key) {
+ var self = this;
+ var t = '';
+
+ client.connect(opts.port || 31415, opts.host || 'localhost', function() {
+ var cmd = {user: opts.user, pass: opts.pass, cmd: 'remove', msg: key};
+ debug('remove cmd = %j', cmd);
+ client.write(JSON.stringify(cmd));
+ });
+
+ client.on('data', function(data) {
+ t += data;
+ });
+
+ client.on('end', function() {
+ debug('remove = %s', t);
+
+ self.parse(t);
+ client.destroy();
+ });
+ }
+ /*}}}*/
+
+ /** \brief parse result {{{
+ */
+ this.parse = function(data) {
+ var ret = JSON.parse(data);
+
+ if (!ret.res) { // failed
+ console.log(ret.msg);
+ return;
+ }
+
+ this.formatList(ret.data);
+ };
+ /*}}}*/
+
+ /** \brief format list {{{
+ */
+ this.formatList = function(data) {
+ debug('data = %j', data);
+ console.log('%s\t%s\t\t\t\t\t\t%s', 'Key', 'File', 'Action');
+ data.forEach(function(item) {
+ console.log('%d\t%s\t%s', item.key, item.file, item.action);
+ });
+ }
+ /*}}}*/
+
+}).call(Watch.prototype);
+
118 lib/watchd.js
@@ -0,0 +1,118 @@
+/**
+ * @file watchd.js
+ * watchd server
+ *
+ * @author yarco <yarco.wang@gmail.com>
+ * @date 2012/11/13
+ */
+/* vim: set tabstop=2 shiftwidth=2 ai si noet: */
+
+var net = require('net')
+ , fs = require('fs')
+ , path = require('path')
+ , cp = require('child_process')
+ , debug = require('debug')('watchd');
+
+module.exports = new Watchd;
+
+function Watchd() {}
+
+(function() {
+ var server, opts;
+ var data = [];
+
+ /** \brief start server {{{
+ */
+ this.start = function(options, callback) {
+ debug('start options = %j', options);
+
+ opts = options;
+ server = net.createServer();
+ server.listen(options.port || 314159, options.host || '127.0.0.1', callback);
+ server.on('connection', this.parse());
+ };
+ /*}}}*/
+
+ /** \brief formatData {{{
+ */
+ this.formatData = function() {
+ var ret = [];
+ data.forEach(function(item, key) {
+ ret.push({key: key, file: item.file, action: item.action});
+ });
+
+ debug('ret = %j', ret);
+ return ret;
+ }
+ /*}}}*/
+
+ /** \brief parse command {{{
+ */
+ this.parse = function() {
+ var self = this;
+ return function(sock) {
+ sock.on('data', function(data) {
+ debug('get data = %s', data);
+ var msg = JSON.parse(data);
+ var ret = {cmd: msg.cmd, res: false, msg: '', data: '', code: 0};
+
+ if (msg.user !== opts.user || msg.pass !== opts.pass) {
+ ret.msg = 'auth failed';
+ ret.code = 403;
+ } else {
+ switch(msg.cmd) {
+ case 'add':
+ self.addWatch(msg.msg.files, msg.msg.action, msg.msg.cwd);
+ ret.res = true;
+ ret.data = self.formatData();
+ break;
+ case 'list':
+ ret.res = true;
+ ret.data = self.formatData();
+ break;
+ case 'remove':
+ self.removeWatch(msg.msg);
+ ret.res = true;
+ ret.data = self.formatData();
+ break;
+ default:
+ ret.msg = 'unknown command';
+ ret.code = 400;
+ }
+ }
+
+ sock.end(JSON.stringify(ret), function() {
+ sock.destroy();
+ });
+ });
+ }
+ }
+ /*}}}*/
+
+ /** \brief add watch {{{
+ */
+ this.addWatch = function(files, action, cwd) {
+ debug('watch files = %j', files);
+ debug('watch action = %s', action);
+
+ files.forEach(function(file) {
+ var child = cp.fork(path.join(__dirname, 'child.js'), {cwd: cwd});
+ child.send({cmd: 'add', file: file, action: action}); // we dont care about the result
+ data.push({file: file, action: action, process: child});
+ });
+
+ data.forEach(function(item) {
+ console.log('forked pid = %d', item.process.pid);
+ });
+ }
+ /*}}}*/
+
+ /** \brief remove watch {{{*/
+ this.removeWatch = function(key) {
+ debug('remove key = %d', key);
+ if (typeof data[key] == 'undefined') return;
+ data[key].process.send({cmd: 'remove', file: data[key].file}); // we dont care about the result
+ delete data[key];
+ }
+ /*}}}*/
+}).call(Watchd.prototype);
30 package.json
@@ -0,0 +1,30 @@
+{
+ "name": "node-watchd",
+ "version": "0.0.1",
+ "description": "a simple watchd server and client",
+ "scripts": {
+ "test": "mocha"
+ },
+ "bin": {
+ "watchd": "./bin/watchd",
+ "watch": "./bin/watch"
+ },
+ "dependencies": {
+ "commander" : "*",
+ "debug": "*"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/yarcowang/node-watchd.git"
+ },
+ "keywords": [
+ "watchd",
+ "server"
+ ],
+ "author": {
+ "name": "yarco",
+ "email": "yarco.wang@gmail.com"
+ },
+ "license": "BSD",
+ "readmeFilename": "README.md"
+}
Please sign in to comment.
Something went wrong with that request. Please try again.