X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=KancolleSniffer%2FLogServer.cs;h=20df04235244a2f8457ee886949c9f7ac5f7a14e;hb=2d4ca31c04161910af09ffaf7e1832ebeffbe246;hp=1c7f3947c2eb50d5e71242754a1c0c8c628626bc;hpb=ce90a32a7f36a3d73a4039b6a25675ffb9eafaa0;p=kancollesniffer%2FKancolleSniffer.git diff --git a/KancolleSniffer/LogServer.cs b/KancolleSniffer/LogServer.cs index 1c7f394..20df042 100644 --- a/KancolleSniffer/LogServer.cs +++ b/KancolleSniffer/LogServer.cs @@ -17,149 +17,97 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; -using System.Net; using System.Net.Sockets; using System.Text; -using System.Threading; -using System.Web; +using System.Text.RegularExpressions; namespace KancolleSniffer { public class LogServer { - private readonly TcpListener _listener; - private readonly string _indexDir = AppDomain.CurrentDomain.BaseDirectory; - private string _outputDir = AppDomain.CurrentDomain.BaseDirectory; - private readonly List _sockets = new List(); + private static readonly string IndexDir = AppDomain.CurrentDomain.BaseDirectory; + private static string _outputDir = AppDomain.CurrentDomain.BaseDirectory; - public int Port { get; private set; } - - public bool IsListening { get; private set; } - - public string OutputDir + public static string OutputDir { - set { _outputDir = value; } + set => _outputDir = value; } - public LogServer(int port) - { - _listener = new TcpListener(IPAddress.Loopback, port); - } + public static MaterialCount[] MaterialHistory { private get; set; } - public void Start() + public static void Process(Socket client, string requestLine) { - _listener.Start(); - Port = ((IPEndPoint)_listener.LocalEndpoint).Port; - IsListening = true; - new Thread(Listen).Start(); - } + var from = DateTime.MinValue; + var to = DateTime.MaxValue; + var timestamp = false; - private void Listen() - { - try + var request = requestLine.Split(' '); + if (request.Length != 3) { - while (true) - { - var socket = _listener.AcceptSocket(); - lock (_sockets) - _sockets.Add(socket); - new Thread(Process).Start(socket); - } + SendError(client, "400 Bad Request"); + return; } - catch (SocketException) + if (!request[0].StartsWith("GET", StringComparison.OrdinalIgnoreCase)) { + SendError(client, "501 Not Implemented"); + return; } - finally + var tmp = request[1].Split('?'); + var path = HttpUtility.UrlDecode(tmp[0]); + if (path == null || !path.StartsWith("/")) { - _listener.Stop(); + SendError(client, "400 Bad Request"); + return; } - } - - private void Process(Object obj) - { - var client = (Socket)obj; - var data = new byte[4096]; - var from = DateTime.MinValue; - var to = DateTime.MaxValue; - try + if (tmp.Length == 2) { - if (client.Receive(data) == 0) - return; - var request = Encoding.UTF8.GetString(data).Split('\r')[0].Split(' '); - if (request.Length != 3) - { - SendError(client, "400 Bad Request"); - return; - } - if (!request[0].StartsWith("GET", StringComparison.OrdinalIgnoreCase)) + var query = HttpUtility.ParseQueryString(tmp[1]); + if (query["from"] != null) { - SendError(client, "501 Not Implemented"); - return; + double.TryParse(query["from"], out var tick); + from = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000); } - var tmp = request[1].Split('?'); - var path = HttpUtility.UrlDecode(tmp[0]); - if (path == null || !path.StartsWith("/")) + if (query["to"] != null) { - SendError(client, "400 Bad Request"); - return; - } - if (tmp.Length == 2) - { - var query = HttpUtility.ParseQueryString(tmp[1]); - if (query["from"] != null) - { - double tick; - double.TryParse(query["from"], out tick); - from = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000); - } - if (query["to"] != null) - { - double tick; - double.TryParse(query["to"], out tick); - to = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000); - } + double.TryParse(query["to"], out var tick); + to = new DateTime(1970, 1, 1).ToLocalTime().AddSeconds(tick / 1000); } + if (query["number"] != null) + timestamp = query["number"] == "true"; + } - path = path == "/" ? "index.html" : path.Substring(1); - var full = Path.Combine(_indexDir, path); - var csv = Path.Combine(_outputDir, path); - if (path.EndsWith(".html", StringComparison.OrdinalIgnoreCase) && File.Exists(full)) - { - SendFile(client, full, "text/html"); - return; - } - if (path.EndsWith(".csv", StringComparison.OrdinalIgnoreCase) && File.Exists(csv)) - { - SendFile(client, csv, "text/csv; charset=Shift_JIS"); - return; - } - if (path.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) - { - SendJsonData(client, csv, from, to); - return; - } - if (path.EndsWith(".js", StringComparison.OrdinalIgnoreCase) && File.Exists(full)) - { - SendFile(client, full, "application/javascript"); - return; - } - SendError(client, "404 Not Found"); + path = path == "/" ? "index.html" : path.Substring(1); + var full = Path.Combine(IndexDir, path); + var csv = Path.Combine(_outputDir, path); + if (path.EndsWith(".html", StringComparison.OrdinalIgnoreCase) && File.Exists(full)) + { + SendFile(client, full, "text/html"); + return; } - catch (IOException) + if (path.EndsWith(".csv", StringComparison.OrdinalIgnoreCase) && File.Exists(csv)) { + SendFile(client, csv, "text/csv; charset=Shift_JIS"); + return; } - catch (SocketException) + if (path.EndsWith(".json", StringComparison.OrdinalIgnoreCase)) { + SendJsonData(client, csv, from, to, timestamp); + return; } - finally + if (path.EndsWith(".js", StringComparison.OrdinalIgnoreCase) && File.Exists(full)) { - lock (_sockets) - _sockets.Remove(client); - client.Close(); + SendFile(client, full, "application/javascript"); + return; } + if (path.EndsWith("proxy.pac")) + { + SendProxyPac(client, HttpProxy.LocalPort); + return; + } + SendError(client, "404 Not Found"); } - private void SendError(Socket client, string error) + private static void SendError(Socket client, string error) { using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII)) { @@ -174,42 +122,103 @@ namespace KancolleSniffer } } - private void SendJsonData(Socket client, string path, DateTime from, DateTime to) + private static void SendJsonData(Socket client, string path, DateTime from, DateTime to, bool number) { - var header = new StreamWriter(new MemoryStream(), Encoding.ASCII); - header.Write("HTTP/1.1 200 OK\r\n"); - header.Write("Server: KancolleSniffer\r\n"); - header.Write("Date: {0:R}\r\n", DateTime.Now); - header.Write("Content-Type: {0}\r\n", "application/json; charset=Shift_JIS"); - header.Write("Connection: close\r\n\r\n"); - header.Flush(); - client.Send(((MemoryStream)header.BaseStream).ToArray()); - + using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII)) + { + header.Write("HTTP/1.1 200 OK\r\n"); + header.Write("Server: KancolleSniffer\r\n"); + header.Write("Date: {0:R}\r\n", DateTime.Now); + header.Write("Content-Type: {0}\r\n", "application/json; charset=Shift_JIS"); + header.Write("Connection: close\r\n\r\n"); + header.Flush(); + client.Send(((MemoryStream)header.BaseStream).ToArray()); + } var csv = path.Replace(".json", ".csv"); var encoding = Encoding.GetEncoding("Shift_JIS"); client.Send(encoding.GetBytes("{ \"data\": [\n")); + var battle = false; + var material = false; try { - if (File.Exists(csv)) + if (!File.Exists(csv)) + return; + var records = 0; + if (path.EndsWith("遠征報告書.json")) + { + records = 10; + } + else if (path.EndsWith("改修報告書.json")) { - var delimiter = ""; - var material = path.EndsWith("資材ログ.json"); // 末尾の空データを削除する必要がある - foreach (var line in File.ReadLines(csv, encoding).Skip(1)) + records = 15; + } + else if (path.EndsWith("海戦・ドロップ報告書.json")) + { + records = 39; + battle = true; + } + else if (path.EndsWith("開発報告書.json")) + { + records = 9; + } + else if (path.EndsWith("建造報告書.json")) + { + records = 12; + } + else if (path.EndsWith("資材ログ.json")) + { + records = 9; + material = true; + } + else if (path.EndsWith("戦果.json")) + { + records = 3; + } + var delimiter = ""; + foreach (var line in File.ReadLines(csv, encoding).Skip(1)) + { + var data = line.Split(','); + if (!DateTime.TryParseExact(data[0], Logger.DateTimeFormat, CultureInfo.InvariantCulture, + DateTimeStyles.AssumeLocal, out DateTime date)) { - var data = line.Split(','); - DateTime date; - if (!DateTime.TryParseExact(data[0], Logger.DateTimeFormat, CultureInfo.InvariantCulture, - DateTimeStyles.AssumeLocal, out date) && - DateTime.TryParse(data[0], CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out date)) + if (DateTime.TryParse(data[0], CultureInfo.CurrentCulture, + DateTimeStyles.AssumeLocal, out date)) { data[0] = date.ToString(Logger.DateTimeFormat); } - if (date < from || to < date) + else + { continue; + } + } + if (date < from || to < date) + continue; + IEnumerable entries = data; + if (material) + entries = data.Take(9); + if (battle) + entries = BattleLogProcessor.Process(data); + if (entries.Count() != records) + continue; + if (number) + { + var stamp = ((date.ToUniversalTime().Ticks - + new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks) / + TimeSpan.TicksPerMillisecond).ToString(); + client.Send(encoding.GetBytes(delimiter + "[" + stamp + "," + + string.Join(",", entries.Skip(1)) + "]")); + } + else + { client.Send(encoding.GetBytes(delimiter + "[\"" + - string.Join("\",\"", (material ? data.Take(9) : data)) + "\"]")); - delimiter = ",\n"; + string.Join("\",\"", entries) + "\"]")); } + delimiter = ",\n"; + } + if (material && !number) + { + client.Send(encoding.GetBytes(delimiter + "[\"" + + string.Join("\",\"", GetCurrentMaterialRecord()) + "\"]")); } } finally @@ -218,28 +227,153 @@ namespace KancolleSniffer } } - private void SendFile(Socket client, string path, string mime) + private static IEnumerable GetCurrentMaterialRecord() { - using (var writer = new StreamWriter(new MemoryStream(), Encoding.ASCII)) + return new[] {DateTime.Now.ToString(Logger.DateTimeFormat)}. + Concat(MaterialHistory.Select(c => c.Now.ToString())); + } + + private static void SendFile(Socket client, string path, string mime) + { + using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII)) { - writer.Write("HTTP/1.1 200 OK\r\n"); - writer.Write("Server: KancolleSniffer\r\n"); - writer.Write("Date: {0:R}\r\n", DateTime.Now); - writer.Write("Content-Length: {0}\r\n", new FileInfo(path).Length); - writer.Write("Content-Type: {0}\r\n", mime); - writer.Write("Connection: close\r\n\r\n"); - writer.Flush(); - client.SendFile(path, ((MemoryStream)writer.BaseStream).ToArray(), null, + header.Write("HTTP/1.1 200 OK\r\n"); + header.Write("Server: KancolleSniffer\r\n"); + header.Write("Date: {0:R}\r\n", DateTime.Now); + header.Write("Content-Length: {0}\r\n", new FileInfo(path).Length); + header.Write("Content-Type: {0}\r\n", mime); + header.Write("Connection: close\r\n\r\n"); + header.Flush(); + client.SendFile(path, ((MemoryStream)header.BaseStream).ToArray(), null, TransmitFileOptions.UseDefaultWorkerThread); } } - public void Stop() + private static void SendProxyPac(Socket client, int port) + { + using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII)) + { + header.Write("HTTP/1.1 200 OK\r\n"); + header.Write("Server: KancolleSniffer\r\n"); + header.Write("Date: {0:R}\r\n", DateTime.Now); + header.Write("Content-Type: application/x-ns-proxy-autoconfig\r\n"); + header.Write("Connection: close\r\n\r\n"); + header.Flush(); + client.Send(((MemoryStream)header.BaseStream).ToArray()); + } + var pacFile = @" +function FindProxyForURL(url, host) { + if(isInNet(host, ""203.104.209.71"", ""255.255.255.255"") || + isInNet(host, ""203.104.209.87"", ""255.255.255.255"") || + isInNet(host, ""125.6.184.16"", ""255.255.255.255"") || + isInNet(host, ""125.6.187.205"", ""255.255.255.255"") || + isInNet(host, ""125.6.187.229"", ""255.255.255.255"") || + isInNet(host, ""203.104.209.134"", ""255.255.255.255"") || + isInNet(host, ""203.104.209.167"", ""255.255.255.255"") || + isInNet(host, ""203.104.248.135"", ""255.255.255.255"") || + isInNet(host, ""125.6.189.7"", ""255.255.255.255"") || + isInNet(host, ""125.6.189.39"", ""255.255.255.255"") || + isInNet(host, ""125.6.189.71"", ""255.255.255.255"") || + isInNet(host, ""125.6.189.103"", ""255.255.255.255"") || + isInNet(host, ""125.6.189.135"", ""255.255.255.255"") || + isInNet(host, ""125.6.189.167"", ""255.255.255.255"") || + isInNet(host, ""125.6.189.215"", ""255.255.255.255"") || + isInNet(host, ""125.6.189.247"", ""255.255.255.255"") || + isInNet(host, ""203.104.209.23"", ""255.255.255.255"") || + isInNet(host, ""203.104.209.39"", ""255.255.255.255"") || + isInNet(host, ""203.104.209.55"", ""255.255.255.255"") || + isInNet(host, ""203.104.209.102"", ""255.255.255.255"")) { + return ""PROXY 127.0.0.1:8080""; + } + else { + return ""DIRECT""; + } +}".Replace("8080", port.ToString()); + client.Send(Encoding.ASCII.GetBytes(pacFile)); + } + } + + public static class BattleLogProcessor + { + public static IEnumerable Process(string[] data) + { + if (data.Length == 35) + data = data.Concat(Enumerable.Repeat("", 3)).ToArray(); + if (data.Length != 38) + return data; + if (data[5] == "T字戦(有利)") + data[5] = "T字有利"; + if (data[5] == "T字戦(不利)") + data[5] = "T字不利"; + if (data[6].EndsWith("航行序列")) + data[6] = data[6].Substring(0, 4); + if (data[7].EndsWith("航行序列")) + data[7] = data[7].Substring(0, 4); + data[37] = ShortenAirBattleResult(data[37]); + return AddDamagedShip(data); + } + + private static string ShortenAirBattleResult(string result) + { + switch (result) + { + case "制空均衡": + return "均衡"; + case "制空権確保": + return "確保"; + case "航空優勢": + return "優勢"; + case "航空劣勢": + return "劣勢"; + case "制空権喪失": + return "喪失"; + default: + return ""; + } + } + + private static IEnumerable AddDamagedShip(string[] data) + { + var damaged = new List(); + for (var i = 11; i < 11 + 12; i += 2) + { + if (data[i] == "") + continue; + var ship = data[i] = StripKana(data[i]); + var hp = data[i + 1]; + try + { + if (ship.Contains("・")) + { + var ships = ship.Split('・'); + var hps = hp.Split('・'); + var nowMax = hps[0].Split('/').Select(int.Parse).ToArray(); + if (ShipStatus.CalcDamage(nowMax[0], nowMax[1]) == ShipStatus.Damage.Badly) + damaged.Add(ships[0]); + nowMax = hps[1].Split('/').Select(int.Parse).ToArray(); + if (ShipStatus.CalcDamage(nowMax[0], nowMax[1]) == ShipStatus.Damage.Badly) + damaged.Add(ships[1]); + } + else + { + var nowMax = hp.Split('/').Select(int.Parse).ToArray(); + if (ShipStatus.CalcDamage(nowMax[0], nowMax[1]) == ShipStatus.Damage.Badly) + damaged.Add(ship); + } + } + catch (FormatException) + { + return data; + } + } + return data.Take(23).Concat(new[] { string.Join("・", damaged) }).Concat(data.Skip(23)); + } + + private static readonly Regex Kana = new Regex(@"\([^)]+\)\(", RegexOptions.Compiled); + + private static string StripKana(string name) { - IsListening = false; - _listener.Server.Close(); - lock (_sockets) - _sockets.ForEach(s => s.Close()); + return Kana.Replace(name, "("); } } } \ No newline at end of file