OSDN Git Service

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