2 using System.Collections.Generic;
\r
3 using System.ComponentModel;
\r
4 using System.Diagnostics;
\r
5 using System.Globalization;
\r
9 using System.Text.RegularExpressions;
\r
10 using System.Windows.Forms;
\r
12 using KancolleSniffer.Forms;
\r
13 using KancolleSniffer.Log;
\r
14 using KancolleSniffer.Net;
\r
15 using KancolleSniffer.Util;
\r
16 using Microsoft.CSharp.RuntimeBinder;
\r
18 namespace KancolleSniffer
\r
22 private ProxyManager _proxyManager;
\r
24 private MainWindow _mainBehavior;
\r
25 private readonly ErrorDialog _errorDialog = new ErrorDialog();
\r
26 private ConfigDialog _configDialog;
\r
27 private ErrorLog _errorLog;
\r
28 private IEnumerator<string> _playLog;
\r
29 private string _debugLogFile;
\r
30 private bool _timerEnabled;
\r
31 private readonly Timer _mainTimer = new Timer {Interval = 1000, Enabled = true};
\r
33 public TimeStep Step { get; } = new TimeStep();
\r
35 public Config Config { get; } = new Config();
\r
36 public Sniffer Sniffer { get; } = new Sniffer();
\r
38 public static void Run()
\r
40 new Main().RunInternal();
\r
43 private void RunInternal()
\r
46 _configDialog = new ConfigDialog(this);
\r
47 var form = Config.Shape.StartsWith("横長") ? (Form)new HorizontalMainForm() : new VerticalMainForm();
\r
49 _mainBehavior = new MainWindow(this, form);
\r
50 _proxyManager = new ProxyManager(_form, Config);
\r
51 _proxyManager.UpdatePacFile();
\r
52 _errorLog = new ErrorLog(Sniffer);
\r
53 Sniffer.RepeatingTimerController = _mainBehavior.Notifier;
\r
57 HttpProxy.AfterSessionComplete += HttpProxy_AfterSessionComplete;
\r
58 _mainTimer.Tick += TimerTick;
\r
59 Application.Run(_form);
\r
63 public void CheckVersionUpMain(LinkLabel guide)
\r
65 CheckVersionUp((current, latest) =>
\r
67 if (latest == current)
\r
69 guide.Text = $"バージョン{latest}があります。";
\r
70 guide.LinkArea = new LinkArea(0, guide.Text.Length);
\r
71 guide.Click += (obj, ev) => { Process.Start("https://ja.osdn.net/rel/kancollesniffer/" + latest); };
\r
75 private readonly FileSystemWatcher _watcher = new FileSystemWatcher
\r
77 Path = AppDomain.CurrentDomain.BaseDirectory,
\r
78 NotifyFilter = NotifyFilters.LastWrite
\r
81 private readonly Timer _watcherTimer = new Timer {Interval = 1000};
\r
83 private void LoadData()
\r
86 Sniffer.LoadState();
\r
87 _watcher.SynchronizingObject = _form;
\r
88 _watcherTimer.Tick += (sender, ev) =>
\r
90 _watcherTimer.Stop();
\r
94 Sniffer.LoadState();
\r
97 Sniffer.AdditionalData.LoadTpSpec();
\r
101 _watcher.Changed += (sender, ev) =>
\r
104 _watcherTimer.Stop();
\r
105 _watcherTimer.Start();
\r
107 _watcher.EnableRaisingEvents = true;
\r
110 private void HttpProxy_AfterSessionComplete(HttpProxy.Session session)
\r
112 _form.BeginInvoke(new Action<HttpProxy.Session>(ProcessRequest), session);
\r
115 public class Session
\r
117 public string Url { get; set; }
\r
118 public string Request { get; set; }
\r
119 public string Response { get; set; }
\r
121 public Session(string url, string request, string response)
\r
125 Response = response;
\r
128 public string[] Lines => new[] {Url, Request, Response};
\r
131 private void ProcessRequest(HttpProxy.Session session)
\r
133 var url = session.Request.PathAndQuery;
\r
134 if (!url.Contains("kcsapi/"))
\r
136 var s = new Session(url, session.Request.BodyAsString, session.Response.BodyAsString);
\r
138 if (s.Response == null || !s.Response.StartsWith("svdata="))
\r
143 s.Response = UnEscapeString(s.Response.Remove(0, "svdata=".Length));
\r
145 ProcessRequestMain(s);
\r
148 private void ProcessRequestMain(Session s)
\r
152 var update = (Sniffer.Update)Sniffer.Sniff(s.Url, s.Request, JsonObject.Parse(s.Response));
\r
153 _mainBehavior.UpdateInfo(update);
\r
154 if (!Sniffer.Started)
\r
156 Step.SetNowIfNeeded();
\r
157 if ((update & Sniffer.Update.Timer) != 0)
\r
158 _timerEnabled = true;
\r
159 _errorLog.CheckBattleApi(s);
\r
162 catch (RuntimeBinderException e)
\r
164 if (_errorDialog.ShowDialog(_form,
\r
165 "艦これに仕様変更があったか、受信内容が壊れています。",
\r
166 _errorLog.GenerateErrorLog(s, e.ToString())) == DialogResult.Abort)
\r
169 catch (LogIOException e)
\r
171 // ReSharper disable once PossibleNullReferenceException
\r
172 if (_errorDialog.ShowDialog(_form, e.Message, e.InnerException.ToString()) == DialogResult.Abort)
\r
175 catch (BattleResultError)
\r
177 if (_errorDialog.ShowDialog(_form, "戦闘結果の計算に誤りがあります。",
\r
178 _errorLog.GenerateBattleErrorLog()) == DialogResult.Abort)
\r
181 catch (Exception e)
\r
183 if (_errorDialog.ShowDialog(_form, "エラーが発生しました。",
\r
184 _errorLog.GenerateErrorLog(s, e.ToString())) == DialogResult.Abort)
\r
189 private void Exit()
\r
191 _proxyManager.Shutdown();
\r
192 Environment.Exit(1);
\r
195 private void WriteDebugLog(Session s)
\r
197 if (_debugLogFile != null)
\r
199 File.AppendAllText(_debugLogFile,
\r
200 $"date: {DateTime.Now:g}\nurl: {s.Url}\nrequest: {s.Request}\nresponse: {s.Response ?? "(null)"}\n");
\r
204 private string UnEscapeString(string s)
\r
208 var rx = new Regex(@"\\[uU]([0-9A-Fa-f]{4})");
\r
209 return rx.Replace(s,
\r
210 match => ((char)int.Parse(match.Value.Substring(2), NumberStyles.HexNumber)).ToString());
\r
212 catch (ArgumentException)
\r
218 public async void CheckVersionUp(Action<string, string> action)
\r
220 var current = string.Join(".", Application.ProductVersion.Split('.').Take(2));
\r
223 var latest = (await new WebClient().DownloadStringTaskAsync("http://kancollesniffer.osdn.jp/version"))
\r
227 action(current, latest);
\r
229 catch (InvalidOperationException)
\r
233 catch (WebException)
\r
238 private void ApplySettings()
\r
240 ApplyDebugLogSetting();
\r
242 ApplyProxySetting();
\r
245 public void ApplyDebugLogSetting()
\r
247 _debugLogFile = Config.DebugLogging ? Config.DebugLogFile : null;
\r
250 public bool ApplyProxySetting()
\r
252 return _proxyManager.ApplyConfig();
\r
255 public void ApplyLogSetting()
\r
257 LogServer.OutputDir = Config.Log.OutputDir;
\r
258 LogServer.LogProcessor = new LogProcessor(Sniffer.Material.MaterialHistory, Sniffer.MapDictionary);
\r
259 Sniffer.EnableLog(Config.Log.On ? LogType.All : LogType.None);
\r
260 Sniffer.MaterialLogInterval = Config.Log.MaterialLogInterval;
\r
261 Sniffer.LogOutputDir = Config.Log.OutputDir;
\r
264 public void SetPlayLog(string file)
\r
268 _playLog = File.ReadLines(file).GetEnumerator();
\r
270 catch (FileNotFoundException)
\r
275 private void TimerTick(object sender, EventArgs ev)
\r
282 _mainBehavior.UpdateTimers();
\r
283 _mainBehavior.Notifier.NotifyTimers();
\r
286 catch (Exception ex)
\r
288 if (_errorDialog.ShowDialog(_form, "エラーが発生しました。", ex.ToString()) == DialogResult.Abort)
\r
292 if (_playLog == null || _configDialog.Visible)
\r
294 _mainBehavior.PlayLogSign.Visible = false;
\r
300 public void ResetAchievement()
\r
302 Sniffer.Achievement.Reset();
\r
303 _mainBehavior.UpdateItemInfo();
\r
306 private void PlayLog()
\r
308 var lines = new List<string>();
\r
309 var sign = _mainBehavior.PlayLogSign;
\r
310 foreach (var s in new[] {"url: ", "request: ", "response: "})
\r
314 if (!_playLog.MoveNext() || _playLog.Current == null)
\r
316 sign.Visible = false;
\r
319 } while (!_playLog.Current.StartsWith(s));
\r
320 lines.Add(_playLog.Current.Substring(s.Length));
\r
322 sign.Visible = !sign.Visible;
\r
323 ProcessRequestMain(new Session(lines[0], lines[1], lines[2]));
\r
326 public void ShowConfigDialog()
\r
328 if (_configDialog.ShowDialog(_form) == DialogResult.OK)
\r
332 _mainBehavior.Notifier.StopRepeatingTimer(_configDialog.RepeatSettingsChanged);
\r
336 private void ApplyConfig()
\r
338 Sniffer.ShipCounter.Margin = Config.MarginShips;
\r
339 Sniffer.ItemCounter.Margin = Config.MarginEquips;
\r
340 _mainBehavior.Notifier.NotifyShipItemCount();
\r
341 Sniffer.Achievement.ResetHours = Config.ResetHours;
\r
342 Sniffer.WarnBadDamageWithDameCon = Config.WarnBadDamageWithDameCon;
\r
343 _mainBehavior.ApplyConfig();
\r
346 public IEnumerable<Control> Controls =>
\r
347 new Control[] {_errorDialog, _configDialog, _configDialog.NotificationConfigDialog};
\r
349 private void Terminate()
\r
351 _proxyManager.Shutdown();
\r
353 Sniffer.FlashLog();
\r
354 Sniffer.SaveState();
\r
357 public void ShowReport()
\r
359 Process.Start("http://localhost:" + Config.Proxy.Listen + "/");
\r
362 public void StartCapture()
\r
366 var proc = new ProcessStartInfo("BurageSnap.exe") {WorkingDirectory = "Capture"};
\r
367 Process.Start(proc);
\r
369 catch (FileNotFoundException)
\r
372 catch (Win32Exception)
\r