OSDN Git Service

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