mirror of
https://github.com/chylex/TweetDuck.git
synced 2025-05-20 11:34:08 +02:00
154 lines
4.7 KiB
C#
154 lines
4.7 KiB
C#
// Uncomment to debug reports locally
|
|
// #define ANALYTICS_LOCALHOST
|
|
// #define ANALYTICS_INSTANT
|
|
|
|
using System;
|
|
using System.Net;
|
|
using System.Threading.Tasks;
|
|
using System.Timers;
|
|
using TweetDuck.Browser;
|
|
using TweetDuck.Controls;
|
|
using TweetDuck.Utils;
|
|
using TweetLib.Core;
|
|
using TweetLib.Core.Features.Plugins;
|
|
using TweetLib.Core.Utils;
|
|
|
|
namespace TweetDuck.Management.Analytics {
|
|
sealed class AnalyticsManager : IDisposable {
|
|
private static readonly TimeSpan CollectionInterval = TimeSpan.FromDays(14);
|
|
|
|
private static readonly Uri CollectionUrl = new Uri(
|
|
#if (DEBUG && ANALYTICS_LOCALHOST)
|
|
"http://localhost/newhome/tweetduck/~breadcrumb/request.php?type=report"
|
|
#else
|
|
"https://tweetduck.chylex.com/breadcrumb/report"
|
|
#endif
|
|
);
|
|
|
|
public AnalyticsFile File { get; }
|
|
|
|
private readonly FormBrowser browser;
|
|
private readonly PluginManager plugins;
|
|
private readonly Timer currentTimer, saveTimer;
|
|
|
|
public AnalyticsManager(FormBrowser browser, PluginManager plugins, string file) {
|
|
this.browser = browser;
|
|
this.plugins = plugins;
|
|
|
|
this.File = AnalyticsFile.Load(file);
|
|
this.File.PropertyChanged += File_PropertyChanged;
|
|
|
|
this.currentTimer = new Timer { SynchronizingObject = browser };
|
|
this.currentTimer.Elapsed += currentTimer_Elapsed;
|
|
|
|
this.saveTimer = new Timer { SynchronizingObject = browser, Interval = 60000 };
|
|
this.saveTimer.Elapsed += saveTimer_Elapsed;
|
|
|
|
if (this.File.LastCollectionVersion != Program.VersionTag) {
|
|
ScheduleReportIn(TimeSpan.FromHours(8), string.Empty);
|
|
}
|
|
else {
|
|
RestartTimer();
|
|
}
|
|
|
|
#if (DEBUG && ANALYTICS_INSTANT)
|
|
SendReport();
|
|
#endif
|
|
}
|
|
|
|
public void Dispose() {
|
|
File.PropertyChanged -= File_PropertyChanged;
|
|
|
|
if (saveTimer.Enabled) {
|
|
File.Save();
|
|
}
|
|
|
|
currentTimer.Dispose();
|
|
saveTimer.Dispose();
|
|
}
|
|
|
|
private void File_PropertyChanged(object sender, EventArgs e) {
|
|
saveTimer.Enabled = true;
|
|
}
|
|
|
|
private void saveTimer_Elapsed(object sender, ElapsedEventArgs e) {
|
|
saveTimer.Stop();
|
|
File.Save();
|
|
}
|
|
|
|
private void ScheduleReportIn(TimeSpan delay, string message = null) {
|
|
SetLastDataCollectionTime(DateTime.Now.Subtract(CollectionInterval).Add(delay), message);
|
|
}
|
|
|
|
private void SetLastDataCollectionTime(DateTime dt, string message = null) {
|
|
File.LastDataCollection = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0, dt.Kind);
|
|
File.LastCollectionVersion = Program.VersionTag;
|
|
File.LastCollectionMessage = message ?? dt.ToString("g", Lib.Culture);
|
|
|
|
File.Save();
|
|
RestartTimer();
|
|
}
|
|
|
|
private void RestartTimer() {
|
|
TimeSpan diff = DateTime.Now.Subtract(File.LastDataCollection);
|
|
int minutesTillNext = (int) (CollectionInterval.TotalMinutes - Math.Floor(diff.TotalMinutes));
|
|
|
|
currentTimer.Interval = Math.Max(minutesTillNext, 2) * 60000;
|
|
currentTimer.Start();
|
|
}
|
|
|
|
private void currentTimer_Elapsed(object sender, ElapsedEventArgs e) {
|
|
currentTimer.Stop();
|
|
|
|
TimeSpan diff = DateTime.Now.Subtract(File.LastDataCollection);
|
|
|
|
if (Math.Floor(diff.TotalMinutes) >= CollectionInterval.TotalMinutes) {
|
|
SendReport();
|
|
}
|
|
else {
|
|
RestartTimer();
|
|
}
|
|
}
|
|
|
|
private void SendReport() {
|
|
AnalyticsReportGenerator.ExternalInfo info = AnalyticsReportGenerator.ExternalInfo.From(browser);
|
|
|
|
Task.Factory.StartNew(() => {
|
|
AnalyticsReport report = AnalyticsReportGenerator.Create(File, info, plugins);
|
|
|
|
#if (DEBUG && !ANALYTICS_INSTANT)
|
|
System.Diagnostics.Debugger.Break();
|
|
#endif
|
|
|
|
WebUtils.NewClient(BrowserUtils.UserAgentVanilla).UploadValues(CollectionUrl, "POST", report.ToNameValueCollection());
|
|
}).ContinueWith(task => browser.InvokeAsyncSafe(() => {
|
|
if (task.Status == TaskStatus.RanToCompletion) {
|
|
SetLastDataCollectionTime(DateTime.Now);
|
|
}
|
|
else if (task.Exception != null) {
|
|
string message = null;
|
|
|
|
if (task.Exception.InnerException is WebException e) {
|
|
message = e.Status switch {
|
|
WebExceptionStatus.ConnectFailure => "Connection Error",
|
|
WebExceptionStatus.NameResolutionFailure => "DNS Error",
|
|
WebExceptionStatus.ProtocolError => "HTTP Error " + (e.Response is HttpWebResponse response ? $"{(int) response.StatusCode} ({response.StatusDescription})" : "(unknown code)"),
|
|
_ => message
|
|
};
|
|
|
|
#if DEBUG
|
|
System.IO.Stream responseStream = e.Response.GetResponseStream();
|
|
|
|
if (responseStream != null) {
|
|
System.Diagnostics.Debug.WriteLine(new System.IO.StreamReader(responseStream).ReadToEnd());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
ScheduleReportIn(TimeSpan.FromHours(4), message ?? "Error: " + (task.Exception.InnerException?.Message ?? task.Exception.Message));
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
}
|