OmnomIRC.js 7.1 KB

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