OSDN Git Service

ログの処理をLogServerからLogProcessorに分離する
authorKazuhiro Fujieda <fujieda@users.osdn.me>
Tue, 11 Sep 2018 11:12:18 +0000 (20:12 +0900)
committerKazuhiro Fujieda <fujieda@users.osdn.me>
Tue, 11 Sep 2018 11:12:18 +0000 (20:12 +0900)
KancolleSniffer.Test/BattleLogProcessorTest.cs
KancolleSniffer.Test/KancolleSniffer.Test.csproj
KancolleSniffer.Test/LogProcessorTest.cs [new file with mode: 0644]
KancolleSniffer.Test/LoggerTest.cs
KancolleSniffer/KancolleSniffer.csproj
KancolleSniffer/Log/BattleLogProcessor.cs [new file with mode: 0644]
KancolleSniffer/Log/LogProcessor.cs [new file with mode: 0644]
KancolleSniffer/Log/Logger.cs [moved from KancolleSniffer/Logger.cs with 97% similarity]
KancolleSniffer/MainForm.cs
KancolleSniffer/Net/LogServer.cs
KancolleSniffer/Sniffer.cs

index 0cc6718..9511989 100644 (file)
@@ -1,6 +1,20 @@
-using System.Linq;\r
+// Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+//    http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System.Linq;\r
 using ExpressionToCodeLib;\r
-using KancolleSniffer.Net;\r
+using KancolleSniffer.Log;\r
 using Microsoft.VisualStudio.TestTools.UnitTesting;\r
 \r
 namespace KancolleSniffer.Test\r
@@ -27,7 +41,7 @@ namespace KancolleSniffer.Test
             input[15] = "綾波改二(Lv148)";\r
             input[16] = "20/37";\r
             input[37] = "制空権確保";\r
-            var result = BattleLogProcessor.Process(input).ToArray();\r
+            var result = new BattleLogProcessor().Process(input);\r
             PAssert.That(() => result[5] == "T字有利");\r
             PAssert.That(() => result[23] == "龍鳳改(Lv97)・夕立改(Lv148)");\r
             PAssert.That(() => result[38] == "確保");\r
@@ -41,7 +55,7 @@ namespace KancolleSniffer.Test
             input[11] = "龍鳳改(Lv97)・夕立改(Lv148)";\r
             input[12] = "3/48・5/36";\r
             input[37] = "航空劣勢";\r
-            var result = BattleLogProcessor.Process(input).ToArray();\r
+            var result = new BattleLogProcessor().Process(input);\r
             PAssert.That(() => result[6] == "第四警戒");\r
             PAssert.That(() => result[23] == "龍鳳改(Lv97)・夕立改(Lv148)");\r
             PAssert.That(() => result[38] == "劣勢");\r
@@ -55,7 +69,7 @@ namespace KancolleSniffer.Test
             input[12] = "3/48・";\r
             input[13] = "・夕立改(Lv148)";\r
             input[14] = "・5/36";\r
-            var result = BattleLogProcessor.Process(input).ToArray();\r
+            var result = new BattleLogProcessor().Process(input);\r
             PAssert.That(() => result[23] == "龍鳳改(Lv97)・夕立改(Lv148)");\r
         }\r
 \r
@@ -65,7 +79,7 @@ namespace KancolleSniffer.Test
             var input = Enumerable.Repeat("", 38).ToArray();\r
             input[11] = "Luigi Torelli(ルイージ・トレッリ)(Lv7)";\r
             input[12] = "2/11";\r
-            var result = BattleLogProcessor.Process(input).ToArray();\r
+            var result = new BattleLogProcessor().Process(input);\r
             PAssert.That(() => result[11] == "Luigi Torelli(Lv7)");\r
             PAssert.That(() => result[23] == "Luigi Torelli(Lv7)");\r
         }\r
@@ -81,7 +95,7 @@ namespace KancolleSniffer.Test
                 "潜水カ級(flagship)", "0/37", "潜水カ級(elite)", "0/27", "潜水カ級(elite)", "0/27", "", "", "", "", "590", "0",\r
                 "制空権確保"\r
             };\r
-            var result = BattleLogProcessor.Process(input).ToArray();\r
+            var result = new BattleLogProcessor().Process(input);\r
             PAssert.That(() => result[21] == "潮改二(Lv94)・龍驤改二(Lv99)" &&\r
                                result[22] == "33/33・50/50");\r
             PAssert.That(() => result.Length == 39);\r
index db7cd60..1d189b5 100644 (file)
@@ -80,6 +80,7 @@
     <Compile Include="ErrorLogTest.cs" />\r
     <Compile Include="FleetPanelTest.cs" />\r
     <Compile Include="JsonTest.cs" />\r
+    <Compile Include="LogProcessorTest.cs" />\r
     <Compile Include="NotificationManagerTest.cs" />\r
     <Compile Include="QuestInfoTest.cs" />\r
     <Compile Include="ShipLabelTest.cs" />\r
diff --git a/KancolleSniffer.Test/LogProcessorTest.cs b/KancolleSniffer.Test/LogProcessorTest.cs
new file mode 100644 (file)
index 0000000..45bd862
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+//    http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using ExpressionToCodeLib;\r
+using KancolleSniffer.Log;\r
+using KancolleSniffer.Model;\r
+using Microsoft.VisualStudio.TestTools.UnitTesting;\r
+\r
+namespace KancolleSniffer.Test\r
+{\r
+    [TestClass]\r
+    public class LogProcessorTest\r
+    {\r
+        [ClassInitialize]\r
+        public static void Initialize(TestContext context)\r
+        {\r
+            ExpressionToCodeConfiguration.GlobalAssertionConfiguration = ExpressionToCodeConfiguration\r
+                .GlobalAssertionConfiguration.WithPrintedListLengthLimit(200).WithMaximumValueLength(1000);\r
+        }\r
+\r
+        /// <summary>\r
+        /// 遠征報告書は普通にJSONに変換する\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void EnseiLog()\r
+        {\r
+            var processor = new LogProcessor();\r
+            var log = new[]\r
+            {\r
+                "2018-09-10 17:45:09,大成功,北方鼠輸送作戦,589,498,0,0,0,0,0",\r
+                "2018-09-10 17:53:34,成功,長距離練習航海,0,117,34,0,0,1,0"\r
+            };\r
+            var result = processor.Process(log, "遠征報告書.csv", DateTime.MinValue, DateTime.MaxValue, false);\r
+            PAssert.That(() => result.SequenceEqual(new[]\r
+            {\r
+                "[\"2018-09-10 17:45:09\",\"大成功\",\"北方鼠輸送作戦\",\"589\",\"498\",\"0\",\"0\",\"0\",\"0\",\"0\"]",\r
+                ",\n[\"2018-09-10 17:53:34\",\"成功\",\"長距離練習航海\",\"0\",\"117\",\"34\",\"0\",\"0\",\"1\",\"0\"]"\r
+            }));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 資材ログは最後に現在値を示すレコードを追加する\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void MaterialLogWithCurrentRecord()\r
+        {\r
+            var processor = new LogProcessor(new[]\r
+            {\r
+                new MaterialCount {Now = 2001}, new MaterialCount {Now = 2002}, new MaterialCount {Now = 2003},\r
+                new MaterialCount {Now = 2004},\r
+                new MaterialCount {Now = 201}, new MaterialCount {Now = 202}, new MaterialCount {Now = 203},\r
+                new MaterialCount {Now = 100}\r
+            });\r
+            var now = new DateTime(2018, 1, 1);\r
+            var log = "2018-09-10 20:36:34,294892,296784,259518,294588,2484,2975,2550,3";\r
+\r
+            var result = processor.Process(new[] {log}, "資材ログ.csv", DateTime.MinValue, DateTime.MaxValue, false, now)\r
+                .ToArray();\r
+            PAssert.That(() =>\r
+                result[0] ==\r
+                "[\"2018-09-10 20:36:34\",\"294892\",\"296784\",\"259518\",\"294588\",\"2484\",\"2975\",\"2550\",\"3\"]");\r
+            var date = Logger.FormatDateTime(now);\r
+            PAssert.That(() =>\r
+                result[1] ==\r
+                $",\n[\"{date}\",\"2001\",\"2002\",\"2003\",\"2004\",\"201\",\"202\",\"203\",\"100\"]", "現在値");\r
+        }\r
+\r
+        /// <summary>\r
+        /// 資材グラフの描画を高速化するために値をすべて数値にする\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void MaterialLogInNumberType()\r
+        {\r
+            var processor = new LogProcessor();\r
+            var log = "2018-09-10 20:36:34,294892,296784,259518,294588,2484,2975,2550,3";\r
+\r
+            var result = processor.Process(new[] {log}, "資材ログ.csv", DateTime.MinValue, DateTime.MaxValue, true)\r
+                .ToArray();\r
+            PAssert.That(() => result.Length == 1, "現在値の出力なし");\r
+            PAssert.That(() => result[0] == "[1536579394000,294892,296784,259518,294588,2484,2975,2550,3]");\r
+        }\r
+\r
+        /// <summary>\r
+        /// 指定された範囲のログを出力する\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void Range()\r
+        {\r
+            var log = new[]\r
+            {\r
+                "2018-09-09 23:58:35,66023314,0",\r
+                "2018-09-10 08:08:31,66023314,0",\r
+                "2018-09-10 11:03:01,66024154,0"\r
+            };\r
+            var processor = new LogProcessor();\r
+            Func<DateTime, DateTime, IEnumerable<string>> rangeProcessor =\r
+                (from, to) => processor.Process(log, "戦果.csv", from, to, false);\r
+\r
+            PAssert.That(\r
+                () => rangeProcessor(DateTime.MinValue, DateTime.MaxValue).SequenceEqual(new[]\r
+                {\r
+                    "[\"2018-09-09 23:58:35\",\"66023314\",\"0\"]",\r
+                    ",\n[\"2018-09-10 08:08:31\",\"66023314\",\"0\"]",\r
+                    ",\n[\"2018-09-10 11:03:01\",\"66024154\",\"0\"]"\r
+                }));\r
+            PAssert.That(\r
+                () => rangeProcessor(DateTime.MinValue, new DateTime(2018, 9, 10)).SequenceEqual(new[]\r
+                    {"[\"2018-09-09 23:58:35\",\"66023314\",\"0\"]"}\r
+                ));\r
+            PAssert.That(\r
+                () => rangeProcessor(new DateTime(2018, 9, 10), DateTime.MaxValue).SequenceEqual(new[]\r
+                {\r
+                    "[\"2018-09-10 08:08:31\",\"66023314\",\"0\"]",\r
+                    ",\n[\"2018-09-10 11:03:01\",\"66024154\",\"0\"]"\r
+                }));\r
+            PAssert.That(\r
+                () => rangeProcessor(new DateTime(2018, 9, 10), new DateTime(2018, 9, 10, 11, 0, 0)).SequenceEqual(new[]\r
+                {\r
+                    "[\"2018-09-10 08:08:31\",\"66023314\",\"0\"]"\r
+                }));\r
+        }\r
+\r
+        /// <summary>\r
+        /// 想定と異なる日付フォーマットに対応する。\r
+        /// </summary>\r
+        [TestMethod]\r
+        public void DateFormat()\r
+        {\r
+            var processor = new LogProcessor();\r
+\r
+            var body = ",大型艦建造,まるゆ,潜水艦,1500,1500,2000,1000,1,0,瑞鶴改二甲(163),120";\r
+            var expected =\r
+                ",\"大型艦建造\",\"まるゆ\",\"潜水艦\",\"1500\",\"1500\",\"2000\",\"1000\",\"1\",\"0\",\"瑞鶴改二甲(163)\",\"120\"]";\r
+\r
+            Func<string, string> dateProcessor =\r
+                date => processor.Process(new[] {date + body}, "建造報告書", DateTime.MinValue, DateTime.MaxValue, false)\r
+                    .First();\r
+            var era = "30-09-10 20:13:39";\r
+            PAssert.That(() => "[\"2018-09-10 20:13:39\"" + expected == dateProcessor(era), "和暦を西暦に直す");\r
+            var excel = "2018/9/10 20:13";\r
+            PAssert.That(() => "[\"2018-09-10 20:13:00\"" + expected == dateProcessor(excel), "Excelの形式から変換する");\r
+        }\r
+    }\r
+}
\ No newline at end of file
index 15fd616..24946ee 100644 (file)
@@ -16,6 +16,7 @@ using System;
 using System.Collections.Generic;\r
 using System.IO;\r
 using ExpressionToCodeLib;\r
+using KancolleSniffer.Log;\r
 using KancolleSniffer.Util;\r
 using Microsoft.VisualStudio.TestTools.UnitTesting;\r
 using Moq;\r
index 7921ee5..49cec61 100644 (file)
@@ -54,6 +54,7 @@
     <Reference Include="System.Xml" />\r
   </ItemGroup>\r
   <ItemGroup>\r
+    <Compile Include="Log\LogProcessor.cs" />\r
     <Compile Include="Model\Achievement.cs" />\r
     <Compile Include="Model\AkashiTimer.cs" />\r
     <Compile Include="Model\AlarmCounter.cs" />\r
@@ -63,6 +64,7 @@
     <Compile Include="Model\ItemSpec.cs" />\r
     <Compile Include="Model\ItemStatus.cs" />\r
     <Compile Include="Model\ShipSpec.cs" />\r
+    <Compile Include="Log\BattleLogProcessor.cs" />\r
     <Compile Include="View\AntiAirPanel.cs">\r
       <SubType>Component</SubType>\r
     </Compile>\r
       <SubType>Component</SubType>\r
     </Compile>\r
     <Compile Include="Util\JsonParser.cs" />\r
-    <Compile Include="Logger.cs" />\r
+    <Compile Include="Log\Logger.cs" />\r
     <Compile Include="Net\LogServer.cs" />\r
     <Compile Include="Model\MaterialInfo.cs" />\r
     <Compile Include="Model\MiscTextInfo.cs" />\r
diff --git a/KancolleSniffer/Log/BattleLogProcessor.cs b/KancolleSniffer/Log/BattleLogProcessor.cs
new file mode 100644 (file)
index 0000000..6bcfe4f
--- /dev/null
@@ -0,0 +1,101 @@
+// Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+//    http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Linq;\r
+using System.Text.RegularExpressions;\r
+using KancolleSniffer.Model;\r
+\r
+namespace KancolleSniffer.Log\r
+{\r
+    public class BattleLogProcessor\r
+    {\r
+        public string[] Process(string[] data)\r
+        {\r
+            if (data.Length == 35)\r
+                data = data.Concat(Enumerable.Repeat("", 3)).ToArray();\r
+            if (data.Length == 40)\r
+            {\r
+                data = data.Take(21).Concat(new[] {data[21] + "・" + data[23], data[22] + "・" + data[24]})\r
+                    .Concat(data.Skip(25)).ToArray();\r
+            }\r
+            else if (data.Length != 38)\r
+            {\r
+                return data;\r
+            }\r
+            if (data[5] == "T字戦(有利)")\r
+                data[5] = "T字有利";\r
+            if (data[5] == "T字戦(不利)")\r
+                data[5] = "T字不利";\r
+            if (data[6].EndsWith("航行序列"))\r
+                data[6] = data[6].Substring(0, 4);\r
+            if (data[7].EndsWith("航行序列"))\r
+                data[7] = data[7].Substring(0, 4);\r
+            data[37] = ShortenAirBattleResult(data[37]);\r
+            return AddDamagedShip(data);\r
+        }\r
+\r
+        private static string ShortenAirBattleResult(string result)\r
+        {\r
+            switch (result)\r
+            {\r
+                case "制空均衡":\r
+                    return "均衡";\r
+                case "制空権確保":\r
+                    return "確保";\r
+                case "航空優勢":\r
+                    return "優勢";\r
+                case "航空劣勢":\r
+                    return "劣勢";\r
+                case "制空権喪失":\r
+                    return "喪失";\r
+                default:\r
+                    return "";\r
+            }\r
+        }\r
+\r
+        private static string[] AddDamagedShip(string[] data)\r
+        {\r
+            var damaged = new List<string>();\r
+            for (var i = 11; i < 11 + 12; i += 2)\r
+            {\r
+                if (data[i] == "")\r
+                    continue;\r
+                var ship = data[i] = StripKana(data[i]);\r
+                var hp = data[i + 1];\r
+                try\r
+                {\r
+                    damaged.AddRange(from entry in ship.Split('・').Zip(hp.Split('・'), (s, h) => new {s, h})\r
+                        where entry.h.Contains("/")\r
+                        let nm = entry.h.Split('/').Select(int.Parse).ToArray()\r
+                        where ShipStatus.CalcDamage(nm[0], nm[1]) == ShipStatus.Damage.Badly\r
+                        select entry.s);\r
+                }\r
+                catch (FormatException)\r
+                {\r
+                    return data;\r
+                }\r
+            }\r
+            return data.Take(23).Concat(new[] {string.Join("・", damaged)}).Concat(data.Skip(23)).ToArray();\r
+        }\r
+\r
+        private static readonly Regex Kana = new Regex(@"\([^)]+\)\(", RegexOptions.Compiled);\r
+\r
+        private static string StripKana(string name)\r
+        {\r
+            return Kana.Replace(name, "(");\r
+        }\r
+    }\r
+}
\ No newline at end of file
diff --git a/KancolleSniffer/Log/LogProcessor.cs b/KancolleSniffer/Log/LogProcessor.cs
new file mode 100644 (file)
index 0000000..583c8d5
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright (C) 2018 Kazuhiro Fujieda <fujieda@users.osdn.me>\r
+//\r
+// Licensed under the Apache License, Version 2.0 (the "License");\r
+// you may not use this file except in compliance with the License.\r
+// You may obtain a copy of the License at\r
+//\r
+//    http://www.apache.org/licenses/LICENSE-2.0\r
+//\r
+// Unless required by applicable law or agreed to in writing, software\r
+// distributed under the License is distributed on an "AS IS" BASIS,\r
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+// See the License for the specific language governing permissions and\r
+// limitations under the License.\r
+\r
+using System;\r
+using System.Collections.Generic;\r
+using System.Globalization;\r
+using System.IO;\r
+using System.Linq;\r
+using KancolleSniffer.Model;\r
+\r
+namespace KancolleSniffer.Log\r
+{\r
+    public class LogProcessor\r
+    {\r
+        private readonly MaterialCount[] _materialCount;\r
+        private readonly BattleLogProcessor _battleLogProcessor;\r
+\r
+        public LogProcessor(MaterialCount[] materialCount = null)\r
+        {\r
+            _materialCount = materialCount ?? new MaterialCount[0];\r
+            _battleLogProcessor = new BattleLogProcessor();\r
+        }\r
+\r
+        public IEnumerable<string> Process(IEnumerable<string> lines, string path, DateTime from, DateTime to,\r
+            bool number, DateTime now = default)\r
+        {\r
+            var fields = 0;\r
+            var battle = false;\r
+            var material = false;\r
+            switch (Path.GetFileNameWithoutExtension(path))\r
+            {\r
+                case "遠征報告書":\r
+                    fields = 10;\r
+                    break;\r
+                case "改修報告書":\r
+                    fields = 15;\r
+                    break;\r
+                case "海戦・ドロップ報告書":\r
+                    fields = 39;\r
+                    battle = true;\r
+                    break;\r
+                case "開発報告書":\r
+                    fields = 9;\r
+                    break;\r
+                case "建造報告書":\r
+                    fields = 12;\r
+                    break;\r
+                case "資材ログ":\r
+                    fields = 9;\r
+                    material = true;\r
+                    break;\r
+                case "戦果":\r
+                    fields = 3;\r
+                    break;\r
+            }\r
+            var delimiter = "";\r
+            foreach (var line in lines)\r
+            {\r
+                var data = line.Split(',');\r
+                var date = ParseDateTime(data[0]);\r
+                if (date == default)\r
+                    continue;\r
+                if (to < date)\r
+                    yield break;\r
+                if (date < from)\r
+                    continue;\r
+                data[0] = Logger.FormatDateTime(date);\r
+                var entries = data;\r
+                if (material)\r
+                    entries = data.Take(fields).ToArray();\r
+                if (battle)\r
+                    entries = _battleLogProcessor.Process(data);\r
+                if (entries.Length != fields)\r
+                    continue;\r
+                var result =\r
+                    number\r
+                        ? delimiter + "[" + JavaScriptTicks(date) + "," + string.Join(",", entries.Skip(1)) + "]"\r
+                        : delimiter + "[\"" + string.Join("\",\"", entries) + "\"]";\r
+                delimiter = ",\n";\r
+                yield return result;\r
+            }\r
+            if (material && !number) // 資材の現在値を出力する\r
+                yield return delimiter + "[\"" + Logger.FormatDateTime(now) + "\",\"" +\r
+                             string.Join("\",\"", _materialCount.Select(c => c.Now)) + "\"]";\r
+        }\r
+\r
+        private DateTime ParseDateTime(string dateTime)\r
+        {\r
+            if (DateTime.TryParseExact(dateTime, Logger.DateTimeFormat, CultureInfo.InvariantCulture,\r
+                DateTimeStyles.AssumeLocal, out var date))\r
+            {\r
+                return date;\r
+            }\r
+            // システムが和暦に設定されていて和暦が出力されてしまったケースを救う\r
+            if (dateTime[2] == '-')\r
+            {\r
+                if (!int.TryParse(dateTime.Substring(0, 2), out var year))\r
+                    return default;\r
+                dateTime = 1988 + year + dateTime.Substring(2);\r
+                return DateTime.TryParseExact(dateTime, Logger.DateTimeFormat, CultureInfo.InvariantCulture,\r
+                    DateTimeStyles.AssumeLocal, out date)\r
+                    ? date\r
+                    : default;\r
+            }\r
+            return DateTime.TryParse(dateTime, CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out date)\r
+                ? date\r
+                : default;\r
+        }\r
+\r
+        private long JavaScriptTicks(DateTime date) =>\r
+            (date.ToUniversalTime().Ticks - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks) /\r
+            TimeSpan.TicksPerMillisecond;\r
+    }\r
+}
\ No newline at end of file
similarity index 97%
rename from KancolleSniffer/Logger.cs
rename to KancolleSniffer/Log/Logger.cs
index 31a0e4b..fdac753 100644 (file)
@@ -21,7 +21,7 @@ using System.Text;
 using KancolleSniffer.Model;\r
 using KancolleSniffer.Util;\r
 \r
-namespace KancolleSniffer\r
+namespace KancolleSniffer.Log\r
 {\r
     [Flags]\r
     public enum LogType\r
index 0581fb1..b50e133 100644 (file)
@@ -26,6 +26,7 @@ using System.Text;
 using System.Text.RegularExpressions;\r
 using System.Threading.Tasks;\r
 using System.Windows.Forms;\r
+using KancolleSniffer.Log;\r
 using KancolleSniffer.Model;\r
 using KancolleSniffer.Net;\r
 using KancolleSniffer.Util;\r
@@ -449,7 +450,7 @@ namespace KancolleSniffer
         public void ApplyLogSetting()\r
         {\r
             LogServer.OutputDir = _config.Log.OutputDir;\r
-            LogServer.MaterialHistory = _sniffer.Material.MaterialHistory;\r
+            LogServer.LogProcessor = new LogProcessor(_sniffer.Material.MaterialHistory);\r
             _sniffer.EnableLog(_config.Log.On ? LogType.All : LogType.None);\r
             _sniffer.MaterialLogInterval = _config.Log.MaterialLogInterval;\r
             _sniffer.LogOutputDir = _config.Log.OutputDir;\r
index 3212ebe..56242d1 100644 (file)
 // limitations under the License.\r
 \r
 using System;\r
-using System.Collections.Generic;\r
-using System.Globalization;\r
 using System.IO;\r
 using System.Linq;\r
 using System.Net.Sockets;\r
 using System.Text;\r
-using System.Text.RegularExpressions;\r
-using KancolleSniffer.Model;\r
+using KancolleSniffer.Log;\r
 using KancolleSniffer.Util;\r
 \r
 namespace KancolleSniffer.Net\r
@@ -35,7 +32,7 @@ namespace KancolleSniffer.Net
             set => _outputDir = value;\r
         }\r
 \r
-        public static MaterialCount[] MaterialHistory { private get; set; }\r
+        public static LogProcessor LogProcessor { private get; set; }\r
 \r
         public static void Process(Socket client, string requestLine)\r
         {\r
@@ -142,101 +139,14 @@ namespace KancolleSniffer.Net
                 client.Send(((MemoryStream)header.BaseStream).ToArray());\r
             }\r
             var csv = path.Replace(".json", ".csv");\r
+            if (!File.Exists(csv))\r
+                return;\r
             var encoding = Encoding.GetEncoding("Shift_JIS");\r
             client.Send(encoding.GetBytes("{ \"data\": [\n"));\r
-            var battle = false;\r
-            var material = false;\r
             try\r
             {\r
-                if (!File.Exists(csv))\r
-                    return;\r
-                var records = 0;\r
-                if (path.EndsWith("遠征報告書.json"))\r
-                {\r
-                    records = 10;\r
-                }\r
-                else if (path.EndsWith("改修報告書.json"))\r
-                {\r
-                    records = 15;\r
-                }\r
-                else if (path.EndsWith("海戦・ドロップ報告書.json"))\r
-                {\r
-                    records = 39;\r
-                    battle = true;\r
-                }\r
-                else if (path.EndsWith("開発報告書.json"))\r
-                {\r
-                    records = 9;\r
-                }\r
-                else if (path.EndsWith("建造報告書.json"))\r
-                {\r
-                    records = 12;\r
-                }\r
-                else if (path.EndsWith("資材ログ.json"))\r
-                {\r
-                    records = 9;\r
-                    material = true;\r
-                }\r
-                else if (path.EndsWith("戦果.json"))\r
-                {\r
-                    records = 3;\r
-                }\r
-                var delimiter = "";\r
-                foreach (var line in File.ReadLines(csv, encoding).Skip(1))\r
-                {\r
-                    var data = line.Split(',');\r
-                    if (!DateTime.TryParseExact(data[0], Logger.DateTimeFormat, CultureInfo.InvariantCulture,\r
-                        DateTimeStyles.AssumeLocal, out var date))\r
-                    {\r
-                        // システムが和暦に設定されていて和暦が出力されてしまったケースを救う\r
-                        if (data[0][2] == '-')\r
-                        {\r
-                            if (!int.TryParse(data[0].Substring(0, 2), out var year))\r
-                                continue;\r
-                            data[0] = 1988 + year + data[0].Substring(2);\r
-                            if (!DateTime.TryParseExact(data[0], Logger.DateTimeFormat, CultureInfo.InvariantCulture,\r
-                                DateTimeStyles.AssumeLocal, out date))\r
-                                continue;\r
-                        }\r
-                        else if (DateTime.TryParse(data[0], CultureInfo.CurrentCulture,\r
-                            DateTimeStyles.AssumeLocal, out date))\r
-                        {\r
-                            data[0] = Logger.FormatDateTime(date);\r
-                        }\r
-                        else\r
-                        {\r
-                            continue;\r
-                        }\r
-                    }\r
-                    if (date < from || to < date)\r
-                        continue;\r
-                    IEnumerable<string> entries = data;\r
-                    if (material)\r
-                        entries = data.Take(9);\r
-                    if (battle)\r
-                        entries = BattleLogProcessor.Process(data);\r
-                    if (entries.Count() != records)\r
-                        continue;\r
-                    if (number)\r
-                    {\r
-                        var stamp = ((date.ToUniversalTime().Ticks -\r
-                                      new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).Ticks) /\r
-                                     TimeSpan.TicksPerMillisecond).ToString();\r
-                        client.Send(encoding.GetBytes(delimiter + "[" + stamp + "," +\r
-                                                      string.Join(",", entries.Skip(1)) + "]"));\r
-                    }\r
-                    else\r
-                    {\r
-                        client.Send(encoding.GetBytes(delimiter + "[\"" +\r
-                                                      string.Join("\",\"", entries) + "\"]"));\r
-                    }\r
-                    delimiter = ",\n";\r
-                }\r
-                if (material && !number)\r
-                {\r
-                    client.Send(encoding.GetBytes(delimiter + "[\"" +\r
-                                                  string.Join("\",\"", GetCurrentMaterialRecord()) + "\"]"));\r
-                }\r
+                foreach (var record in LogProcessor.Process(File.ReadLines(csv, encoding).Skip(1), csv, from, to, number))\r
+                    client.Send(encoding.GetBytes(record));\r
             }\r
             finally\r
             {\r
@@ -244,11 +154,6 @@ namespace KancolleSniffer.Net
             }\r
         }\r
 \r
-        private static IEnumerable<string> GetCurrentMaterialRecord()\r
-        {\r
-            return new[] {Logger.FormatDateTime(DateTime.Now)}.Concat(MaterialHistory.Select(c => c.Now.ToString()));\r
-        }\r
-\r
         private static void SendFile(Socket client, string path, string mime)\r
         {\r
             using (var header = new StreamWriter(new MemoryStream(), Encoding.ASCII))\r
@@ -289,83 +194,4 @@ namespace KancolleSniffer.Net
             client.Send(Encoding.ASCII.GetBytes(pacFile));\r
         }\r
     }\r
-\r
-    public static class BattleLogProcessor\r
-    {\r
-        public static IEnumerable<string> Process(string[] data)\r
-        {\r
-            if (data.Length == 35)\r
-                data = data.Concat(Enumerable.Repeat("", 3)).ToArray();\r
-            if (data.Length == 40)\r
-            {\r
-                data = data.Take(21).Concat(new[] {data[21] + "・" + data[23], data[22] + "・" + data[24]})\r
-                    .Concat(data.Skip(25)).ToArray();\r
-            }\r
-            else if (data.Length != 38)\r
-            {\r
-                return data;\r
-            }\r
-            if (data[5] == "T字戦(有利)")\r
-                data[5] = "T字有利";\r
-            if (data[5] == "T字戦(不利)")\r
-                data[5] = "T字不利";\r
-            if (data[6].EndsWith("航行序列"))\r
-                data[6] = data[6].Substring(0, 4);\r
-            if (data[7].EndsWith("航行序列"))\r
-                data[7] = data[7].Substring(0, 4);\r
-            data[37] = ShortenAirBattleResult(data[37]);\r
-            return AddDamagedShip(data);\r
-        }\r
-\r
-        private static string ShortenAirBattleResult(string result)\r
-        {\r
-            switch (result)\r
-            {\r
-                case "制空均衡":\r
-                    return "均衡";\r
-                case "制空権確保":\r
-                    return "確保";\r
-                case "航空優勢":\r
-                    return "優勢";\r
-                case "航空劣勢":\r
-                    return "劣勢";\r
-                case "制空権喪失":\r
-                    return "喪失";\r
-                default:\r
-                    return "";\r
-            }\r
-        }\r
-\r
-        private static IEnumerable<string> AddDamagedShip(string[] data)\r
-        {\r
-            var damaged = new List<string>();\r
-            for (var i = 11; i < 11 + 12; i += 2)\r
-            {\r
-                if (data[i] == "")\r
-                    continue;\r
-                var ship = data[i] = StripKana(data[i]);\r
-                var hp = data[i + 1];\r
-                try\r
-                {\r
-                    damaged.AddRange(from entry in ship.Split('・').Zip(hp.Split('・'), (s, h) => new {s, h})\r
-                        where entry.h.Contains("/")\r
-                        let nm = entry.h.Split('/').Select(int.Parse).ToArray()\r
-                        where ShipStatus.CalcDamage(nm[0], nm[1]) == ShipStatus.Damage.Badly\r
-                        select entry.s);\r
-                }\r
-                catch (FormatException)\r
-                {\r
-                    return data;\r
-                }\r
-            }\r
-            return data.Take(23).Concat(new[] {string.Join("・", damaged)}).Concat(data.Skip(23));\r
-        }\r
-\r
-        private static readonly Regex Kana = new Regex(@"\([^)]+\)\(", RegexOptions.Compiled);\r
-\r
-        private static string StripKana(string name)\r
-        {\r
-            return Kana.Replace(name, "(");\r
-        }\r
-    }\r
 }
\ No newline at end of file
index 4652085..b65f706 100644 (file)
@@ -16,6 +16,7 @@ using System;
 using KancolleSniffer.Util;\r
 using System.Collections.Generic;\r
 using System.Linq;\r
+using KancolleSniffer.Log;\r
 using KancolleSniffer.Model;\r
 \r
 namespace KancolleSniffer\r