OSDN Git Service

装備一覧が正しく更新されないのを直す
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / Net / LogServer.cs
1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
2 //\r
3 // Licensed under the Apache License, Version 2.0 (the "License");\r
4 // you may not use this file except in compliance with the License.\r
5 // You may obtain a copy of the License at\r
6 //\r
7 //    http://www.apache.org/licenses/LICENSE-2.0\r
8 //\r
9 // Unless required by applicable law or agreed to in writing, software\r
10 // distributed under the License is distributed on an "AS IS" BASIS,\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
12 // See the License for the specific language governing permissions and\r
13 // limitations under the License.\r
14 \r
15 using System;\r
16 using System.IO;\r
17 using System.Linq;\r
18 using System.Net.Sockets;\r
19 using System.Text;\r
20 using KancolleSniffer.Log;\r
21 using KancolleSniffer.Util;\r
22 \r
23 namespace KancolleSniffer.Net\r
24 {\r
25     public class LogServer\r
26     {\r
27         private static readonly string IndexDir = AppDomain.CurrentDomain.BaseDirectory;\r
28         private static string _outputDir = AppDomain.CurrentDomain.BaseDirectory;\r
29 \r
30         public static string OutputDir\r
31         {\r
32             set => _outputDir = value;\r
33         }\r
34 \r
35         public static LogProcessor LogProcessor { private get; set; }\r
36 \r
37         public static void Process(Socket client, string requestLine)\r
38         {\r
39             var from = DateTime.MinValue;\r
40             var to = DateTime.MaxValue;\r
41             var timestamp = false;\r
42 \r
43             var request = requestLine.Split(' ');\r
44             if (request.Length != 3)\r
45             {\r
46                 SendError(client, "400 Bad Request");\r
47                 return;\r
48             }\r
49             if (!request[0].StartsWith("GET", StringComparison.OrdinalIgnoreCase))\r
50             {\r
51                 SendError(client, "501 Not Implemented");\r
52                 return;\r
53             }\r
54             var tmp = request[1].Split('?');\r
55             var path = HttpUtility.UrlDecode(tmp[0]);\r
56             if (path == null || !path.StartsWith("/"))\r
57             {\r
58                 SendError(client, "400 Bad Request");\r
59                 return;\r
60             }\r
61             if (tmp.Length == 2)\r
62             {\r
63                 var query = HttpUtility.ParseQueryString(tmp[1]);\r
64                 if (query["from"] != null)\r
65                 {\r
66                     double.TryParse(query["from"], out var tick);\r
67                     from = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000);\r
68                 }\r
69                 if (query["to"] != null)\r
70                 {\r
71                     double.TryParse(query["to"], out var tick);\r
72                     to = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000);\r
73                 }\r
74                 if (query["number"] != null)\r
75                     timestamp = query["number"] == "true";\r
76             }\r
77 \r
78             path = path == "/" ? "index.html" : path.Substring(1);\r
79             var full = Path.Combine(IndexDir, path);\r
80             var csv = Path.Combine(_outputDir, path);\r
81             if (path.EndsWith(".html", StringComparison.OrdinalIgnoreCase) && File.Exists(full))\r
82             {\r
83                 SendFile(client, full, "text/html");\r
84                 return;\r
85             }\r
86             if (path.EndsWith(".csv", StringComparison.OrdinalIgnoreCase) && File.Exists(csv))\r
87             {\r
88                 SendFile(client, csv, "text/csv; charset=Shift_JIS");\r
89                 return;\r
90             }\r
91             if (path.EndsWith(".json", StringComparison.OrdinalIgnoreCase))\r
92             {\r
93                 SendJsonData(client, csv, from, to, timestamp);\r
94                 return;\r
95             }\r
96             if (path.EndsWith(".js", StringComparison.OrdinalIgnoreCase) && File.Exists(full))\r
97             {\r
98                 SendFile(client, full, "application/javascript");\r
99                 return;\r
100             }\r
101             if (path.EndsWith(".pac"))\r
102             {\r
103                 SendProxyPac(client, HttpProxy.LocalPort);\r
104                 return;\r
105             }\r
106             if (File.Exists(full))\r
107             {\r
108                 SendFile(client, full, "text/plain");\r
109                 return;\r
110             }\r
111             SendError(client, "404 Not Found");\r
112         }\r
113 \r
114         private static void SendError(Socket client, string error)\r
115         {\r
116             using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
117             {\r
118                 writer.Write("HTTP/1.1 {0}\r\n", error);\r
119                 writer.Write("Server: KancolleSniffer\r\n");\r
120                 writer.Write("Date: {0:R}\r\n", DateTime.Now);\r
121                 writer.Write("Connection: close\r\n\r\n");\r
122                 writer.Write("<html><head><title>{0}</title></head>\r\n", error);\r
123                 writer.Write("<body><h4>{0}</h4></body></html>\r\n\r\n", error);\r
124                 writer.Flush();\r
125                 client.Send(((MemoryStream)writer.BaseStream).ToArray());\r
126             }\r
127         }\r
128 \r
129         private static void SendJsonData(Socket client, string path, DateTime from, DateTime to, bool number)\r
130         {\r
131             using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
132             {\r
133                 header.Write("HTTP/1.1 200 OK\r\n");\r
134                 header.Write("Server: KancolleSniffer\r\n");\r
135                 header.Write("Date: {0:R}\r\n", DateTime.Now);\r
136                 header.Write("Content-Type: {0}\r\n", "application/json; charset=Shift_JIS");\r
137                 header.Write("Connection: close\r\n\r\n");\r
138                 header.Flush();\r
139                 client.Send(((MemoryStream)header.BaseStream).ToArray());\r
140             }\r
141             var csv = path.Replace(".json", ".csv");\r
142             if (!File.Exists(csv))\r
143                 return;\r
144             var encoding = Encoding.GetEncoding("Shift_JIS");\r
145             client.Send(encoding.GetBytes("{ \"data\": [\n"));\r
146             try\r
147             {\r
148                 foreach (var record in LogProcessor.Process(File.ReadLines(csv, encoding).Skip(1), csv, from, to, number))\r
149                     client.Send(encoding.GetBytes(record));\r
150             }\r
151             finally\r
152             {\r
153                 client.Send(encoding.GetBytes("]}\n"));\r
154             }\r
155         }\r
156 \r
157         private static void SendFile(Socket client, string path, string mime)\r
158         {\r
159             using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
160             {\r
161                 header.Write("HTTP/1.1 200 OK\r\n");\r
162                 header.Write("Server: KancolleSniffer\r\n");\r
163                 header.Write("Date: {0:R}\r\n", DateTime.Now);\r
164                 header.Write("Content-Length: {0}\r\n", new FileInfo(path).Length);\r
165                 header.Write("Content-Type: {0}\r\n", mime);\r
166                 header.Write("Connection: close\r\n\r\n");\r
167                 header.Flush();\r
168                 client.SendFile(path, ((MemoryStream)header.BaseStream).ToArray(), null,\r
169                     TransmitFileOptions.UseDefaultWorkerThread);\r
170             }\r
171         }\r
172 \r
173         private static void SendProxyPac(Socket client, int port)\r
174         {\r
175             using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
176             {\r
177                 header.Write("HTTP/1.1 200 OK\r\n");\r
178                 header.Write("Server: KancolleSniffer\r\n");\r
179                 header.Write("Date: {0:R}\r\n", DateTime.Now);\r
180                 header.Write("Content-Type: application/x-ns-proxy-autoconfig\r\n");\r
181                 header.Write("Connection: close\r\n\r\n");\r
182                 header.Flush();\r
183                 client.Send(((MemoryStream)header.BaseStream).ToArray());\r
184             }\r
185             string pacFile;\r
186             try\r
187             {\r
188                 pacFile = File.ReadAllText("proxy.pac").Replace("8080", port.ToString());\r
189             }\r
190             catch\r
191             {\r
192                 pacFile = "";\r
193             }\r
194             client.Send(Encoding.ASCII.GetBytes(pacFile));\r
195         }\r
196     }\r
197 }