OmnomIRC.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. #!node
  2. var fs = require('fs'),
  3. url = require('url'),
  4. path = require('path'),
  5. vm = require('vm'),
  6. toobusy = function(){return false;},//require('toobusy'),
  7. cluster = require('cluster'),
  8. options = (function(){
  9. var defaults = {
  10. port: 80,
  11. loglevel: 3,
  12. redis: {
  13. port: 6379,
  14. host: 'localhost'
  15. }
  16. },
  17. options;
  18. try{
  19. options = JSON.parse(fs.readFileSync('./options.json'));
  20. for(var i in options){
  21. defaults[i] = options[i];
  22. }
  23. }catch(e){
  24. console.warn('Using default settings. Please create options.js');
  25. }
  26. return defaults;
  27. })();
  28. if(cluster.isMaster){
  29. for(var i=0;i<require('os').cpus().length;i++){
  30. cluster.fork();
  31. }
  32. cluster.on('exit', function(worker, code, signal) {
  33. console.log('worker ' + worker.process.pid + ' died');
  34. });
  35. }else{
  36. var RedisStore = require('socket.io/lib/stores/redis'),
  37. redis = require('socket.io/node_modules/redis'),
  38. pub = redis.createClient(options.redis.port,options.redis.host),
  39. sub = redis.createClient(options.redis.port,options.redis.host),
  40. client = redis.createClient(options.redis.port,options.redis.host),
  41. mimeTypes = {
  42. 'html': 'text/html',
  43. 'js': 'text/javascript',
  44. 'css': 'text/css',
  45. 'png': 'image/png',
  46. 'jpg': 'image/jpeg'
  47. },
  48. app = require('http').createServer(function(req,res){
  49. if(toobusy()){
  50. res.writeHead(503,{
  51. 'Content-type': 'text/plain'
  52. });
  53. res.write('503 Server busy.\n');
  54. res.end();
  55. return;
  56. }
  57. req.addListener('end',function(){
  58. logger.debug('served static content for '+req.url);
  59. var uri = url.parse(req.url).pathname,
  60. serveFile = function(filename,req,res){
  61. try{
  62. stats = fs.lstatSync(filename);
  63. }catch(e){
  64. res.writeHead(404,{
  65. 'Content-type': 'text/plain'
  66. });
  67. res.write('404 Not Found.\n');
  68. res.end();
  69. return;
  70. }
  71. if(stats.isFile()){
  72. var fileStream,
  73. mimetype = mimeTypes[path.extname(filename).split('.')[1]];
  74. res.writeHead(200,{
  75. 'Content-Type': mimetype
  76. });
  77. fileStream = fs.createReadStream(filename);
  78. fileStream.pipe(res);
  79. }else if(stats.isDirectory()){
  80. if(fs.existsSync(path.join(filename,'index.html'))){
  81. serveFile(path.join(filename,'index.html'),req,res);
  82. }else if(fs.existsSync(path.join(filename,'index.htm'))){
  83. serveFile(path.join(filename,'index.htm'),req,res);
  84. }else if(fs.existsSync(path.join(filename,'index.txt'))){
  85. serveFile(path.join(filename,'index.txt'),req,res);
  86. }else{
  87. res.writeHead(200,{
  88. 'Content-Type': 'text/plain'
  89. });
  90. res.write('Index of '+url+'\n');
  91. res.write('TODO, show index');
  92. res.end();
  93. }
  94. }else{
  95. res.writeHead(500,{
  96. 'Content-Type': 'text/plain'
  97. });
  98. res.write('500 Internal server error\n');
  99. res.end();
  100. }
  101. },
  102. filepath = unescape(uri);
  103. if(filepath.substr(0,5) == '/api/'){
  104. filepath = path.join('./api/',filepath.substr(5));
  105. logger.debug('Attempting to run api script '+filepath);
  106. if(fs.existsSync(filepath)){
  107. fs.readFile(filepath,function(e,data){
  108. if(e){
  109. logger.error(e);
  110. res.end('null;');
  111. }else{
  112. var output = '',
  113. sandbox = {
  114. log: function(text){
  115. output += text;
  116. },
  117. error: function(msg){
  118. logger.error(msg);
  119. },
  120. info: function(msg){
  121. logger.info(msg);
  122. },
  123. debug: function(msg){
  124. logger.debug(msg);
  125. },
  126. head: {
  127. 'Content-Type': 'text/javascript'
  128. },
  129. returnCode: 200,
  130. vm: vm,
  131. fs: fs
  132. };
  133. vm.runInNewContext(data,sandbox,filepath);
  134. res.writeHead(sandbox.returnCode,sandbox.head);
  135. res.end(output);
  136. }
  137. });
  138. }else{
  139. res.writeHead(404,{
  140. 'Content-Type': 'text/javascript'
  141. });
  142. res.end('null;');
  143. }
  144. }else{
  145. serveFile(path.join('./www/',filepath),req,res);
  146. }
  147. }).resume();
  148. }).listen(options.port),
  149. io = require('socket.io').listen(app)
  150. logger = io.log;
  151. io.set('log level',options.loglevel);
  152. if(typeof options.redis.password != 'undefined'){
  153. var eh = function(e){
  154. throw e;
  155. };
  156. pub.auth(options.redis.ppassword,eh);
  157. sub.auth(options.redis.ppassword,eh);
  158. client.auth(options.redis.ppassword,eh);
  159. }
  160. io.set('store', new RedisStore({
  161. redisPub : pub,
  162. redisSub : sub,
  163. redisClient : client
  164. }));
  165. io.sockets.on('connection',function(socket){
  166. socket.on('join',function(data){
  167. socket.join(data.name);
  168. data.title = data.name;
  169. socket.emit('join',{
  170. name: data.name,
  171. title: data.title
  172. });
  173. sendUserList(data.name);
  174. socket.get('nick',function(e,nick){
  175. logger.debug(nick+' joined '+data.name);
  176. io.sockets.in(data.name).emit('message',{
  177. message: nick+' joined the channel',
  178. room: data.name,
  179. from: 0
  180. });
  181. });
  182. });
  183. socket.on('part',function(data){
  184. socket.leave(data.name);
  185. socket.get('nick',function(e,nick){
  186. logger.debug(nick+' left '+data.name);
  187. sendUserList(data.name);
  188. });
  189. });
  190. socket.on('disconnect',function(data){
  191. var rooms = io.sockets.manager.rooms,
  192. i,
  193. room;
  194. for(i in rooms){
  195. if(rooms[i] != '' && typeof rooms[i] == 'string'){
  196. try{
  197. room = rooms[i].substr(1);
  198. }catch(e){}
  199. sendUserList(room);
  200. }
  201. }
  202. });
  203. socket.on('message',function(data){
  204. logger.debug('message sent to '+data.room);
  205. io.sockets.in(data.room).emit('message',data);
  206. });
  207. socket.on('echo',function(data){
  208. logger.debug('echoing to '+data.room);
  209. socket.emit('message',data);
  210. });
  211. socket.on('names',function(data){
  212. var sockets = io.sockets.clients(data.name),
  213. i;
  214. runWithUserList(data.name,function(users){
  215. socket.emit('message',{
  216. message: data.name+" users:\n"+users.join("\n\t"),
  217. room: data.name,
  218. from: 0
  219. });
  220. sendUserList(data.name);
  221. });
  222. });
  223. socket.on('auth',function(data){
  224. logger.info(data.nick+' registered');
  225. // TODO - authorize
  226. socket.set('nick',data.nick.substr(0,12));
  227. socket.emit('authorized',{
  228. nick: data.nick.substr(0,12)
  229. });
  230. });
  231. var runWithUserList = function(room,callback){
  232. var sockets = io.sockets.clients(room),
  233. i = 0,
  234. ret = [],
  235. getNext = function(){
  236. if(i < sockets.length){
  237. sockets[i].get('nick',function(e,nick){
  238. if(e){
  239. logger.error(e);
  240. ret.push('');
  241. }else{
  242. logger.debug(room+' '+nick);
  243. ret.push(nick);
  244. }
  245. i++;
  246. getNext();
  247. });
  248. }else{
  249. callback(ret);
  250. }
  251. };
  252. getNext();
  253. },
  254. sendUserList = function(room){
  255. if(typeof room != 'undefined'){
  256. runWithUserList(room,function(users){
  257. io.sockets.in(room).emit('names',{
  258. room: room,
  259. names: users
  260. });
  261. });
  262. }
  263. };
  264. });
  265. }
  266. process.on('uncaughtException',function(e){
  267. logger.error(e);
  268. });