[Core] Change statistics update to be async.

This commit is contained in:
2024-05-02 01:45:22 +01:00
parent 81de9bc02e
commit 6a3ef12e25
3 changed files with 565 additions and 583 deletions

View File

@@ -37,7 +37,7 @@ using System.Linq;
using System.Net; using System.Net;
using System.Text; using System.Text;
using System.Text.Json; using System.Text.Json;
using System.Threading; using System.Threading.Tasks;
using Aaru.CommonTypes.Interop; using Aaru.CommonTypes.Interop;
using Aaru.CommonTypes.Metadata; using Aaru.CommonTypes.Metadata;
using Aaru.Console; using Aaru.Console;
@@ -93,13 +93,13 @@ public static class Statistics
} }
/// <summary>Saves statistics to disk</summary> /// <summary>Saves statistics to disk</summary>
public static void SaveStats() public static async Task SaveStats()
{ {
try try
{ {
using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath); await using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath);
ctx.SaveChanges(); await ctx.SaveChangesAsync();
} }
catch(SqliteException ex) catch(SqliteException ex)
{ {
@@ -107,15 +107,13 @@ public static class Statistics
AaruConsole.WriteException(ex); AaruConsole.WriteException(ex);
} }
if(Settings.Settings.Current.Stats is { ShareStats: true }) SubmitStats(); if(Settings.Settings.Current.Stats is { ShareStats: true }) await SubmitStats();
} }
/// <summary>Submits statistics to Aaru.Server</summary> /// <summary>Submits statistics to Aaru.Server</summary>
static void SubmitStats() static async Task SubmitStats()
{ {
var submitThread = new Thread(() => await using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath);
{
using var ctx = AaruContext.Create(Settings.Settings.LocalDbPath);
try try
{ {
@@ -156,9 +154,7 @@ public static class Statistics
{ {
dto.Filesystems = []; dto.Filesystems = [];
foreach(string nvs in ctx.Filesystems.Where(c => !c.Synchronized) foreach(string nvs in ctx.Filesystems.Where(c => !c.Synchronized).Select(c => c.Name).Distinct())
.Select(c => c.Name)
.Distinct())
{ {
dto.Filesystems.Add(new NameValueStats dto.Filesystems.Add(new NameValueStats
{ {
@@ -186,9 +182,7 @@ public static class Statistics
{ {
dto.MediaFormats = []; dto.MediaFormats = [];
foreach(string nvs in ctx.MediaFormats.Where(c => !c.Synchronized) foreach(string nvs in ctx.MediaFormats.Where(c => !c.Synchronized).Select(c => c.Name).Distinct())
.Select(c => c.Name)
.Distinct())
{ {
dto.MediaFormats.Add(new NameValueStats dto.MediaFormats.Add(new NameValueStats
{ {
@@ -279,8 +273,7 @@ public static class Statistics
.Select(c => c.Name) .Select(c => c.Name)
.Distinct()) .Distinct())
{ {
foreach(string osVersion in ctx.OperatingSystems foreach(string osVersion in ctx.OperatingSystems.Where(c => !c.Synchronized && c.Name == osName)
.Where(c => !c.Synchronized && c.Name == osName)
.Select(c => c.Version) .Select(c => c.Version)
.Distinct()) .Distinct())
{ {
@@ -305,8 +298,7 @@ public static class Statistics
.Distinct()) .Distinct())
{ {
foreach(string remoteAppVersion in ctx.RemoteApplications foreach(string remoteAppVersion in ctx.RemoteApplications
.Where(c => !c.Synchronized && .Where(c => !c.Synchronized && c.Name == remoteAppName)
c.Name == remoteAppName)
.Select(c => c.Version) .Select(c => c.Version)
.Distinct()) .Distinct())
{ {
@@ -378,19 +370,19 @@ public static class Statistics
request.Method = "POST"; request.Method = "POST";
request.ContentLength = jsonBytes.Length; request.ContentLength = jsonBytes.Length;
request.ContentType = "application/json"; request.ContentType = "application/json";
Stream reqStream = request.GetRequestStream(); Stream reqStream = await request.GetRequestStreamAsync();
reqStream.Write(jsonBytes, 0, jsonBytes.Length); await reqStream.WriteAsync(jsonBytes, 0, jsonBytes.Length);
//jsonStream.CopyTo(reqStream); //jsonStream.CopyTo(reqStream);
reqStream.Close(); reqStream.Close();
WebResponse response = request.GetResponse(); WebResponse response = await request.GetResponseAsync();
if(((HttpWebResponse)response).StatusCode != HttpStatusCode.OK) return; if(((HttpWebResponse)response).StatusCode != HttpStatusCode.OK) return;
Stream data = response.GetResponseStream(); Stream data = response.GetResponseStream();
var reader = new StreamReader(data ?? throw new InvalidOperationException()); var reader = new StreamReader(data ?? throw new InvalidOperationException());
string result = reader.ReadToEnd(); string result = await reader.ReadToEndAsync();
data.Close(); data.Close();
response.Close(); response.Close();
@@ -415,12 +407,9 @@ public static class Statistics
if(ctx.Filesystems.Any(c => !c.Synchronized)) if(ctx.Filesystems.Any(c => !c.Synchronized))
{ {
foreach(string nvs in ctx.Filesystems.Where(c => !c.Synchronized) foreach(string nvs in ctx.Filesystems.Where(c => !c.Synchronized).Select(c => c.Name).Distinct())
.Select(c => c.Name)
.Distinct())
{ {
Filesystem existing = Filesystem existing = ctx.Filesystems.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ??
ctx.Filesystems.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ??
new Filesystem new Filesystem
{ {
Name = nvs, Name = nvs,
@@ -454,12 +443,9 @@ public static class Statistics
if(ctx.MediaFormats.Any(c => !c.Synchronized)) if(ctx.MediaFormats.Any(c => !c.Synchronized))
{ {
foreach(string nvs in ctx.MediaFormats.Where(c => !c.Synchronized) foreach(string nvs in ctx.MediaFormats.Where(c => !c.Synchronized).Select(c => c.Name).Distinct())
.Select(c => c.Name)
.Distinct())
{ {
MediaFormat existing = MediaFormat existing = ctx.MediaFormats.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ??
ctx.MediaFormats.FirstOrDefault(c => c.Synchronized && c.Name == nvs) ??
new MediaFormat new MediaFormat
{ {
Name = nvs, Name = nvs,
@@ -529,9 +515,7 @@ public static class Statistics
ctx.Medias.Update(existing); ctx.Medias.Update(existing);
ctx.Medias.RemoveRange(ctx.Medias.Where(c => !c.Synchronized && ctx.Medias.RemoveRange(ctx.Medias.Where(c => !c.Synchronized && c.Type == media && c.Real));
c.Type == media &&
c.Real));
} }
if(!ctx.Medias.Any(c => !c.Synchronized && c.Type == media && !c.Real)) continue; if(!ctx.Medias.Any(c => !c.Synchronized && c.Type == media && !c.Real)) continue;
@@ -573,8 +557,7 @@ public static class Statistics
.Select(c => c.Name) .Select(c => c.Name)
.Distinct()) .Distinct())
{ {
foreach(string osVersion in ctx.OperatingSystems foreach(string osVersion in ctx.OperatingSystems.Where(c => !c.Synchronized && c.Name == osName)
.Where(c => !c.Synchronized && c.Name == osName)
.Select(c => c.Version) .Select(c => c.Version)
.Distinct()) .Distinct())
{ {
@@ -610,8 +593,7 @@ public static class Statistics
.Distinct()) .Distinct())
{ {
foreach(string remoteAppVersion in ctx.RemoteApplications foreach(string remoteAppVersion in ctx.RemoteApplications
.Where(c => !c.Synchronized && .Where(c => !c.Synchronized && c.Name == remoteAppName)
c.Name == remoteAppName)
.Select(c => c.Version) .Select(c => c.Version)
.Distinct()) .Distinct())
{ {
@@ -691,14 +673,13 @@ public static class Statistics
ctx.RemoteOperatingSystems.Update(existing); ctx.RemoteOperatingSystems.Update(existing);
ctx.RemoteOperatingSystems.RemoveRange(ctx.RemoteOperatingSystems.Where(c => ctx.RemoteOperatingSystems.RemoveRange(ctx.RemoteOperatingSystems.Where(c => !c.Synchronized &&
!c.Synchronized &&
c.Name == remoteOsName && c.Name == remoteOsName &&
c.Version == remoteOsVersion)); c.Version == remoteOsVersion));
} }
} }
ctx.SaveChanges(); await ctx.SaveChangesAsync();
} }
} }
catch(WebException) catch(WebException)
@@ -721,9 +702,6 @@ public static class Statistics
} }
_submitStatsLock = false; _submitStatsLock = false;
});
submitThread.Start();
} }
/// <summary>Adds the execution of a command to statistics</summary> /// <summary>Adds the execution of a command to statistics</summary>

View File

@@ -148,8 +148,8 @@ public sealed class SplashWindowViewModel(SplashWindow view) : ViewModelBase
foreach(string migration in ctx.Database.GetPendingMigrations()) foreach(string migration in ctx.Database.GetPendingMigrations())
{ {
ctx.Database
#pragma warning disable EF1002 #pragma warning disable EF1002
ctx.Database
.ExecuteSqlRaw($"INSERT INTO \"__EFMigrationsHistory\" (MigrationId, ProductVersion) VALUES ('{ .ExecuteSqlRaw($"INSERT INTO \"__EFMigrationsHistory\" (MigrationId, ProductVersion) VALUES ('{
migration}', '0.0.0')"); migration}', '0.0.0')");
#pragma warning restore EF1002 #pragma warning restore EF1002
@@ -294,9 +294,9 @@ public sealed class SplashWindowViewModel(SplashWindow view) : ViewModelBase
Message = UI.Saving_statistics; Message = UI.Saving_statistics;
AaruConsole.WriteLine(UI.Saving_statistics); AaruConsole.WriteLine(UI.Saving_statistics);
Task.Run(() => Task.Run(async () =>
{ {
Statistics.SaveStats(); await Statistics.SaveStats();
Dispatcher.UIThread.Post(LoadMainWindow); Dispatcher.UIThread.Post(LoadMainWindow);
}); });

View File

@@ -37,6 +37,7 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Threading.Tasks;
using Aaru.Commands; using Aaru.Commands;
using Aaru.Commands.Archive; using Aaru.Commands.Archive;
using Aaru.Commands.Database; using Aaru.Commands.Database;
@@ -62,7 +63,7 @@ class MainClass
static string _assemblyTitle; static string _assemblyTitle;
static AssemblyInformationalVersionAttribute _assemblyVersion; static AssemblyInformationalVersionAttribute _assemblyVersion;
public static int Main([NotNull] string[] args) public static async Task<int> Main([NotNull] string[] args)
{ {
IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings IAnsiConsole stderrConsole = AnsiConsole.Create(new AnsiConsoleSettings
{ {
@@ -113,14 +114,17 @@ class MainClass
try try
{ {
ctx = AaruContext.Create(Settings.Settings.LocalDbPath, false); ctx = AaruContext.Create(Settings.Settings.LocalDbPath, false);
ctx.Database.Migrate(); await ctx.Database.MigrateAsync();
} }
catch(NotSupportedException) catch(NotSupportedException)
{ {
try try
{ {
ctx?.Database.CloseConnection(); if(ctx is not null)
ctx?.Dispose(); {
await ctx.Database.CloseConnectionAsync();
await ctx.DisposeAsync();
}
} }
catch(Exception) catch(Exception)
{ {
@@ -129,21 +133,21 @@ class MainClass
File.Delete(Settings.Settings.LocalDbPath); File.Delete(Settings.Settings.LocalDbPath);
ctx = AaruContext.Create(Settings.Settings.LocalDbPath); ctx = AaruContext.Create(Settings.Settings.LocalDbPath);
ctx.Database.EnsureCreated(); await ctx.Database.EnsureCreatedAsync();
ctx.Database await ctx.Database
.ExecuteSqlRaw("CREATE TABLE IF NOT EXISTS \"__EFMigrationsHistory\" (\"MigrationId\" TEXT PRIMARY KEY, \"ProductVersion\" TEXT)"); .ExecuteSqlRawAsync("CREATE TABLE IF NOT EXISTS \"__EFMigrationsHistory\" (\"MigrationId\" TEXT PRIMARY KEY, \"ProductVersion\" TEXT)");
foreach(string migration in ctx.Database.GetPendingMigrations()) foreach(string migration in await ctx.Database.GetPendingMigrationsAsync())
{ {
ctx.Database
#pragma warning disable EF1002 #pragma warning disable EF1002
.ExecuteSqlRaw($"INSERT INTO \"__EFMigrationsHistory\" (MigrationId, ProductVersion) VALUES ('{ await ctx.Database
.ExecuteSqlRawAsync($"INSERT INTO \"__EFMigrationsHistory\" (MigrationId, ProductVersion) VALUES ('{
migration}', '0.0.0')"); migration}', '0.0.0')");
#pragma warning restore EF1002 #pragma warning restore EF1002
} }
ctx.SaveChanges(); await ctx.SaveChangesAsync();
} }
// Remove duplicates // Remove duplicates
@@ -170,7 +174,7 @@ class MainClass
// Remove nulls // Remove nulls
ctx.RemoveRange(ctx.SeenDevices.Where(d => d.Manufacturer == null && d.Model == null && d.Revision == null)); ctx.RemoveRange(ctx.SeenDevices.Where(d => d.Manufacturer == null && d.Model == null && d.Revision == null));
ctx.SaveChanges(); await ctx.SaveChangesAsync();
var mainDbUpdate = false; var mainDbUpdate = false;
@@ -182,7 +186,7 @@ class MainClass
var mainContext = AaruContext.Create(Settings.Settings.MainDbPath, false); var mainContext = AaruContext.Create(Settings.Settings.MainDbPath, false);
if(mainContext.Database.GetPendingMigrations().Any()) if((await mainContext.Database.GetPendingMigrationsAsync()).Any())
{ {
AaruConsole.WriteLine(UI.New_database_version_updating); AaruConsole.WriteLine(UI.New_database_version_updating);
@@ -198,8 +202,8 @@ class MainClass
return (int)ErrorNumber.CannotRemoveDatabase; return (int)ErrorNumber.CannotRemoveDatabase;
} }
mainContext.Database.CloseConnection(); await mainContext.Database.CloseConnectionAsync();
mainContext.Dispose(); await mainContext.DisposeAsync();
UpdateCommand.DoUpdate(true); UpdateCommand.DoUpdate(true);
} }
@@ -244,9 +248,9 @@ class MainClass
rootCommand.AddCommand(new ListNamespacesCommand()); rootCommand.AddCommand(new ListNamespacesCommand());
rootCommand.AddCommand(new RemoteCommand()); rootCommand.AddCommand(new RemoteCommand());
int ret = rootCommand.Invoke(args); int ret = await rootCommand.InvokeAsync(args);
Statistics.SaveStats(); await Statistics.SaveStats();
if(!rootCommand.Parse(args).RootCommandResult.GetValueForOption(pauseOption)) return ret; if(!rootCommand.Parse(args).RootCommandResult.GetValueForOption(pauseOption)) return ret;