OSDN Git Service

135ca6bd84aaa8c784f5cb6c76bdbac74e11edbc
[kancollesniffer/KancolleSniffer.git] / KancolleSniffer / ErrorLog.cs
1 // Copyright (C) 2017 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.Collections.Generic;\r
17 using System.IO;\r
18 using System.IO.Compression;\r
19 using System.Linq;\r
20 using System.Text;\r
21 using System.Text.RegularExpressions;\r
22 using System.Windows.Forms;\r
23 \r
24 namespace KancolleSniffer\r
25 {\r
26     public class BattleResultError : Exception\r
27     {\r
28     }\r
29 \r
30     public class ErrorLog\r
31     {\r
32         private readonly Sniffer _sniffer;\r
33         private BattleState _prevBattleState = BattleState.None;\r
34         private readonly List<string[]> _battleApiLog = new List<string[]>();\r
35 \r
36         public ErrorLog(Sniffer sniffer)\r
37         {\r
38             _sniffer = sniffer;\r
39         }\r
40 \r
41         public void CheckBattleApi(string url, string request, string response)\r
42         {\r
43             if (_prevBattleState == BattleState.None)\r
44                 _battleApiLog.Clear();\r
45             try\r
46             {\r
47                 if (_sniffer.Battle.BattleState != BattleState.None)\r
48                 {\r
49                     _battleApiLog.Add(new[] {url, request, response});\r
50                 }\r
51                 else if (_prevBattleState == BattleState.Result &&\r
52                          // battleresultのあとのship_deckかportでのみエラー判定する\r
53                          IsBattleResultError)\r
54                 {\r
55                     throw new BattleResultError();\r
56                 }\r
57             }\r
58             finally\r
59             {\r
60                 _prevBattleState = _sniffer.Battle.BattleState;\r
61             }\r
62         }\r
63 \r
64         private bool IsBattleResultError =>\r
65             _sniffer.Battle.DisplayedResultRank.IsError || _sniffer.IsBattleResultStatusError;\r
66 \r
67         public string GenerateBattleErrorLog()\r
68         {\r
69             foreach (var logs in _battleApiLog)\r
70                 RemoveUnwantedInformation(ref logs[1], ref logs[2]);\r
71             var version = string.Join(".", Application.ProductVersion.Split('.').Take(2));\r
72             var api = CompressApi(string.Join("\r\n",\r
73                 new[] {BattleStartSlots()}.Concat(_battleApiLog.SelectMany(logs => logs))));\r
74             var rank = _sniffer.Battle.DisplayedResultRank;\r
75             var status = string.Join("\r\n", new[]\r
76             {\r
77                 rank.IsError ? $"{rank.Assumed}->{rank.Actual}" : "",\r
78                 HpDiffLog()\r
79             }.Where(s => !string.IsNullOrEmpty(s)));\r
80             var result = $"{{{{{{\r\n{DateTime.Now:g} {version}\r\n{status}\r\n{api}\r\n}}}}}}";\r
81             File.WriteAllText("error.log", result);\r
82             return result;\r
83         }\r
84 \r
85         private string BattleStartSlots()\r
86         {\r
87             return JsonObject.CreateJsonObject((from ship in _sniffer.BattleStartStatus\r
88                 group ship by ship.Fleet\r
89                 into fleet\r
90                 select\r
91                 (from s in fleet\r
92                     select (from item in s.AllSlot select item.Spec.Id).ToArray()\r
93                 ).ToArray()\r
94             ).ToArray()).ToString();\r
95         }\r
96 \r
97         private string HpDiffLog() => string.Join(" ",\r
98             from pair in _sniffer.BattleResultStatusDiff\r
99             let assumed = pair.Assumed\r
100             let actual = pair.Actual\r
101             select $"({assumed.Fleet}-{assumed.DeckIndex}) {assumed.NowHp}->{actual.NowHp}");\r
102 \r
103         public string GenerateErrorLog(string url, string request, string response, string exception)\r
104         {\r
105             RemoveUnwantedInformation(ref request, ref response);\r
106             var version = string.Join(".", Application.ProductVersion.Split('.').Take(2));\r
107             var api = CompressApi($"{url}\r\n{request}\r\n{response}");\r
108             var result = $"{{{{{{\r\n{DateTime.Now:g} {version}\r\n{exception}\r\n{api}\r\n}}}}}}";\r
109             File.WriteAllText("error.log", result);\r
110             return result;\r
111         }\r
112 \r
113         public static void RemoveUnwantedInformation(ref string request, ref string response)\r
114         {\r
115             var token = new Regex(@"&api%5Ftoken=.+?(?=&|$)|api%5Ftoken=.+?(?:&|$)|api%5Fbtime=\d+&?");\r
116             request = token.Replace(request, "");\r
117             var id = new Regex(@"""api_member_id"":""?\d+""?,?|""api_nickname"":"".+?"",?|""api_nickname_id"":""\d+"",?|""api_name_id"":"".+?"",?|");\r
118             response = id.Replace(response, "");\r
119             var name = new Regex(@"""api_name"":"".+?""");\r
120             response = name.Replace(response, @"""api_name"":""""");\r
121         }\r
122 \r
123         private string CompressApi(string api)\r
124         {\r
125             var output = new MemoryStream();\r
126             var gzip = new GZipStream(output, CompressionLevel.Optimal);\r
127             var bytes = Encoding.UTF8.GetBytes(api);\r
128             gzip.Write(bytes, 0, bytes.Length);\r
129             gzip.Close();\r
130             var ascii85 = Ascii85.Encode(output.ToArray());\r
131             var result = new List<string>();\r
132             var rest = ascii85.Length;\r
133             const int lineLength = 80;\r
134             for (var i = 0; i < ascii85.Length; i += lineLength, rest -= lineLength)\r
135                 result.Add(ascii85.Substring(i, Math.Min(rest, lineLength)));\r
136             return string.Join("\r\n", result);\r
137         }\r
138     }\r
139 }