123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- #!node
- process.chdir(__dirname);
- var fs = require('fs'),
- url = require('url'),
- path = require('path'),
- vm = require('vm'),
- toobusy = function(){return false;},//require('toobusy'),
- cluster = require('cluster'),
- options = global.options = (function(){
- var defaults = {
- port: 80,
- loglevel: 3,
- redis: {
- port: 6379,
- host: 'localhost'
- },
- debug: false,
- paths: {
- www: './www/',
- api: './api/',
- plugins: './plugins/'
- }
- },
- i,
- options;
- try{
- options = JSON.parse(fs.readFileSync('./options.json'));
- for(var i in options){
- defaults[i] = options[i];
- }
- }catch(e){
- console.warn('Using default settings. Please create options.json');
- }
- options = {};
- for(i in defaults){
- Object.defineProperty(options,i,{
- value: defaults[i],
- enumerable: true,
- writable: false
- });
- }
- return options;
- })();
- if(typeof fs.existsSync == 'undefined') fs.existsSync = path.existsSync; // legacy support
- if(cluster.isMaster){
- for(var i=0;i<require('os').cpus().length;i++){
- cluster.fork();
- }
- cluster.on('exit', function(worker, code, signal) {
- console.log('worker ' + worker.process.pid + ' died');
- });
- if(options.debug){
- require('repl').start({
- prompt: '> ',
- useGlobal: true
- }).on('exit',function(){
- process.exit();
- });
- }
- }else{
- var RedisStore = require('socket.io/lib/stores/redis'),
- redis = require('socket.io/node_modules/redis'),
- pub = redis.createClient(options.redis.port,options.redis.host),
- sub = redis.createClient(options.redis.port,options.redis.host),
- client = redis.createClient(options.redis.port,options.redis.host),
- mimeTypes = {
- 'html': 'text/html',
- 'js': 'text/javascript',
- 'css': 'text/css',
- 'png': 'image/png',
- 'jpg': 'image/jpeg'
- },
- app = require('http').createServer(function(req,res){
- if(toobusy()){
- res.writeHead(503,{
- 'Content-type': 'text/plain'
- });
- res.write('503 Server busy.\n');
- res.end();
- return;
- }
- req.addListener('end',function(){
- logger.debug('served static content for '+req.url);
- var uri = url.parse(req.url).pathname,
- serveFile = function(filename,req,res){
- try{
- stats = fs.lstatSync(filename);
- }catch(e){
- res.writeHead(404,{
- 'Content-type': 'text/plain'
- });
- res.write('404 Not Found.\n');
- res.end();
- return;
- }
- if(stats.isFile()){
- var fileStream,
- mimetype = mimeTypes[path.extname(filename).split('.')[1]];
- res.writeHead(200,{
- 'Content-Type': mimetype
- });
- fileStream = fs.createReadStream(filename);
- fileStream.pipe(res);
- }else if(stats.isDirectory()){
- if(fs.existsSync(path.join(filename,'index.html'))){
- serveFile(path.join(filename,'index.html'),req,res);
- }else if(fs.existsSync(path.join(filename,'index.htm'))){
- serveFile(path.join(filename,'index.htm'),req,res);
- }else if(fs.existsSync(path.join(filename,'index.txt'))){
- serveFile(path.join(filename,'index.txt'),req,res);
- }else{
- res.writeHead(200,{
- 'Content-Type': 'text/plain'
- });
- res.write('Index of '+url+'\n');
- res.write('TODO, show index');
- res.end();
- }
- }else{
- res.writeHead(500,{
- 'Content-Type': 'text/plain'
- });
- res.write('500 Internal server error\n');
- res.end();
- }
- },
- filepath = unescape(uri);
- if(filepath.substr(0,5) == '/api/'){
- filepath = path.join(options.paths.api,filepath.substr(5));
- logger.debug('Attempting to run api script '+filepath);
- if(fs.existsSync(filepath)){
- fs.readFile(filepath,function(e,data){
- if(e){
- logger.error(e);
- res.end('null;');
- }else{
- var output = '',
- sandbox = {
- log: function(text){
- output += text;
- },
- error: function(msg){
- logger.error(msg);
- },
- info: function(msg){
- logger.info(msg);
- },
- debug: function(msg){
- logger.debug(msg);
- },
- head: {
- 'Content-Type': 'text/javascript'
- },
- returnCode: 200,
- vm: vm,
- fs: fs
- };
- vm.runInNewContext(data,sandbox,filepath);
- res.writeHead(sandbox.returnCode,sandbox.head);
- res.end(output);
- }
- });
- }else{
- res.writeHead(404,{
- 'Content-Type': 'text/javascript'
- });
- res.end('null;');
- }
- }else{
- serveFile(path.join(options.paths.www,filepath),req,res);
- }
- }).resume();
- }).listen(options.port),
- io = require('socket.io').listen(app)
- logger = io.log;
- io.set('log level',options.loglevel);
- if(typeof options.redis.password != 'undefined'){
- var eh = function(e){
- throw e;
- };
- pub.auth(options.redis.ppassword,eh);
- sub.auth(options.redis.ppassword,eh);
- client.auth(options.redis.ppassword,eh);
- }
- io.set('store', new RedisStore({
- redisPub : pub,
- redisSub : sub,
- redisClient : client
- }));
- io.sockets.on('connection',function(socket){
- socket.on('join',function(data){
- socket.join(data.name);
- data.title = data.name;
- socket.emit('join',{
- name: data.name
- });
- sendUserList(data.name);
- socket.get('nick',function(e,nick){
- logger.debug(nick+' joined '+data.name);
- io.sockets.in(data.name).emit('message',{
- message: nick+' joined the channel',
- room: data.name,
- from: 0
- });
- });
- });
- socket.on('part',function(data){
- socket.leave(data.name);
- socket.get('nick',function(e,nick){
- logger.debug(nick+' left '+data.name);
- sendUserList(data.name);
- });
- });
- socket.on('disconnect',function(data){
- var rooms = io.sockets.manager.rooms,
- i,
- room;
- for(i in rooms){
- if(rooms[i] != '' && typeof rooms[i] == 'string'){
- try{
- room = rooms[i].substr(1);
- }catch(e){}
- sendUserList(room);
- }
- }
- });
- socket.on('message',function(data){
- logger.debug('message sent to '+data.room);
- io.sockets.in(data.room).emit('message',data);
- });
- socket.on('echo',function(data){
- logger.debug('echoing to '+data.room);
- socket.emit('message',data);
- });
- socket.on('names',function(data){
- var sockets = io.sockets.clients(data.name),
- i;
- runWithUserList(data.name,function(users){
- var temp = [],i;
- for(i in users) i && i != null && temp.push(users[i]);
- users = temp;
- socket.emit('message',{
- message: data.name+" users:\n\t\t"+users.join("\n\t\t"),
- room: data.name,
- from: 0
- });
- sendUserList(data.name);
- });
- });
- socket.on('auth',function(data){
- logger.info(data.nick+' registered');
- // TODO - authorize
- socket.set('nick',data.nick.substr(0,12));
- socket.emit('authorized',{
- nick: data.nick.substr(0,12)
- });
- });
- var runWithUserList = function(room,callback){
- var sockets = io.sockets.clients(room),
- i = 0,
- ret = [],
- getNext = function(){
- if(i < sockets.length){
- sockets[i].get('nick',function(e,nick){
- if(e){
- logger.error(e);
- }else if(!inArray(ret,nick)){
- logger.debug(room+' '+nick);
- ret.push(nick);
- }
- i++;
- getNext();
- });
- }else{
- callback(ret);
- }
- };
- getNext();
- },
- inArray = function(arr,val){
- for(var i in arr){
- if(arr[i] == val){
- return true;
- }
- }
- return false;
- },
- sendUserList = function(room){
- if(typeof room != 'undefined'){
- runWithUserList(room,function(users){
- io.sockets.in(room).emit('names',{
- room: room,
- names: users
- });
- });
- }
- };
- });
- }
- process.on('uncaughtException',function(e){
- if(typeof logger != 'undefined'){
- logger.error(e);
- }else{
- console.error(e);
- }
- });
|