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