OSDN Git Service

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