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