Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

code refactored, packages updated

  • Loading branch information...
commit ca378d153ea5519bef0b3b109d72222d69348c1a 1 parent a27fda9
@netroy authored
View
4 .gitignore
@@ -0,0 +1,4 @@
+npm-debug.log
+node_modules
+.DS_Store
+*.css
View
33 .jshintrc
@@ -0,0 +1,33 @@
+{
+ // Globals
+ "predef": [
+ "console",
+ "require",
+ "module",
+ "exports",
+ "Buffer",
+ "process",
+ "setTimeout",
+ "__dirname"
+ ],
+
+ // ES5 Strict mode on
+ "es5": true,
+ "strict": true,
+ "esnext": false,
+
+ // Each block must be wrapped in curly-braces
+ "curly": true,
+
+ // Allow ExpressionStatements
+ "expr": true,
+
+ // Require capitalization of all constructor function-names
+ "newcap": true,
+
+ // Fail for trailing white-spaces
+ "trailing": true,
+
+ // mandate 2-space indentation
+ "indent": 2
+}
View
90 index.html
@@ -1,90 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
- <title>Websockets tail Server</title>
- <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
- <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
- <script src="/socket.io/socket.io.js"></script>
- <style type="text/css" rel="stylesheet">
- body{background-color:#333;}
- #selector{ float:left;}
- #info{ height:40px; font-size: 32px; color:#000;text-shadow:#777 1px 1px 2px; text-align:right;margin:20px 10px;text-transform:lowercase;}
- #tail{ clear:both; border: 1px solid #555; overflow-x:hidden; overflow-y:auto; background-color:#444; color: #EEE; text-shadow:#000 0 0 2px; height: 400px; padding: 10px; font-size:12px; line-height:20px;}
- .trebuchet{font-family: "Trebuchet MS","Lucida Sans Unicode","Lucida Grande","Lucida Sans",Arial,sans-serif;}
- .monospace{font-family: Monaco,"Bitstream Vera Sans Mono","Lucida Console",Terminal,monospace;}
- .selection::selection , .selection *::selection{background: #EEE;color:#000;border-color:#000; text-shadow:#fff 0 0 2px;}
- .selection::-moz-selection , .selection *::-moz-selection{background: #EEE;color:#000;border-color:#000; text-shadow:#fff 0 0 2px;}
-
- ::-webkit-scrollbar {width: 6px;}
- ::-webkit-scrollbar-track-piece { border-radius: 3px; }
- ::-webkit-scrollbar-thumb{ background: #555; width: 5px; border-radius: 10px; opacity: 0.2;}
- ol:hover::-webkit-scrollbar-thumb { background-color: #ccc; opacity: 1.0;}
- #tail li:hover { background:#000; }
-
- /* Yellow-fade thanks to @snookca: http://snook.ca/archives/html_and_css/yellow-fade-technique-css-animations */
- #tail li {
- -webkit-animation: target-fade 3s 1;
- -moz-animation: target-fade 3s 1;
- }
- @-webkit-keyframes target-fade {
- 0% { background-color: rgba(255,255,0,0.2); }
- 100% { background-color: rgba(0,0,0,0); }
- }
- @-moz-keyframes target-fade {
- 0% { background-color: rgba(255,255,0,0.2); }
- 100% { background-color: rgba(0,0,0,0); }
- }
- </style>
-</head>
-<body>
- <div id="selector"><select><option value="" selected>-- select a log --</option></select></div>
- <div id="info" class="trebuchet"></div>
- <ol id="tail" class="monospace selection"></ol>
- <script type="text/javascript">
- (function() {
- var lines = 0, notice = $("#info"), buffer = $('#tail');
- function rescale(){
- $("#tail").height($(window).height()-120);
- }
- rescale();
- $(window).resize(rescale);
- var socket = io.connect();
- socket.on('connect', function() {
- console.log('Connected');
- });
- socket.on('message', function(message) {
- if (message.logs){
- var selector = $("#selector select");
- $.each(message.logs,function(){
- var log = new Option(this,this);
- if ($.browser.msie) selector[0].add(log);
- else selector[0].add(log,null);
- });
- selector.bind('change',function(e){
- var log = selector[0];
- if(log.selectedIndex == 0){
- $("#info,#tail").empty();
- return;
- }
- socket.emit('message', {log:log.options[log.selectedIndex].value});
- });
- }else if (message.filename) {
- notice.html( 'watching ' + message.filename );
- }else if (message.tail) {
- message.tail.forEach(function(entry){
- if(!entry) return;
- var li = $('<li>');
- li.text(entry);
- buffer.append(li);
- });
-
- buffer.scrollTop(lines*100)
- lines = lines + message.tail.length;
- }else if(message.clear) {
- $('#tail').empty();
- }else console.log(message);
- });
- })();
- </script>
-</body>
-</html>
View
56 index.js
@@ -0,0 +1,56 @@
+// ===================================
+// `tail -f` in Node.js and WebSockets
+// ===================================
+
+(function() {
+
+ 'use strict';
+
+ var socketIO = require('socket.io');
+ var optmist = require('optimist');
+ var connect = require('connect');
+ var stylus = require('stylus');
+
+ var http = require('http');
+ var fs = require('fs');
+ var path = require('path');
+
+ // Directory to watch
+ var logDir = process.argv.length > 2 ? process.argv[2] : "/tmp";
+
+ // Create an connect app
+ var app = connect();
+
+ // Setup Socket.IO
+ var httpServer = http.createServer(app);
+ var io = socketIO.listen(httpServer);
+ io.set('log level', 1);
+
+
+ // Stylesheets
+ var baseDir = path.join(__dirname, 'public');
+ app.use(stylus.middleware({
+ 'src': baseDir
+ }));
+
+ // Other static content
+ app.use(connect['static'](baseDir));
+
+
+ // Fetch list of files & start watching
+ require('./lib/list-files')(logDir, function(err, logFiles) {
+
+ if(err) {
+ throw err;
+ }
+
+ io.sockets.on('connection', require('./lib/io-handler')(logDir, logFiles));
+
+ httpServer.listen(8007);
+
+ console.log('Log Server running now at http://0.0.0.0:8007/');
+ });
+
+ module.exports = httpServer;
+
+}).call();
View
83 lib/io-handler.js
@@ -0,0 +1,83 @@
+(function() {
+
+ 'use strict';
+
+ var fs = require('fs');
+ var path = require('path');
+
+ var backlog_size = 5000;
+
+ function streamData(fileName, start, end, socket) {
+
+ var stream = fs.createReadStream(fileName, {
+ 'start': start,
+ 'end': end
+ });
+
+ stream.addListener("data", function(lines){
+
+ lines = lines.toString('utf-8');
+ lines = lines.slice(lines.indexOf("\n") + 1).split("\n");
+ socket.emit('tail', lines);
+ });
+
+ return stream;
+ }
+
+ function onConnect(logDir, logFiles) {
+
+ return function(socket) {
+
+ socket.emit('list', logFiles);
+
+ socket.on('message', function(message) {
+
+ if(message.log) {
+
+ // Stop watching the last file and send the new one
+ fs.unwatchFile(fileName);
+
+ var fileName = path.join(logDir, message.log);
+ socket.emit('select', fileName);
+
+ // send some back log
+ fs.stat(fileName, function(err, stats) {
+
+ if (err) {
+ throw err;
+ }
+
+ if (stats.size === 0){
+ socket.emit('clear');
+ return;
+ }
+
+ var start = (stats.size > backlog_size) ? (stats.size - backlog_size) : 0;
+ streamData(fileName, start, stats.size, socket);
+ });
+
+ // watch the file now
+ fs.watchFile(fileName, function(curr, prev) {
+
+ if(prev.size > curr.size) {
+ return {
+ 'clear': true
+ };
+ }
+
+ streamData(fileName, prev.size, curr.size, socket);
+ });
+
+ // stop watching the file
+ socket.on('disconnect',function() {
+
+ fs.unwatchFile(fileName);
+ });
+ }
+ });
+ };
+ }
+
+ module.exports = onConnect;
+
+}).call();
View
35 lib/list-files.js
@@ -0,0 +1,35 @@
+/*global require, module*/
+(function() {
+
+ 'use strict';
+
+ var fs = require('fs');
+ var path = require('path');
+
+ module.exports = function populate(logDir, callback) {
+
+ // look up the dir for logs
+ fs.readdir(logDir, function(err, files){
+
+ if(err) {
+ return callback(err);
+ }
+
+ var logFiles = [];
+
+ // Fix the Array
+ files = Array.prototype.sort.apply(files,[]);
+
+ files.forEach(function(file) {
+ var filePath = path.join(logDir, file);
+ var isFile = fs.statSync(filePath).isFile();
+ if(isFile) {
+ logFiles.push(file);
+ }
+ });
+
+ callback(null, logFiles);
+ });
+ };
+
+}).call();
View
31 package.json
@@ -0,0 +1,31 @@
+{
+ "name": "lockets",
+ "version": "0.1.0",
+ "description": "Tail -f in node.js",
+ "keywords": [],
+ "author": {
+ "name": "Aditya",
+ "email": "aditya@netroy.in"
+ },
+ "license": {
+ "type": "MIT"
+ },
+ "repository": {
+ "type": "git",
+ "url": "http://github.com/netroy/lockets.git"
+ },
+ "directories": {},
+ "engines": {
+ "node": ">=0.8.0"
+ },
+ "dependencies": {
+ "connect": "2.4.5",
+ "optimist": "0.3.5",
+ "socket.io": "0.9.10",
+ "stylus": "0.29.0"
+ },
+ "main": "index.js",
+ "scripts": {
+ "test": "vows --spec tests/*"
+ }
+}
View
79 public/css/app.styl
@@ -0,0 +1,79 @@
+body
+ background-color: #333
+
+#selector
+ float: left
+
+#info
+ height: 40px
+ font-size: 32px
+ color: #000
+ text-shadow: #777 1px 1px 2px
+ text-align: right
+ margin: 20px 10px
+ text-transform: lowercase
+
+#tail
+ clear: both
+ border: 1px solid #555
+ overflow-x: hidden
+ overflow-y: auto
+ background-color: #444
+ color: #EEE
+ text-shadow: #000 0 0 2px
+ height: 400px
+ padding: 10px
+ font-size: 12px
+ line-height: 20px
+
+.trebuchet
+ font-family: "Trebuchet MS","Lucida Sans Unicode","Lucida Grande","Lucida Sans",Arial,sans-serif
+
+.monospace
+ font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", "Terminal", monospace
+
+.selection::selection, .selection *::selection
+ background: #EEE
+ color: #000
+ border-color: #000
+ text-shadow: #fff 0 0 2px
+
+.selection::-moz-selection, .selection *::-moz-selection
+ background: #EEE
+ color: #000
+ border-color: #000
+ text-shadow: #fff 0 0 2px
+
+::-webkit-scrollbar
+ width: 6px
+
+::-webkit-scrollbar-track-piece
+ border-radius: 3px
+
+::-webkit-scrollbar-thumb
+ background: #555
+ width: 5px
+ border-radius: 10px
+ opacity: 0.2
+
+ol:hover::-webkit-scrollbar-thumb
+ background-color: #ccc
+ opacity: 1.0
+
+#tail li:hover
+ background: #000
+
+/* Yellow-fade thanks to @snookca: http://snook.ca/archives/html_and_css/yellow-fade-technique-css-animations */
+
+#tail li
+ -webkit-animation: target-fade 3s 1
+ -moz-animation: target-fade 3s 1
+
+@-webkit-keyframes target-fade {
+ 0% { background-color: rgba(255,255,0,0.2); }
+ 100% { background-color: rgba(0,0,0,0); }
+}
+@-moz-keyframes target-fade {
+ 0% { background-color: rgba(255,255,0,0.2); }
+ 100% { background-color: rgba(0,0,0,0); }
+}
View
16 public/index.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Websockets tail Server</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+ <script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
+ <script src="/socket.io/socket.io.js"></script>
+ <link rel="stylesheet" type="text/css" href="css/app.css">
+</head>
+<body>
+ <div id="selector"><select><option value="" selected>-- select a log --</option></select></div>
+ <div id="info" class="trebuchet"></div>
+ <ol id="tail" class="monospace selection"></ol>
+ <script type="text/javascript" src = "js/app.js"></script>
+</body>
+</html>
View
73 public/js/app.js
@@ -0,0 +1,73 @@
+/*global $, window, io, Option, console*/
+$(function() {
+
+ 'use strict';
+
+ var lines = 0;
+ var notice = $('#info');
+ var buffer = $('#tail');
+
+ var $win = $(window);
+ function rescale(){
+ buffer.height($win.height()-120);
+ }
+ $win.resize(rescale);
+ rescale();
+
+ var log = console.log.bind(console, 'TAIL');
+
+ var socket = io.connect();
+ socket.on('connect', function() {
+ log('Connected');
+ });
+
+ socket.on('list', function(logFiles) {
+ var selector = $("#selector select");
+ $.each(logFiles, function() {
+ var log = new Option(this,this);
+ if ($.browser.msie) {
+ selector[0].add(log);
+ } else {
+ selector[0].add(log,null);
+ }
+ });
+
+ selector.bind('change',function(e){
+ var log = selector[0];
+ if(log.selectedIndex === 0){
+ $("#info,#tail").empty();
+ return;
+ }
+ socket.emit('message', {
+ 'log':log.options[log.selectedIndex].value
+ });
+ });
+ });
+
+ socket.on('select', function(fileName) {
+ notice.html('watching ' + fileName);
+ });
+
+ socket.on('tail', function(backLog) {
+
+ $.each(backLog, function(index, entry) {
+
+ if(!entry) {
+ return;
+ }
+
+ var li = $('<li>');
+ li.text(entry);
+ buffer.append(li);
+ });
+
+ buffer.scrollTop(lines * 100);
+ lines = lines + backLog.length;
+ });
+
+ socket.on('clear', function() {
+ buffer.empty();
+ });
+
+ socket.on('message', log);
+});
View
82 server.js
@@ -1,82 +0,0 @@
-// ===================================
-// `tail -f` in Node.js and WebSockets
-// ===================================
-var http = require('http'),
- io = require('socket.io'),
- fs = require('fs');
-var path = require('path');
-
-var backlog_size = 5000;
-var log_dir = process.argv.length > 2 ? process.argv[2] : "/var/log/";
-var logs = [];
-// look up the dir for logs
-fs.readdir(log_dir, function(err,files){
- if(err) throw err;
- files = Array.prototype.sort.apply(files,[]);
- for(var file in files){
- file = files[file];
- if(fs.statSync(path.join(log_dir,file)).isFile()) logs.push(file);
- }
-});
-
-// -- Node.js HTTP Server ----------------------------------------------------------
-server = http.createServer(function(req, res){
- res.writeHead(200, {
- 'Content-Type': 'text/html'
- });
-
- fs.readFile(__dirname + '/index.html', function(err, data){
- res.write(data, 'utf8');
- res.end();
- });
-});
-server.listen(8000);
-
-// -- Setup Socket.IO ---------------------------------------------------------
-var io = io.listen(server);
-io.set('log level', 0);
-
-io.sockets.on('connection', function(client){
- var filename;
- client.json.send( { logs : logs } );
- client.on("message",function(message){
- if(message.log){
- // Stop watching the last file and send the new one
- fs.unwatchFile(filename);
- filename = join(log_dir, message.log);
- client.json.send({filename: filename});
-
- // send some back log
- fs.stat(filename,function(err,stats){
- if (err) throw err;
- if (stats.size === 0){
- client.json.send({clear:true});
- return;
- }
- var start = (stats.size > backlog_size)?(stats.size - backlog_size):0;
- var stream = fs.createReadStream(filename,{start:start, end:stats.size});
- stream.addListener("data", function(lines){
- lines = lines.toString('utf-8');
- lines = lines.slice(lines.indexOf("\n")+1).split("\n");
- client.json.send({ tail : lines});
- });
- });
-
- // watch the file now
- fs.watchFile(filename, function(curr, prev) {
- if(prev.size > curr.size) return {clear:true};
- var stream = fs.createReadStream(filename, { start: prev.size, end: curr.size});
- stream.addListener("data", function(lines) {
- client.json.send({ tail : lines.toString('utf-8').split("\n") });
- });
- });
-
- // stop watching the file
- client.on("disconnect",function(){
- fs.unwatchFile(filename);
- });
- }
- });
-});
-
-console.log('Log Server running now at http://[HOSTNAME]:8000/ in your browser');
Please sign in to comment.
Something went wrong with that request. Please try again.