OSDN Git Service

タイマーが解放されない問題を解決した
[webchat/WebChat.git] / chatServer.js
1 /*\r
2  * 設定\r
3  */\r
4 $max_room_number = 3;   //最大ルーム数\r
5 $spilt_size = 1024 * 512;       //分割するサイズ\r
6 $reset_password_diff = 1000 * 60 * 60;  //ルームパスワードをリセットする間隔\r
7 $gc_time_interval = 1000 * 60 * 60;     //ゴミ掃除を行う間隔\r
8 $block_message = "メッセージの送信に失敗しました";       //ブロック時のメッセージ\r
9 $not_match_password = "パスワードが一致しませんでした";  //パスワードが一致しない場合に表示されるメッセージ\r
10 $password_setted_message = "パスワードを設定しました";      //パスワードが設定されたときに表示されるメッセージ\r
11 $password_resetted_message = "パスワードをリセットしました";      //パスワードが再設定されたときに表示されるメッセージ\r
12 $failed_set_password_message = "パスワードの設定に失敗しました"; //パスワードが再設定されたときに表示されるメッセージ\r
13 $ip_ban_list_file_name = "ipbanlist.txt";       //アクセスを禁止するIPが記録されているファイル\r
14 $room_configure_file_name = "roomlist.txt";     //ルームの設定が記録されているファイル\r
15 $port = process.env.port || 3000;       //ポート\r
16 $username = "admin";    //管理者用のページにアクセスできるユーザ名\r
17 $password = "admin";    //管理者用のページにアクセスするのに必要なパスワード\r
18 $token_length = 32;     //トークンの長さ\r
19 $redisHost = "localhost";       //redisサーバのアドレス\r
20 $redisPort = 6379;      //redisサーバのポート\r
21 $redisPassword = "";    //redisサーバのパスワード\r
22 $system_name = "system";        //システム発言を表す名前\r
23 $log_directory = "log"; //ログファイルを置くフォルダー\r
24 $log_file_name = "logfile%d.txt";       //ログファイル名(%dはそのままにしておくこと)\r
25 $splited_log_file_name = "logfile%d_%s.txt"     //分割後のファイル名(%dと%sはそのままにしておくこと)\r
26 $pastlogfile_pattern = "logfile%d(_+.*)?\.txt"; //過去ログと判定する正規表現\r
27 $logfile_pattern = "logfile[0-9]+(_*.*)?\.txt"  //過去ログと判定する正規表現\r
28 \r
29 /**\r
30  * Module dependencies.\r
31  */\r
32 \r
33 // Server\r
34 var express = require('express');\r
35 \r
36 var app = module.exports = express.createServer();\r
37 \r
38 var util = require("util");\r
39 \r
40 var lazy = require("lazy");\r
41 \r
42 var fs = require("fs");\r
43 \r
44 var parseCookie = require("connect").utils.parseCookie;\r
45 \r
46 var RedisStore = require("connect-redis")(express);\r
47 var sessionStore = new RedisStore({host:$redisHost,port:$redisPort,pass:$redisPassword});\r
48 \r
49 var async = require("async");\r
50 \r
51 var path = require("path");\r
52 \r
53 // Configuration\r
54 \r
55 app.configure(function(){\r
56         app.disabled("view cache");\r
57         app.set("view options", { layout: false })\r
58         app.set("views", __dirname + "/public");\r
59         app.set("view engine", "ejs");\r
60         app.use(express.bodyParser());\r
61         app.use(express.methodOverride());\r
62         app.use(express.cookieParser());\r
63         app.use(express.session({\r
64                 store:sessionStore,\r
65                 secret: "5514EA2B-C9B2-4D65-8D81-1F33A180A0C2",\r
66                 cookie: { httpOnly: false }\r
67         }));\r
68         app.use(app.router);\r
69         app.use(express.static(__dirname + "/public"));\r
70 });\r
71 \r
72 app.configure('development', function(){\r
73   app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); \r
74 });\r
75 \r
76 app.configure('production', function(){\r
77   app.use(express.errorHandler()); \r
78 });\r
79 \r
80 // Routes\r
81 app.get("/chat", function(req, res){\r
82         var auth_string = getRandomString($token_length);\r
83         req.session.items = {token:auth_string};\r
84 \r
85         var room_number = 0;\r
86         if(typeof(req.query.rno) != "undefined")\r
87                 room_number = req.query.rno;\r
88         res.render("chat",{rno:room_number,token:auth_string});\r
89 });\r
90 \r
91 app.all("/log/" + $logfile_pattern,express.basicAuth(function (user, pass) {\r
92         return user === $username && pass === $password;\r
93 }));\r
94 \r
95 app.get("/log/" + $logfile_pattern, function(req, res){\r
96         res.sendfile(__dirname + req.url);\r
97 });\r
98 \r
99 app.all("/admin",express.basicAuth(function (user, pass) {\r
100         return user === $username && pass === $password;\r
101 }));\r
102 \r
103 app.get("/admin", function(req, res){\r
104         renderAdmin(req,res);\r
105 });\r
106 \r
107 app.post("/admin",function(req,res){\r
108         if(req.session.items.token != req.body.token)\r
109         {\r
110                 res.send($invaild_token_message);\r
111                 return;\r
112         }\r
113         if(typeof(req.body.erase) != "undefined")\r
114         {\r
115                 removeLog(req.body.file,function(){\r
116                         renderAdmin(req,res);\r
117                 });\r
118         }\r
119         if(typeof(req.body.registor) != "undefined")\r
120         {\r
121                 ipbanlist.Update(req.body.newbanlist,function(){\r
122                         renderAdmin(req,res);\r
123                 });\r
124         }\r
125         if(typeof(req.body.updateroom) != "undefined")\r
126         {\r
127                 $rooms.Update(req.body.newroomlist,function(){\r
128                         renderAdmin(req,res);\r
129                 });\r
130         }\r
131 });\r
132 \r
133 function renderAdmin(req,res)\r
134 {\r
135         var auth_string = getRandomString($token_length);\r
136         req.session.items = {token:auth_string};\r
137         var iplist = ipbanlist.GetText();\r
138 \r
139         fs.readdir($log_directory,function(err,list){\r
140                 res.render("admin", {\r
141                         files: list,\r
142                         log_directory:$log_directory,\r
143                         ipbanlist:iplist,\r
144                         token:auth_string,\r
145                         roomlist:$rooms.GetString()\r
146                 });\r
147         });\r
148 }\r
149 \r
150 function getRandomString(length)\r
151 {\r
152         var RandomString = "";\r
153         var BaseString ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&'()=~|-^\@[;:],./\`{+*}<>?_";\r
154         for(var i=0; i<length; i++) {\r
155                 RandomString += BaseString.charAt( Math.floor( Math.random() * BaseString.length));\r
156         }\r
157         return RandomString\r
158 }\r
159 \r
160 function removeLog(files,callback)\r
161 {\r
162         async.map(files,\r
163         function(item,callback){\r
164                 fs.unlink($log_directory + "/" + item,callback);\r
165         },\r
166         function(err,results){\r
167                 if(typeof(callback) == "function")\r
168                         callback();\r
169         });\r
170 }\r
171 \r
172 app.listen($port);\r
173 console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);\r
174 \r
175 /*\r
176  * サーバー部分\r
177  */\r
178 \r
179 var io = require("socket.io").listen(app);\r
180 io.configure('production', function(){\r
181   io.enable('browser client minification');  // minified されたクライアントファイルを送信する\r
182   io.enable('browser client etag');          // バージョンによって etag によるキャッシングを有効にする\r
183   io.set('log level', 1);                    // ログレベルを設定(デフォルトより下げている)\r
184 });\r
185 var clients = new Array();\r
186 \r
187 var ipbanlist = new IpBanCollecion();\r
188 var $rooms = new RoomInfomationCollection();\r
189 \r
190 createLogDirectory();\r
191 \r
192 for(var i = 0; i < $max_room_number; i++)\r
193 {\r
194         clients[i] =io\r
195         .of(GetNameFromRoomNumber(i))\r
196         .authorization(ParseAuthorization)\r
197         .on("connection", function (socket) {\r
198                 var ip = GetClientIPAdress(socket);\r
199 \r
200                 console.log("connected from %s",ip);\r
201 \r
202                 var rno = GetRoomNumberFromName(socket.namespace.name);\r
203                 var roomconfig = {};\r
204                 $rooms.Get(rno).AddRom(ip);\r
205                 if($rooms.Get(rno).IsVolatile() == false)\r
206                 {\r
207                         if($rooms.Get(rno).IsFixedPassword())\r
208                                 roomconfig.type = 2;\r
209                         else if($rooms.Get(rno).IsHiddenLogFromRom())\r
210                                 roomconfig.type = 3;\r
211                         else\r
212                                 roomconfig.type = 1;\r
213                         roomconfig.IsOwned = !$rooms.Get(rno).IsFirstAuth();\r
214                 }else{\r
215                         roomconfig.type = 0;\r
216                 }\r
217                 socket.json.emit("send roominfo",roomconfig);\r
218 \r
219                 var romcount = $rooms.Get(rno).GetRomCount();\r
220                 socket.json.emit("send romcount",romcount);\r
221                 socket.json.broadcast.emit("send romcount",romcount);\r
222 \r
223                 socket.on("get pastLogList", function (msg) {\r
224                         ParseGetPastLogList(socket,msg);\r
225                 });\r
226                 socket.on("get pastLog", function (msg) {\r
227                         ParseGetPastLog(socket,msg);\r
228                 });\r
229                 socket.on("join",function(msg){\r
230                         ParseJoin(socket,msg);\r
231                 });\r
232                 socket.on("quit",function(msg){\r
233                         ParseQuit(socket,msg);\r
234                 });\r
235                 socket.on("set password",function(msg){\r
236                         ParseSetPassword(socket,msg);\r
237                 });\r
238                 socket.on("send msg", function (msg) {\r
239                         ParseSendMsg(socket,msg);\r
240                 });\r
241                 socket.on("disconnect", function (msg) {\r
242                         ParseDisconnect(socket,msg);\r
243                 });\r
244         });\r
245 }\r
246 \r
247 function createLogDirectory()\r
248 {\r
249         path.exists($log_directory,function(exists){\r
250                 if(exists == false)\r
251                         fs.mkdirSync($log_directory);\r
252         });\r
253 }\r
254 \r
255 function ParseAuthorization(handshakeData, callback)\r
256 {\r
257         if(handshakeData.headers.cookie) {\r
258                 var cookie = handshakeData.headers.cookie;\r
259                 var sessionID = parseCookie(cookie)["connect.sid"];\r
260                 sessionStore.get(sessionID, function (err, session) {\r
261                         var result = null;\r
262                         if (ipbanlist.IsBaned(handshakeData.address.address))\r
263                                 result = "failed get from session store";\r
264                         else if(err)\r
265                                 result = err;\r
266                         else if(handshakeData.query.token != session.items.token)\r
267                                 result = "invaild token";\r
268                         sessionStore.destroy(sessionID);\r
269                         callback(result,result == null && !err);\r
270                 });\r
271         } else {\r
272                 return callback("failed get cookie", false);\r
273         }\r
274 }\r
275 \r
276 function ParseDisconnect(socket,msg)\r
277 {\r
278         var ip = GetClientIPAdress(socket);\r
279         var rno = GetRoomNumberFromName(socket.namespace.name);\r
280         $rooms.Get(rno).RemoveRom(ip);\r
281 \r
282         var romcount = $rooms.Get(rno).GetRomCount();\r
283         socket.json.emit("send romcount",romcount);\r
284         socket.json.broadcast.emit("send romcount",romcount);\r
285 \r
286         console.log("disconnected");\r
287 }\r
288 \r
289 function ParseSetPassword(socket,msg)\r
290 {\r
291         var rno = GetRoomNumberFromName(socket.namespace.name);\r
292         var newMeg = {\r
293                 name:$system_name,\r
294                 message:null,\r
295         };\r
296         if($rooms.Get(rno).IsVolatile() == false && $rooms.Get(rno).SetPassword(msg.owner,msg.password))\r
297                 newMeg.message = $password_setted_message;\r
298         else\r
299                 newMeg.message = $failed_set_password_message;\r
300         ParseSendMsg(socket,newMeg);\r
301 }\r
302 \r
303 function ParseJoin(socket,msg)\r
304 {\r
305         var ip = GetClientIPAdress(socket);\r
306 \r
307         if(ipbanlist.IsBlockedToWrite(ip))\r
308         {\r
309                 socket.emit("error",$block_message);\r
310                 return;\r
311         }\r
312 \r
313         var rno = GetRoomNumberFromName(socket.namespace.name);\r
314 \r
315         $rooms.Get(rno).RemoveRom(ip);\r
316         \r
317         var romcount = $rooms.Get(rno).GetRomCount();\r
318         socket.json.emit("send romcount",romcount);\r
319         socket.json.broadcast.emit("send romcount",romcount);\r
320 \r
321         if($rooms.Get(rno).IsVolatile() == false)\r
322         {\r
323                 if($rooms.Get(rno).IsTimeout() ||\r
324                         $rooms.Get(rno).IsFirstAuth())\r
325                 {\r
326                         $rooms.Get(rno).Reset(msg.name);\r
327                         ParseGetPastLog(socket,util.format($log_file_name,rno));\r
328                 }\r
329                 else if($rooms.Get(rno).Auth(msg.name,msg.password))\r
330                 {\r
331                         ParseGetPastLog(socket,util.format($log_file_name,rno));\r
332                 }\r
333                 else\r
334                 {\r
335                         socket.emit("error",$not_match_password);\r
336                         return;\r
337                 }\r
338         }\r
339 \r
340         var newMeg = {\r
341                 name:$system_name,\r
342                 message:util.format("/enteredby %s %s %s",msg.name,msg.color,msg.mailto),\r
343         };\r
344         ParseSendMsg(socket,newMeg);\r
345 }\r
346 \r
347 function ParseQuit(socket,msg)\r
348 {\r
349         var ip = GetClientIPAdress(socket);\r
350 \r
351         if(ipbanlist.IsBlockedToWrite(ip))\r
352         {\r
353                 socket.emit("error",$block_message);\r
354                 return;\r
355         }\r
356 \r
357         var rno = GetRoomNumberFromName(socket.namespace.name);\r
358 \r
359         var newMeg = {\r
360                 name:$system_name,\r
361                 message:$password_resetted_message,\r
362         };\r
363 \r
364         $rooms.Get(rno).AddRom(ip);\r
365 \r
366         var romcount = $rooms.Get(rno).GetRomCount();\r
367         socket.json.emit("send romcount",romcount);\r
368         socket.json.broadcast.emit("send romcount",romcount);\r
369 \r
370         if($rooms.Get(rno).IsVolatile() == false)\r
371         {\r
372                 if($rooms.Get(rno).IsOwner(msg.name))\r
373                 {\r
374                         $rooms.Get(rno).Reset(null);\r
375                         ParseSendMsg(socket,newMeg);\r
376                 }\r
377                 if(!$rooms.Get(rno).IsFirstAuth() &&\r
378                         !$rooms.Get(rno).IsAuthed(msg.name))\r
379                         return;\r
380                 else\r
381                         $rooms.Get(rno).RemoveAuth(msg.name);\r
382         }\r
383 \r
384         newMeg.message = util.format("/quitedby %s",msg.name);\r
385         ParseSendMsg(socket,newMeg);\r
386 }\r
387 \r
388 //socket 接続中のソケット\r
389 //msg msgクラス\r
390 function ParseSendMsg(socket,msg)\r
391 {\r
392         var ip = GetClientIPAdress(socket);\r
393 \r
394         if(ip in ipbanlist)\r
395         {\r
396                 socket.emit("error",$block_message);\r
397                 return;\r
398         }\r
399 \r
400         var rno = GetRoomNumberFromName(socket.namespace.name);\r
401 \r
402         if(msg.name != $system_name && \r
403                 $rooms.Get(rno).IsVolatile() == false &&\r
404                 !$rooms.Get(rno).IsAuthed(msg.name) &&\r
405                 !$rooms.Get(rno).IsOwner(rno,msg.name))\r
406         {\r
407                 return;\r
408         }\r
409 \r
410         var date = new Date();\r
411 \r
412         var repacked_msg = CreateMessage(msg.name,date,msg.message);\r
413 \r
414         socket.json.emit("req msg", repacked_msg);\r
415 \r
416         socket.json.broadcast.emit("req msg", repacked_msg);\r
417 \r
418         var path = $log_directory + "/" + util.format($log_file_name,rno);\r
419         var log = new ChatLog(path);\r
420         log.Save(repacked_msg,ip,rno);\r
421 }\r
422 \r
423 function GetNameFromRoomNumber(number)\r
424 {\r
425         return "/" + number;\r
426 }\r
427 \r
428 function GetRoomNumberFromName(name)\r
429 {\r
430         if(name.charAt(0) == "/")\r
431                 return parseInt(name.substr(1));\r
432         throw "GetRoomNumberFromName error";\r
433 }\r
434 \r
435 function ParseGetPastLogList(socket,msg)\r
436 {\r
437         var list = fs.readdir($log_directory,function(err,files){\r
438                 var text = "";\r
439                 var rno = GetRoomNumberFromName(socket.namespace.name);\r
440                 var pattern = $pastlogfile_pattern.replace("%d",rno);\r
441                 for(var i = 0; i < files.length; i++)\r
442                 {\r
443                         var logname = files[i];\r
444                         if(logname.match(pattern))\r
445                                 text += files[i] + "\n";\r
446                 }\r
447                 socket.emit("req pastloglist",text);\r
448         });\r
449 }\r
450 \r
451 function ParseGetPastLog(socket,file)\r
452 {\r
453         if(file == "")\r
454                 return;\r
455         var path = $log_directory + "/" + file;\r
456         var log = new ChatLog(path);\r
457         log.ToArray(function(array){\r
458                 socket.json.emit("req pastlog",array);\r
459         });\r
460 }\r
461 \r
462 function ChatLog(path)\r
463 {\r
464         this.ToArray = function(callback)\r
465         {\r
466                 var state = fs.stat(path,function(err,state){\r
467                         if(err)\r
468                                 return;\r
469                         var array = new Array();\r
470                         var stream = fs.createReadStream(path);\r
471                         new lazy(stream)\r
472                                 .lines\r
473                                 .forEach(function(line){\r
474                                         array.push(CreateMessageFromText(line.toString()));\r
475                                 })\r
476                                 .join(function(){\r
477                                         callback(array);\r
478                                 });\r
479                 });\r
480         }\r
481 \r
482         this.Save = function(msg,ip,rno){\r
483                 var text = GetTextFromMessage(msg,ip);\r
484 \r
485                 SplitLog(rno,function(){\r
486                         WritePastLog(path,text);\r
487                 });\r
488         };\r
489 \r
490         function GetTextFromMessage(msg,ip)\r
491         {\r
492                 var text = msg.name + "<>" +\r
493                                 msg.date + "<>" +\r
494                                 ip + "<>" +\r
495                                 msg.message +\r
496                                 "\n";\r
497                 return text;\r
498         }\r
499 \r
500         function SplitLog(rno,callback)\r
501         {\r
502                 var state = fs.stat(path,function(err,state){\r
503                         if(err && typeof(callback) == "function")\r
504                         {\r
505                                 callback();\r
506                                 return;\r
507                         }\r
508                         if(state.size > $spilt_size)\r
509                         {\r
510                                 var date = new Date();\r
511                                 var dateString = ""+date.getFullYear()+date.getMonth()+date.getDate()+date.getHours()+date.getMinutes()+date.getSeconds();\r
512 \r
513                                 var newpath = $log_directory + "/" +\r
514                                         util.format($splited_log_file_name,rno,dateString);\r
515                                 fs.rename(path,newpath,callback);\r
516                         }else{\r
517                                 if(typeof(callback) == "function")\r
518                                         callback();\r
519                         }\r
520                 });\r
521         }\r
522 \r
523         function WritePastLog(path,text)\r
524         {\r
525                 async.waterfall([\r
526                         function(callback){\r
527                                 fs.open(path,"a",callback);\r
528                         },\r
529                         function(fd,callback){\r
530                                 var buf = new Buffer(text);\r
531                                 fs.write(fd,buf,0,Buffer.byteLength(text),null,function(){\r
532                                         callback(null,fd);\r
533                                 });\r
534                         },\r
535                         function(fd){\r
536                                 fs.close(fd);\r
537                         }\r
538                 ]);\r
539         }\r
540 }\r
541 \r
542 function GetClientIPAdress(socket)\r
543 {\r
544         return socket.handshake.headers["x-forwarded-for"] || socket.handshake.address.address;\r
545 }\r
546 \r
547 // Message クラス\r
548 function CreateMessage(name,date,message)\r
549 {\r
550         var result = {name:name,\r
551                 date:date,\r
552                 message:message};\r
553         return result;\r
554 }\r
555 function CreateMessageFromText(text)\r
556 {\r
557         var data = text.split("<>");\r
558         var msg = {name:data[0],\r
559                 date:data[1],\r
560                 message:data[3]};\r
561         return msg;\r
562 }\r
563 \r
564 //RoomInfomationCollecionクラス\r
565 function RoomInfomationCollection()\r
566 {\r
567         var collection = {};\r
568         this.Get = function(rno){\r
569                 return collection[rno];\r
570         }\r
571         this.IsContains = function(rno){\r
572                 return rno in collection;\r
573         };\r
574         this.GetString = function(){\r
575                 var retval = "";\r
576                 for(var rno in collection)\r
577                 {\r
578                         if($rooms.Get(rno).IsVolatile())\r
579                                 continue;\r
580                         var pass = collection[rno].password;\r
581                         if(pass == null)\r
582                                 pass = "";\r
583                         var hiddenlog = collection[rno].hiddenlog;\r
584                         retval += rno + ":" + pass + ":" + hiddenlog + "\r\n";\r
585                 }\r
586                 return retval;\r
587         };\r
588         this.GetKeys = function(){\r
589                 var retval = {};\r
590                 for(var rno in collection)\r
591                 {\r
592                         retval[rno] = {};\r
593                 }\r
594                 return retval;\r
595         }\r
596         this.Update = function(text,callfunc){\r
597                 async.waterfall([\r
598                         function(callback){\r
599                                 fs.open($room_configure_file_name,"w",callback);\r
600                         },\r
601                         function(fd,callback){\r
602                                 var buf = new Buffer(text);\r
603                                 fs.write(fd,buf,0,Buffer.byteLength(text),null,function(){\r
604                                         callback(null,fd);\r
605                                 });\r
606                         },\r
607                         function(fd,callback){\r
608                                 fs.close(fd,function(){\r
609                                         GetRoomList(callfunc);\r
610                                 });\r
611                         }\r
612                 ]);\r
613         }\r
614         function GetRoomList(callback){\r
615                 Clear();\r
616                 path.exists($room_configure_file_name,function(exists){\r
617                         if(exists == false)\r
618                         {\r
619                                 if(typeof(callback) == "function")\r
620                                         callback();\r
621                                 return;\r
622                         }\r
623                         var stream = fs.createReadStream($room_configure_file_name);\r
624                         new lazy(stream)\r
625                                 .lines\r
626                                 .forEach(function(line){\r
627                                         var token = line.toString().replace(/(\r|\n|\r\n)/gm, "").split(":");\r
628                                         if(token.length == 1)\r
629                                         {\r
630                                                 Add(token[0],null,false);\r
631                                         }\r
632                                         else if(token.length == 2)\r
633                                         {\r
634                                                 var rno = token[0];\r
635                                                 var pass = token[1];\r
636                                                 if(pass == "")\r
637                                                         pass = null;\r
638                                                 Add(rno, pass,false);\r
639                                         }\r
640                                         else if(token.length == 3)\r
641                                         {\r
642                                                 var rno = token[0];\r
643                                                 var pass = token[1];\r
644                                                 if(pass == "")\r
645                                                         pass = null;\r
646                                                 var hiddenlog = false;\r
647                                                 if(token[2] == "true")\r
648                                                         hiddenlog = true;\r
649                                                 Add(rno, pass,hiddenlog);\r
650                                         }\r
651                                 })\r
652                                 .join(function(){\r
653                                         if(typeof(callback) == "function")\r
654                                                 callback();\r
655                                 });\r
656                 });\r
657         }\r
658         function Clear(){\r
659                 collection = {};\r
660                 for(var i = 0; i < $max_room_number; i++)\r
661                         Add(i,null,null);\r
662         };\r
663         function Add(rno,pass,hiddenlogflag){\r
664                 collection[rno] = new RoomInfomation(pass,hiddenlogflag);\r
665                 if(pass != null)\r
666                         collection[rno].owner = $system_name;\r
667         };\r
668         var $gc_interval_id = setInterval(function(){\r
669                 for(var rno in this.rom_list)\r
670                         collection[rno].GCRomList();\r
671         },$gc_time_interval);\r
672         GetRoomList();\r
673 }\r
674 \r
675 //RoomInfomationクラス\r
676 function RoomInfomation(pass,hiddenlogflag)\r
677 {\r
678         this.password = pass;\r
679         this.rom_list = {};\r
680         this.authed_list = {};\r
681         this.owner = null;\r
682         this.time = null;\r
683         this.hiddenlog = hiddenlogflag;\r
684         this.IsVolatile = function(){\r
685                 return this.owner == null &&\r
686                         this.password == null &&\r
687                         this.time == null &&\r
688                         this.hiddenlog == null;\r
689         }\r
690         this.GetRomCount = function(){\r
691                 var count = 0;\r
692                 for(var key in this.rom_list)\r
693                         count++;\r
694                 return count;\r
695         };\r
696         this.AddRom = function(ip){\r
697                 var date = new Date();\r
698                 this.rom_list[ip] = {time:date.getTime()};\r
699         };\r
700         this.RemoveRom = function(ip){\r
701                 delete this.rom_list[ip];\r
702         };\r
703         this.Reset = function(owner){\r
704                 var date = new Date();\r
705                 var time = date.getTime();\r
706                 this.password = null;\r
707                 this.authed_list = {};\r
708                 this.owner = owner;\r
709                 this.time = time;\r
710         };\r
711         this.IsFirstAuth = function(){\r
712                 return this.owner == null;\r
713         };\r
714         this.IsAuthed = function(name){\r
715                 return name == this.owner ||\r
716                         name in this.authed_list;\r
717         };\r
718         this.IsHiddenLogFromRom = function(){\r
719                 return this.hiddenlog;\r
720         };\r
721         this.IsFixedPassword = function(){\r
722                 return this.owner == $system_name;\r
723         };\r
724         this.IsOwner = function(name){\r
725                 return this.owner == name;\r
726         };\r
727         this.IsTimeout = function(){\r
728                 var date = new Date();\r
729                 var current_time = date.getTime();\r
730                 return !this.IsFixedPassword() &&\r
731                         current_time - this.time >= $reset_password_diff;\r
732         };\r
733         this.RemoveAuth = function(name)\r
734         {\r
735                 delete this.authed_list[name];\r
736         };\r
737         this.Auth = function(name,password){\r
738                 if(this.password != password)\r
739                         return false;\r
740                 var date = new Date();\r
741                 var time = date.getTime();\r
742                 this.time = time;\r
743                 this.authed_list[name] = "";\r
744                 return true;\r
745         };\r
746         this.SetPassword = function(owner,password){\r
747                 if(owner == this.owner &&\r
748                         !this.IsFixedPassword() &&\r
749                         !this.IsHiddenLogFromRom())\r
750                 {\r
751                         var date = new Date();\r
752                         this.time = date.getTime();\r
753                         this.password = password;\r
754                         return true;\r
755                 }\r
756                 return false;\r
757         };\r
758         this.GCRomList = function(){\r
759                 var date = new Date();\r
760                 var current_time = date.getTime();\r
761                 for(var ip in this.rom_list)\r
762                 {\r
763                         if(current_time - this.rom_list[ip].time >= $gc_time_interval)\r
764                                 delete this.rom_list[ip];\r
765                 }\r
766         };\r
767 }\r
768 \r
769 //IPBANクラス\r
770 function IpBanCollecion()\r
771 {\r
772         var collection = {};\r
773         this.IsBaned = function(ip){\r
774                 return collection[ip] == "r";\r
775         }\r
776         this.IsBlockedToWrite = function(ip){\r
777                 return ip in collection;\r
778         }\r
779         this.GetText = function(){\r
780                 var text = "";\r
781                 for(var key in collection)\r
782                 {\r
783                         if(collection[key] == "")\r
784                                 text += key + "\r\n";\r
785                         else\r
786                                 text += key + ":" + collection[key] + "\r\n";\r
787                 }\r
788                 return text;\r
789         }\r
790         this.Update = function(text,callfunc){\r
791                 async.waterfall([\r
792                         function(callback){\r
793                                 fs.open($ip_ban_list_file_name,"w",callback);\r
794                         },\r
795                         function(fd,callback){\r
796                                 var buf = new Buffer(text);\r
797                                 fs.write(fd,buf,0,Buffer.byteLength(text),null,function(){\r
798                                         callback(null,fd);\r
799                                 });\r
800                         },\r
801                         function(fd,callback){\r
802                                 fs.close(fd,function(){\r
803                                         GetIpBanList(callfunc);\r
804                                 });\r
805                         }\r
806                 ]);\r
807         }\r
808         function GetIpBanList(callback)\r
809         {\r
810                 collection = {};\r
811                 path.exists($ip_ban_list_file_name,function(exists){\r
812                         if(exists == false)\r
813                         {\r
814                                 if(typeof(callback) == "function")\r
815                                         callback();\r
816                                 return;\r
817                         }\r
818                         var stream = fs.createReadStream($ip_ban_list_file_name);\r
819                         new lazy(stream)\r
820                                 .lines\r
821                                 .forEach(function(line){\r
822                                         var token = line.toString().replace(/(\r|\n|\r\n)/gm, "").split(":");\r
823                                         var ip = token[0];\r
824                                         if(token.length == 1)\r
825                                                 collection[ip] = "";\r
826                                         else\r
827                                                 collection[ip] = token[1];\r
828                                 })\r
829                                 .join(function(){\r
830                                         if(typeof(callback) == "function")\r
831                                                 callback();\r
832                                 });\r
833                 });\r
834         }\r
835         GetIpBanList();\r
836 }\r
837 \r