OSDN Git Service

著作権表示を更新する
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / LogServer.cs
1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.sourceforge.jp>\r
2 //\r
3 // This program is part of KancolleSniffer.\r
4 //\r
5 // KancolleSniffer is free software: you can redistribute it and/or modify\r
6 // it under the terms of the GNU General Public License as published by\r
7 // the Free Software Foundation, either version 3 of the License, or\r
8 // (at your option) any later version.\r
9 //\r
10 // This program is distributed in the hope that it will be useful,\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13 // GNU General Public License for more details.\r
14 //\r
15 // You should have received a copy of the GNU General Public License\r
16 // along with this program; if not, see <http://www.gnu.org/licenses/>.\r
17 \r
18 using System;\r
19 using System.IO;\r
20 using System.Linq;\r
21 using System.Net;\r
22 using System.Net.Sockets;\r
23 using System.Text;\r
24 using System.Threading;\r
25 using System.Web;\r
26 using System.Windows.Forms;\r
27 \r
28 namespace KancolleSniffer\r
29 {\r
30     public class LogServer\r
31     {\r
32         private readonly TcpListener _listener;\r
33         private readonly string _indexDir = Path.GetDirectoryName(Application.ExecutablePath);\r
34         private string _outputDir = Path.GetDirectoryName(Application.ExecutablePath);\r
35 \r
36         public string OutputDir\r
37         {\r
38             set { _outputDir = value; }\r
39         }\r
40 \r
41         public LogServer(int port)\r
42         {\r
43             _listener = new TcpListener(IPAddress.Loopback, port);\r
44         }\r
45 \r
46         public void Start()\r
47         {\r
48             _listener.Start();\r
49             new Thread(Listen).Start();\r
50         }\r
51 \r
52         private void Listen()\r
53         {\r
54             try\r
55             {\r
56                 while (true)\r
57                 {\r
58                     var socket = _listener.AcceptSocket();\r
59                     new Thread(Process).Start(socket);\r
60                 }\r
61             }\r
62             catch (SocketException)\r
63             {\r
64             }\r
65             finally\r
66             {\r
67                 _listener.Stop();\r
68             }\r
69         }\r
70 \r
71         private void Process(Object obj)\r
72         {\r
73             var client = (Socket)obj;\r
74             var data = new byte[4096];\r
75             try\r
76             {\r
77                 if (client.Receive(data) == 0)\r
78                     return;\r
79                 var request = Encoding.UTF8.GetString(data).Split('\r')[0].Split(' ');\r
80                 if (request.Length != 3)\r
81                 {\r
82                     SendError(client, "400 Bad Request");\r
83                     return;\r
84                 }\r
85                 if (!request[0].StartsWith("GET", StringComparison.OrdinalIgnoreCase))\r
86                 {\r
87                     SendError(client, "501 Not Implemented");\r
88                     return;\r
89                 }\r
90                 var path = HttpUtility.UrlDecode(request[1].Split('?')[0]);\r
91                 if (path == null || !path.StartsWith("/"))\r
92                 {\r
93                     SendError(client, "400 Bad Request");\r
94                     return;\r
95                 }\r
96 \r
97                 path = path == "/" ? "index.html" : path.Substring(1);\r
98                 var full = Path.Combine(_indexDir, path);\r
99                 var csv = Path.Combine(_outputDir, path);\r
100                 if (path.EndsWith(".html", StringComparison.OrdinalIgnoreCase) && File.Exists(full))\r
101                 {\r
102                     SendFile(client, full, "text/html");\r
103                     return;\r
104                 }\r
105                 if (path.EndsWith(".csv", StringComparison.OrdinalIgnoreCase) && File.Exists(csv))\r
106                 {\r
107                     SendFile(client, csv, "text/csv; charset=Shift_JIS");\r
108                     return;\r
109                 }\r
110                 if (path.EndsWith(".json", StringComparison.OrdinalIgnoreCase))\r
111                 {\r
112                     SendJsonData(client, csv);\r
113                     return;\r
114                 }\r
115                 if (path.EndsWith(".js", StringComparison.OrdinalIgnoreCase) && File.Exists(full))\r
116                 {\r
117                     SendFile(client, full, "application/javascript");\r
118                     return;\r
119                 }\r
120                 SendError(client, "404 Not Found");\r
121             }\r
122             catch (IOException)\r
123             {\r
124             }\r
125             catch (SocketException)\r
126             {\r
127             }\r
128             finally\r
129             {\r
130                 client.Close();\r
131             }\r
132         }\r
133 \r
134         private void SendError(Socket client, string error)\r
135         {\r
136             using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
137             {\r
138                 writer.Write("HTTP/1.1 {0}\r\n", error);\r
139                 writer.Write("Server: KancolleSniffer\r\n");\r
140                 writer.Write("Date: {0:R}\r\n", DateTime.Now);\r
141                 writer.Write("Connection: close\r\n\r\n");\r
142                 writer.Write("<html><head><title>{0}</title></head>\r\n", error);\r
143                 writer.Write("<body><h4>{0}</h4></body></html>\r\n\r\n", error);\r
144                 writer.Flush();\r
145                 client.Send(((MemoryStream)writer.BaseStream).ToArray());\r
146             }\r
147         }\r
148 \r
149         private void SendJsonData(Socket client, string path)\r
150         {\r
151             var header = new StreamWriter(new MemoryStream(), Encoding.ASCII);\r
152             header.Write("HTTP/1.1 200 OK\r\n");\r
153             header.Write("Server: KancolleSniffer\r\n");\r
154             header.Write("Date: {0:R}\r\n", DateTime.Now);\r
155             header.Write("Content-Type: {0}\r\n", "application/json; charset=Shift_JIS");\r
156             header.Write("Connection: close\r\n\r\n");\r
157             header.Flush();\r
158             client.Send(((MemoryStream)header.BaseStream).ToArray());\r
159 \r
160             var csv = path.Replace(".json", ".csv");\r
161             var encoding = Encoding.GetEncoding("Shift_JIS");\r
162             client.Send(encoding.GetBytes("{ \"data\": [\n"));\r
163             if (File.Exists(csv))\r
164             {\r
165                 var delimiter = "";\r
166                 var material = path.EndsWith("資材ログ.json"); // 末尾の空データを削除する必要がある\r
167                 foreach (var line in File.ReadLines(csv, encoding).Skip(1))\r
168                 {\r
169                     var data = line.Split(',');\r
170                     client.Send(encoding.GetBytes(delimiter + "[\"" + string.Join("\",\"", (material ? data.Take(9) : data)) + "\"]"));\r
171                     delimiter = ",\n";\r
172                 }\r
173             }\r
174             client.Send(encoding.GetBytes("]}\n"));\r
175         }\r
176 \r
177         private void SendFile(Socket client, string path, string mime)\r
178         {\r
179             using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
180             {\r
181                 writer.Write("HTTP/1.1 200 OK\r\n");\r
182                 writer.Write("Server: KancolleSniffer\r\n");\r
183                 writer.Write("Date: {0:R}\r\n", DateTime.Now);\r
184                 writer.Write("Content-Length: {0}\r\n", new FileInfo(path).Length);\r
185                 writer.Write("Content-Type: {0}\r\n", mime);\r
186                 writer.Write("Connection: close\r\n\r\n");\r
187                 writer.Flush();\r
188                 client.SendFile(path, ((MemoryStream)writer.BaseStream).ToArray(), null,\r
189                     TransmitFileOptions.UseDefaultWorkerThread);\r
190             }\r
191         }\r
192 \r
193         public void Stop()\r
194         {\r
195             _listener.Server.Close();\r
196         }\r
197     }\r
198 }