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