mirror of
https://github.com/chylex/TweetDuck.git
synced 2024-11-23 17:42:46 +01:00
159 lines
5.8 KiB
C#
159 lines
5.8 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.Core.Controls;
|
|
using TweetDuck.Core.Utils;
|
|
using TweetDuck.Plugins;
|
|
|
|
namespace TweetDuck.Core.Other.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", Program.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
|
|
|
|
BrowserUtils.CreateWebClient().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){
|
|
switch(e.Status){
|
|
case WebExceptionStatus.ConnectFailure:
|
|
message = "Connection Error";
|
|
break;
|
|
|
|
case WebExceptionStatus.NameResolutionFailure:
|
|
message = "DNS Error";
|
|
break;
|
|
|
|
case WebExceptionStatus.ProtocolError:
|
|
HttpWebResponse response = e.Response as HttpWebResponse;
|
|
message = "HTTP Error "+(response != null ? $"{(int)response.StatusCode} ({response.StatusDescription})" : "(unknown code)");
|
|
break;
|
|
}
|
|
|
|
#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));
|
|
}
|
|
}));
|
|
}
|
|
}
|
|
}
|