1 // Copyright (C) 2014, 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>
\r
3 // This program is part of KancolleSniffer.
\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
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
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
19 using System.Globalization;
\r
23 using System.Net.Sockets;
\r
25 using System.Threading;
\r
27 using System.Windows.Forms;
\r
29 namespace KancolleSniffer
\r
31 public class LogServer
\r
33 private readonly TcpListener _listener;
\r
34 private readonly string _indexDir = Path.GetDirectoryName(Application.ExecutablePath);
\r
35 private string _outputDir = Path.GetDirectoryName(Application.ExecutablePath);
\r
37 public int Port { get; private set; }
\r
39 public bool IsListening { get; private set; }
\r
41 public string OutputDir
\r
43 set { _outputDir = value; }
\r
46 public LogServer(int port)
\r
48 _listener = new TcpListener(IPAddress.Loopback, port);
\r
54 Port = ((IPEndPoint)_listener.LocalEndpoint).Port;
\r
56 new Thread(Listen).Start();
\r
59 private void Listen()
\r
65 var socket = _listener.AcceptSocket();
\r
66 new Thread(Process).Start(socket);
\r
69 catch (SocketException)
\r
78 private void Process(Object obj)
\r
80 var client = (Socket)obj;
\r
81 var data = new byte[4096];
\r
82 var from = DateTime.MinValue;
\r
83 var to = DateTime.MaxValue;
\r
86 if (client.Receive(data) == 0)
\r
88 var request = Encoding.UTF8.GetString(data).Split('\r')[0].Split(' ');
\r
89 if (request.Length != 3)
\r
91 SendError(client, "400 Bad Request");
\r
94 if (!request[0].StartsWith("GET", StringComparison.OrdinalIgnoreCase))
\r
96 SendError(client, "501 Not Implemented");
\r
99 var tmp = request[1].Split('?');
\r
100 var path = HttpUtility.UrlDecode(tmp[0]);
\r
101 if (path == null || !path.StartsWith("/"))
\r
103 SendError(client, "400 Bad Request");
\r
106 if (tmp.Length == 2)
\r
108 var query = HttpUtility.ParseQueryString(tmp[1]);
\r
109 if (query["from"] != null)
\r
112 double.TryParse(query["from"], out tick);
\r
113 from = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000);
\r
115 if (query["to"] != null)
\r
118 double.TryParse(query["to"], out tick);
\r
119 to = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000);
\r
123 path = path == "/" ? "index.html" : path.Substring(1);
\r
124 var full = Path.Combine(_indexDir, path);
\r
125 var csv = Path.Combine(_outputDir, path);
\r
126 if (path.EndsWith(".html", StringComparison.OrdinalIgnoreCase) && File.Exists(full))
\r
128 SendFile(client, full, "text/html");
\r
131 if (path.EndsWith(".csv", StringComparison.OrdinalIgnoreCase) && File.Exists(csv))
\r
133 SendFile(client, csv, "text/csv; charset=Shift_JIS");
\r
136 if (path.EndsWith(".json", StringComparison.OrdinalIgnoreCase))
\r
138 SendJsonData(client, csv, from, to);
\r
141 if (path.EndsWith(".js", StringComparison.OrdinalIgnoreCase) && File.Exists(full))
\r
143 SendFile(client, full, "application/javascript");
\r
146 SendError(client, "404 Not Found");
\r
148 catch (IOException)
\r
151 catch (SocketException)
\r
160 private void SendError(Socket client, string error)
\r
162 using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
164 writer.Write("HTTP/1.1 {0}\r\n", error);
\r
165 writer.Write("Server: KancolleSniffer\r\n");
\r
166 writer.Write("Date: {0:R}\r\n", DateTime.Now);
\r
167 writer.Write("Connection: close\r\n\r\n");
\r
168 writer.Write("<html><head><title>{0}</title></head>\r\n", error);
\r
169 writer.Write("<body><h4>{0}</h4></body></html>\r\n\r\n", error);
\r
171 client.Send(((MemoryStream)writer.BaseStream).ToArray());
\r
175 private void SendJsonData(Socket client, string path, DateTime from, DateTime to)
\r
177 var header = new StreamWriter(new MemoryStream(), Encoding.ASCII);
\r
178 header.Write("HTTP/1.1 200 OK\r\n");
\r
179 header.Write("Server: KancolleSniffer\r\n");
\r
180 header.Write("Date: {0:R}\r\n", DateTime.Now);
\r
181 header.Write("Content-Type: {0}\r\n", "application/json; charset=Shift_JIS");
\r
182 header.Write("Connection: close\r\n\r\n");
\r
184 client.Send(((MemoryStream)header.BaseStream).ToArray());
\r
186 var csv = path.Replace(".json", ".csv");
\r
187 var encoding = Encoding.GetEncoding("Shift_JIS");
\r
188 client.Send(encoding.GetBytes("{ \"data\": [\n"));
\r
191 if (File.Exists(csv))
\r
193 var delimiter = "";
\r
194 var material = path.EndsWith("資材ログ.json"); // 末尾の空データを削除する必要がある
\r
195 foreach (var line in File.ReadLines(csv, encoding).Skip(1))
\r
197 var data = line.Split(',');
\r
199 if (!DateTime.TryParseExact(data[0], Logger.DateTimeFormat, CultureInfo.InvariantCulture,
\r
200 DateTimeStyles.AssumeLocal, out date) &&
\r
201 DateTime.TryParse(data[0], CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out date))
\r
203 data[0] = date.ToString(Logger.DateTimeFormat);
\r
205 if (date < from || to < date)
\r
207 client.Send(encoding.GetBytes(delimiter + "[\"" +
\r
208 string.Join("\",\"", (material ? data.Take(9) : data)) + "\"]"));
\r
215 client.Send(encoding.GetBytes("]}\n"));
\r
219 private void SendFile(Socket client, string path, string mime)
\r
221 using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII))
\r
223 writer.Write("HTTP/1.1 200 OK\r\n");
\r
224 writer.Write("Server: KancolleSniffer\r\n");
\r
225 writer.Write("Date: {0:R}\r\n", DateTime.Now);
\r
226 writer.Write("Content-Length: {0}\r\n", new FileInfo(path).Length);
\r
227 writer.Write("Content-Type: {0}\r\n", mime);
\r
228 writer.Write("Connection: close\r\n\r\n");
\r
230 client.SendFile(path, ((MemoryStream)writer.BaseStream).ToArray(), null,
\r
231 TransmitFileOptions.UseDefaultWorkerThread);
\r
237 IsListening = false;
\r
238 _listener.Server.Close();
\r