OSDN Git Service

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