From 4c76f04d0e31771451170ae480e1f71c27760abd Mon Sep 17 00:00:00 2001 From: Jose Conde Date: Tue, 30 Sep 2025 15:57:56 +0200 Subject: [PATCH] refactors --- ModVersionChecker/Main.cs | 25 ++- ModVersionChecker/VersionChecker.cs | 109 +--------- .../repository/api/ApiRepository.cs | 4 +- .../repository/api/IApiRepository.cs | 2 +- .../repository/api/dto/AppResponse.cs | 4 +- .../repository/filesystem/AppStatusManager.cs | 2 +- .../repository/filesystem/ConfigManager.cs | 2 +- .../{IAppsManager.cs => IAppRepository.cs} | 2 +- ...atusManager.cs => IAppStatusRepository.cs} | 2 +- ...IConfigManager.cs => IConfigRepository.cs} | 2 +- ...ypeManager.cs => ITypeConfigRepository.cs} | 2 +- ...lightSimsManager.cs => ITypeRepository.cs} | 2 +- .../repository/litedb/AppLiteDb.cs | 2 +- .../repository/litedb/ConfigLiteDb.cs | 2 +- .../repository/litedb/TypeConfigLiteDb.cs | 2 +- .../repository/litedb/TypeLiteDb.cs | 2 +- ModVersionChecker/service/ApiService.cs | 8 +- ModVersionChecker/service/AppService.cs | 203 ++++++++++++++++++ ...yIconService.cs => NotificationService.cs} | 2 +- ModVersionChecker/service/StateService.cs | 41 ++++ ModVersionChecker/service/VersionService.cs | 112 +--------- .../service/interfaces/IApiService.cs | 5 +- .../service/interfaces/IAppService.cs | 20 ++ ...IconService.cs => INotificationService.cs} | 2 +- .../service/interfaces/IStateService.cs | 20 ++ .../service/interfaces/IVersionService.cs | 8 +- ModVersionChecker/ui/forms/AppDetailsForm.cs | 16 +- ModVersionChecker/ui/forms/FormFactory.cs | 10 +- .../ui/forms/GlobalConfigForm.cs | 4 +- ModVersionChecker/ui/forms/MainForm.cs | 71 +++--- ModVersionChecker/ui/forms/TypeConfigForm.cs | 8 +- 31 files changed, 403 insertions(+), 293 deletions(-) rename ModVersionChecker/repository/interfaces/{IAppsManager.cs => IAppRepository.cs} (92%) rename ModVersionChecker/repository/interfaces/{IAppStatusManager.cs => IAppStatusRepository.cs} (91%) rename ModVersionChecker/repository/interfaces/{IConfigManager.cs => IConfigRepository.cs} (88%) rename ModVersionChecker/repository/interfaces/{ITypeManager.cs => ITypeConfigRepository.cs} (88%) rename ModVersionChecker/repository/interfaces/{IFlightSimsManager.cs => ITypeRepository.cs} (90%) create mode 100644 ModVersionChecker/service/AppService.cs rename ModVersionChecker/service/{NotifyIconService.cs => NotificationService.cs} (90%) create mode 100644 ModVersionChecker/service/StateService.cs create mode 100644 ModVersionChecker/service/interfaces/IAppService.cs rename ModVersionChecker/service/interfaces/{INotifyIconService.cs => INotificationService.cs} (88%) create mode 100644 ModVersionChecker/service/interfaces/IStateService.cs diff --git a/ModVersionChecker/Main.cs b/ModVersionChecker/Main.cs index 1827068..6b2a31c 100644 --- a/ModVersionChecker/Main.cs +++ b/ModVersionChecker/Main.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.Hosting; using ModVersionChecker.managers.filesystem; using ModVersionChecker.managers.interfaces; using ModVersionChecker.managers.litedb; +using ModVersionChecker.repository.api; using ModVersionChecker.service; using ModVersionChecker.service.interfaces; using ModVersionChecker.ui.forms; @@ -19,16 +20,19 @@ namespace ModVersionChecker builder.ConfigureServices(services => { - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); services.AddTransient(); services.AddTransient(); @@ -59,9 +63,10 @@ namespace ModVersionChecker var serviceProvider = host.Services; var configForm = serviceProvider.GetService(); - var notifyIconService = serviceProvider.GetRequiredService(); - var configManager = serviceProvider.GetRequiredService(); + var notifyIconService = serviceProvider.GetRequiredService(); + var configManager = serviceProvider.GetRequiredService(); var versionService = serviceProvider.GetRequiredService(); + var appService = serviceProvider.GetRequiredService(); var config = configManager.GetConfig(); EventHandler openFormHandler = (s, e) => @@ -101,9 +106,9 @@ namespace ModVersionChecker if (checkOnInitialStart) { - Task.Run(async () => + Task.Run(() => { - await versionService.CheckAllApps(); + appService.CheckAllApps(); if (configForm != null) { configForm.UpdateListView(); diff --git a/ModVersionChecker/VersionChecker.cs b/ModVersionChecker/VersionChecker.cs index 0e36076..aab4316 100644 --- a/ModVersionChecker/VersionChecker.cs +++ b/ModVersionChecker/VersionChecker.cs @@ -7,34 +7,31 @@ namespace ModVersionChecker { public class VersionChecker { - private readonly IConfigManager _configManager; + private readonly IAppService _appService; + private readonly IConfigRepository _configManager; private readonly IVersionService _versionService; public event EventHandler? OnFinished; public VersionChecker( + IAppService appService, IVersionService versionService, - IConfigManager configManager) + IConfigRepository configManager + ) { _configManager = configManager ?? throw new ArgumentNullException(nameof(configManager)); _versionService = versionService ?? throw new ArgumentNullException(nameof(versionService)); + _appService = appService ?? throw new ArgumentNullException(nameof(appService)); } - - //private void HandleAppError(string message, AppConfig app) - //{ - // errorMessages.Add(message); - // _appsManager.UpdateStatus(app, AppStatus.ERROR); - //} public void StartVersionChecking() { var config = _configManager.Load() ?? new Config(); - // Run version checks in a background thread - new Thread(async () => + new Thread(() => { while (true) { - await _versionService.CheckAllApps(); + _appService.CheckAllApps(); Thread.Sleep(config.IntervalMinutes * 60 * 1000); } @@ -42,95 +39,5 @@ namespace ModVersionChecker }) { IsBackground = true }.Start(); } - - - - //public async Task CheckAsync() - //{ - // var config = _configManager.Load() ?? new GlobalConfig(); - // var apps = _appsManager.Load() ?? new List(); - // var sources = _sourcesDefManager.List() ?? new List(); - // var fsMods = _fsManager.Load() ?? new List(); - // var types = _typeConfigManager.GetTypeConfigs() ?? new List(); - - // var appVersionsMap = await _apiVersionService.GetAppVersionsAsync(apps); - - // updateMessages = new List(); - // errorMessages = new List(); - - // foreach (AppConfig app in apps) - // { - // if (app.Status != AppStatus.ERROR && app.LastCheckedAt != 0 && app.LastCheckedAt < TimeUtils.GetUnixTimeMillis(DateTime.Now.AddMinutes(-60))) - // continue; - - // var status = AppStatus.NONE; - // var sourceId = app.Source; - - // // Skip apps that are not in the API response - - // if (!appVersionsMap.Any(a => app.Id == a.Id)) { - // continue; - // } - // var latesstVersion = appVersionsMap.FirstOrDefault(a => a.Id == app.Id).LatestVersion; - // if (string.IsNullOrWhiteSpace(sourceId)) - // { - // HandleAppError($"{app.Name} has no source configured.", app); - // continue; - // } - // var source = sources.FirstOrDefault(s => s.Id == sourceId); - // if (source == null) - // { - // HandleAppError($"{app.Name} has an invalid source: {sourceId}", app); - // continue; - // } - // try - // { - // var type = app.Types[0]; - // var typeConfig = types[0]; - // if (typeConfig == null) - // { - // HandleAppError($"{app.Name} has no FS mod path configured for version {type}.", app); - // continue; - // } - // var current = NuGetVersion.Parse(VersionUtils.GetCurrentVersion(app, typeConfig)); - // var latest = NuGetVersion.Parse(latesstVersion); - - // app.CurrentVersion = current.ToString(); - // app.LatestVersion = latest.ToString(); - - // if (latest.CompareTo(current) == 1) - // { - // updateMessages.Add($"{app.Name}: New version {latest} (current: {current})"); - // status = AppStatus.UPDATE_AVAILABLE; - // } - - // _appsManager.UpdateStatus(app, status); - // } - // catch (Exception ex) - // { - // HandleAppError($"Failed for {app.Name}: {ex.Message}", app); - // } - // } - - // if (updateMessages.Count > 0) - // { - // _notifyIconService.ShowBalloonTip( - // 10000, - // "Updates Available", - // string.Join("\n", updateMessages), - // ToolTipIcon.Info - // ); - // } - // if (errorMessages.Count > 0) - // { - // _notifyIconService.ShowBalloonTip( - // 10000, - // "Errors", - // string.Join("\n", errorMessages), - // ToolTipIcon.Error - // ); - // } - // OnFinished?.Invoke(this, "Version check completed."); - //} } } diff --git a/ModVersionChecker/repository/api/ApiRepository.cs b/ModVersionChecker/repository/api/ApiRepository.cs index 7a01223..1677ffe 100644 --- a/ModVersionChecker/repository/api/ApiRepository.cs +++ b/ModVersionChecker/repository/api/ApiRepository.cs @@ -141,7 +141,7 @@ namespace ModVersionChecker.repository.api public async Task?> SearchApps(string searchText) { - var url = $"{baseUrl}/app/search?query={Uri.EscapeDataString(searchText)}"; + var url = $"{baseUrl}/app/search?q={Uri.EscapeDataString(searchText)}"; var request = await CreateRequestAsync(HttpMethod.Get, url); var response = await _httpClient.SendAsync(request); response.EnsureSuccessStatusCode(); @@ -149,7 +149,7 @@ namespace ModVersionChecker.repository.api return JsonSerializer.Deserialize>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true }); } - public async Task> GetAppsByIds(App[] apps) + public async Task> GetAppsByIds(List apps) { var query = string.Join("&", apps.Select(a => $"id={Uri.EscapeDataString(a.Id)}")); var url = $"{baseUrl}/app/search?{query}"; diff --git a/ModVersionChecker/repository/api/IApiRepository.cs b/ModVersionChecker/repository/api/IApiRepository.cs index a1fb918..72a07be 100644 --- a/ModVersionChecker/repository/api/IApiRepository.cs +++ b/ModVersionChecker/repository/api/IApiRepository.cs @@ -12,6 +12,6 @@ namespace ModVersionChecker.repository.api Task?> SearchApps(string searchText); Task> GetTypes(); Task> GetSources(); - Task> GetAppsByIds(App[] apps); + Task> GetAppsByIds(List apps); } } \ No newline at end of file diff --git a/ModVersionChecker/repository/api/dto/AppResponse.cs b/ModVersionChecker/repository/api/dto/AppResponse.cs index d5becfb..14369b5 100644 --- a/ModVersionChecker/repository/api/dto/AppResponse.cs +++ b/ModVersionChecker/repository/api/dto/AppResponse.cs @@ -1,4 +1,5 @@ using ModVersionChecker.enums; +using ModVersionChecker.utils; using System.Text.Json.Serialization; namespace ModVersionChecker.repository.api.dto @@ -74,7 +75,8 @@ namespace ModVersionChecker.repository.api.dto LatestVersion = appResponse.LatestVersion, Status = appResponse.Status, LastCheckedAt = appResponse.LastCheckedAt, - + LocalCheckedAt = TimeUtils.GetUnixTimeMillis(null) + }; } } diff --git a/ModVersionChecker/repository/filesystem/AppStatusManager.cs b/ModVersionChecker/repository/filesystem/AppStatusManager.cs index 9159099..92cf351 100644 --- a/ModVersionChecker/repository/filesystem/AppStatusManager.cs +++ b/ModVersionChecker/repository/filesystem/AppStatusManager.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace ModVersionChecker.managers.filesystem { - public class AppStatusManager : IAppStatusManager + public class AppStatusManager : IAppStatusRepository { private Dictionary _statuses = new Dictionary(); diff --git a/ModVersionChecker/repository/filesystem/ConfigManager.cs b/ModVersionChecker/repository/filesystem/ConfigManager.cs index 36a927e..b3fa7eb 100644 --- a/ModVersionChecker/repository/filesystem/ConfigManager.cs +++ b/ModVersionChecker/repository/filesystem/ConfigManager.cs @@ -6,7 +6,7 @@ using System.Text.Json; namespace ModVersionChecker.managers.filesystem { - public class ConfigManager : IConfigManager + public class ConfigManager : IConfigRepository { private static readonly string _filePath = Path.Combine(AppContext.BaseDirectory, "data", "config.json"); diff --git a/ModVersionChecker/repository/interfaces/IAppsManager.cs b/ModVersionChecker/repository/interfaces/IAppRepository.cs similarity index 92% rename from ModVersionChecker/repository/interfaces/IAppsManager.cs rename to ModVersionChecker/repository/interfaces/IAppRepository.cs index 955d0e5..023da0d 100644 --- a/ModVersionChecker/repository/interfaces/IAppsManager.cs +++ b/ModVersionChecker/repository/interfaces/IAppRepository.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace ModVersionChecker.managers.interfaces { - public interface IAppsManager + public interface IAppRepository { List Load(); diff --git a/ModVersionChecker/repository/interfaces/IAppStatusManager.cs b/ModVersionChecker/repository/interfaces/IAppStatusRepository.cs similarity index 91% rename from ModVersionChecker/repository/interfaces/IAppStatusManager.cs rename to ModVersionChecker/repository/interfaces/IAppStatusRepository.cs index b4e0973..2e4ad56 100644 --- a/ModVersionChecker/repository/interfaces/IAppStatusManager.cs +++ b/ModVersionChecker/repository/interfaces/IAppStatusRepository.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace ModVersionChecker.managers.interfaces { - public interface IAppStatusManager + public interface IAppStatusRepository { List Load(); void Save(List appStatuses); diff --git a/ModVersionChecker/repository/interfaces/IConfigManager.cs b/ModVersionChecker/repository/interfaces/IConfigRepository.cs similarity index 88% rename from ModVersionChecker/repository/interfaces/IConfigManager.cs rename to ModVersionChecker/repository/interfaces/IConfigRepository.cs index 161e0c6..5ed56b8 100644 --- a/ModVersionChecker/repository/interfaces/IConfigManager.cs +++ b/ModVersionChecker/repository/interfaces/IConfigRepository.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace ModVersionChecker.managers.interfaces { - public interface IConfigManager + public interface IConfigRepository { Config Load(); void Save(Config config); diff --git a/ModVersionChecker/repository/interfaces/ITypeManager.cs b/ModVersionChecker/repository/interfaces/ITypeConfigRepository.cs similarity index 88% rename from ModVersionChecker/repository/interfaces/ITypeManager.cs rename to ModVersionChecker/repository/interfaces/ITypeConfigRepository.cs index 278a030..6c1eb0a 100644 --- a/ModVersionChecker/repository/interfaces/ITypeManager.cs +++ b/ModVersionChecker/repository/interfaces/ITypeConfigRepository.cs @@ -2,7 +2,7 @@ namespace ModVersionChecker.managers.interfaces { - public interface ITypeManager + public interface ITypeConfigRepository { List GetTypeConfigs(); void SaveTypeConfigs(List types); diff --git a/ModVersionChecker/repository/interfaces/IFlightSimsManager.cs b/ModVersionChecker/repository/interfaces/ITypeRepository.cs similarity index 90% rename from ModVersionChecker/repository/interfaces/IFlightSimsManager.cs rename to ModVersionChecker/repository/interfaces/ITypeRepository.cs index c2686c3..c2bc635 100644 --- a/ModVersionChecker/repository/interfaces/IFlightSimsManager.cs +++ b/ModVersionChecker/repository/interfaces/ITypeRepository.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace ModVersionChecker.managers.interfaces { - public interface IFlightSimsManager + public interface ITypeRepository { List Load(); void Save(TypeResponse config); diff --git a/ModVersionChecker/repository/litedb/AppLiteDb.cs b/ModVersionChecker/repository/litedb/AppLiteDb.cs index d94e8ab..2bf40e0 100644 --- a/ModVersionChecker/repository/litedb/AppLiteDb.cs +++ b/ModVersionChecker/repository/litedb/AppLiteDb.cs @@ -9,7 +9,7 @@ using System.Threading.Tasks; namespace ModVersionChecker.managers.litedb { - public class AppLiteDb : LiteDb, IAppsManager + public class AppLiteDb : LiteDb, IAppRepository { protected override string collection => LiteDb.APPS_COLLECTION; diff --git a/ModVersionChecker/repository/litedb/ConfigLiteDb.cs b/ModVersionChecker/repository/litedb/ConfigLiteDb.cs index 4c7510c..1d141cc 100644 --- a/ModVersionChecker/repository/litedb/ConfigLiteDb.cs +++ b/ModVersionChecker/repository/litedb/ConfigLiteDb.cs @@ -3,7 +3,7 @@ using ModVersionChecker.model; namespace ModVersionChecker.managers.litedb { - public class ConfigLiteDb : LiteDb, IConfigManager + public class ConfigLiteDb : LiteDb, IConfigRepository { protected override string collection => LiteDb.CONFIG_COLLECTION; public Config Load() diff --git a/ModVersionChecker/repository/litedb/TypeConfigLiteDb.cs b/ModVersionChecker/repository/litedb/TypeConfigLiteDb.cs index 14aee6e..6734674 100644 --- a/ModVersionChecker/repository/litedb/TypeConfigLiteDb.cs +++ b/ModVersionChecker/repository/litedb/TypeConfigLiteDb.cs @@ -3,7 +3,7 @@ using ModVersionChecker.model; namespace ModVersionChecker.managers.litedb { - internal class TypeConfigLiteDb : LiteDb, ITypeManager + internal class TypeConfigLiteDb : LiteDb, ITypeConfigRepository { protected override string collection => TYPES_COLLECTION; diff --git a/ModVersionChecker/repository/litedb/TypeLiteDb.cs b/ModVersionChecker/repository/litedb/TypeLiteDb.cs index 5ea1246..941cb5d 100644 --- a/ModVersionChecker/repository/litedb/TypeLiteDb.cs +++ b/ModVersionChecker/repository/litedb/TypeLiteDb.cs @@ -8,7 +8,7 @@ using System.Threading.Tasks; namespace ModVersionChecker.managers.litedb { - internal class TypeLiteDb : LiteDb, IFlightSimsManager + internal class TypeLiteDb : LiteDb, ITypeRepository { protected override string collection => FLIGHT_SIMS_COLLECTION; diff --git a/ModVersionChecker/service/ApiService.cs b/ModVersionChecker/service/ApiService.cs index 39a59ed..de94037 100644 --- a/ModVersionChecker/service/ApiService.cs +++ b/ModVersionChecker/service/ApiService.cs @@ -31,16 +31,16 @@ namespace ModVersionChecker.service public Task> GetSources() => _apiRepository.GetSources(); - public async Task> GetAppsByIds(App[] apps) + public async Task> GetAppsByIds(List apps) { var appResponses = await _apiRepository.GetAppsByIds(apps); return appResponses.Select(AppResponse.toModel).ToList(); } - public Task?> SearchApps(string searchText) + public async Task> SearchApps(string searchText) { - var appResponses = _apiRepository.SearchApps(searchText); - return appResponses.ContinueWith(t => t.Result?.Select(AppResponse.toModel).ToList()); + var appResponses = await _apiRepository.SearchApps(searchText); + return appResponses.Select(AppResponse.toModel).ToList(); } } diff --git a/ModVersionChecker/service/AppService.cs b/ModVersionChecker/service/AppService.cs new file mode 100644 index 0000000..027193a --- /dev/null +++ b/ModVersionChecker/service/AppService.cs @@ -0,0 +1,203 @@ +using ModVersionChecker.enums; +using ModVersionChecker.managers.interfaces; +using ModVersionChecker.model; +using ModVersionChecker.service.interfaces; +using ModVersionChecker.utils; + +namespace ModVersionChecker.service +{ + public class AppService: IAppService + { + private readonly IApiService _apiService; + private readonly IAppRepository _appRepository; + private readonly IVersionService _versionService; + private readonly IStateService _stateService; + private readonly INotificationService _notificationService; + private readonly Config _config; + + public AppService( + IApiService apiService, + IVersionService versionService, + IAppRepository appManager, + IStateService stateService, + INotificationService notificationService + + ) { + _apiService = apiService; + _appRepository = appManager; + _versionService = versionService; + _stateService = stateService; + _notificationService = notificationService; + _config = _stateService.GetConfig(); + } + + public bool CreateApp(App? app) + { + if (app != null) + { + _appRepository.Insert(app); + return true; + } + return false; + } + + public bool DeleteApp(App? app) + { + if (app !=null) + { + _appRepository.Delete(app.Id); + return true; + } + return false; + } + + public bool UpdateApp(App? app) + { + if (app != null) + { + _appRepository.Update(app); + return true; + } + return false; + } + + public async Task> GetAndUpdateCurrentApps() + { + + try + { + List apps = _appRepository.Load(); + + if (apps == null) throw new InvalidOperationException("Failed to load apps: repository returned null."); + if (apps.Count == 0) return new List(); + + List updatedApps = await _apiService.GetAppsByIds(apps); + + if (updatedApps == null) throw new InvalidOperationException("Failed to load apps: repository returned null."); + if (updatedApps.Count == 0) return apps; + + foreach (App app in updatedApps) + { + app.CurrentVersion = _versionService.GetCurrentVersion(app); + CheckAppStatus(app); + _appRepository.Update(app); + } + _stateService.SetApps(updatedApps); + return updatedApps; + } + catch (Exception ex) + { + Console.WriteLine(ex); + return new List(); + } + } + + public App CheckAppStatus(App app) + { + var status = AppStatus.NONE; + if (app.LatestVersion == null) + { + app.Status = AppStatus.ERROR; + _appRepository.Update(app); + return app; + } + var currentVersion = app.CurrentVersion; + var updateMessage = ""; + if (_versionService.IsUpdateAvailable(currentVersion, app.LatestVersion)) + { + updateMessage = $"{app.Name}: New version {app.LatestVersion} (current: {currentVersion})"; + status = AppStatus.UPDATE_AVAILABLE; + } + app.Status = status; + app.LastCheckedAt = TimeUtils.GetUnixTimeMillis(null); + return app; + } + + public void CheckAllApps() + { + + var apps = _appRepository.Load(); + var sources = _stateService.GetSources(); + List errorMessages = new List(); + List updateMessages = new List(); + + if (apps == null || apps.Count == 0) + { + return; + } + foreach (App app in apps) + { + + var sourceId = app.Source; + + if ( + app.Status != AppStatus.ERROR && app.LastCheckedAt != 0 && + app.LastCheckedAt < TimeUtils.GetUnixTimeMillis(DateTime.UtcNow.AddMinutes(-60)) || + string.IsNullOrWhiteSpace(sourceId) + ) + { + continue; + } + + try + { + var latesstVersion = app.LatestVersion; + var source = sources.FirstOrDefault(s => s.Id == sourceId); + if (source == null) + { + errorMessages.Add($"{app.Name} has an invalid source: {sourceId}"); + continue; + } + var typeConfig = _config.Types.FirstOrDefault(t => t.ShortName == app.Type); + if (typeConfig == null) + { + errorMessages.Add($"{app.Name} has no valid type config."); + continue; + } + app.CurrentVersion = VersionUtils.GetCurrentVersion(app, typeConfig); + + var updatedApp = CheckAppStatus(app); + _appRepository.Update(updatedApp); + if (updatedApp.Status == AppStatus.UPDATE_AVAILABLE) + { + updateMessages.Add($"{app.Name}: New version {app.LatestVersion} (current: {app.CurrentVersion})"); + } + } + catch (Exception ex) + { + errorMessages.Add($"Failed to check {app.Name}: {ex.Message}"); + } + } + + if (updateMessages.Count > 0) + { + _notificationService.ShowBalloonTip( + 10000, + "Updates Available", + string.Join("\n", updateMessages), + ToolTipIcon.Info + ); + } + if (errorMessages.Count > 0) + { + _notificationService.ShowBalloonTip( + 10000, + "Errors", + string.Join("\n", errorMessages), + ToolTipIcon.Error + ); + } + } + + + public List PurgeExisitingApps(List apps) + { + var _existingApps = _stateService.GetApps(); + if (_existingApps == null || _existingApps.Count == 0) + { + return apps; + } + return apps.Where(a => !_existingApps.Any(e => e.Id == a.Id)).ToList(); + } + } +} diff --git a/ModVersionChecker/service/NotifyIconService.cs b/ModVersionChecker/service/NotificationService.cs similarity index 90% rename from ModVersionChecker/service/NotifyIconService.cs rename to ModVersionChecker/service/NotificationService.cs index fdb06b4..8b873b5 100644 --- a/ModVersionChecker/service/NotifyIconService.cs +++ b/ModVersionChecker/service/NotificationService.cs @@ -7,7 +7,7 @@ using System.Threading.Tasks; namespace ModVersionChecker.service { - public class NotifyIconService : INotifyIconService + public class NotificationService : INotificationService { private NotifyIcon? _notifyIcon; public void SetNotifyIcon(NotifyIcon icon) diff --git a/ModVersionChecker/service/StateService.cs b/ModVersionChecker/service/StateService.cs new file mode 100644 index 0000000..9b3c9c3 --- /dev/null +++ b/ModVersionChecker/service/StateService.cs @@ -0,0 +1,41 @@ +using ModVersionChecker.managers.interfaces; +using ModVersionChecker.model; +using ModVersionChecker.repository.api.dto; +using ModVersionChecker.service.interfaces; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ModVersionChecker.service +{ + public class StateService: IStateService + { + private List apps = new List(); + private List sources = new List(); + private List types = new List(); + private Config config = new Config(); + private readonly IAppRepository _appRepository; + + public StateService( + IAppRepository appRepository + ) { + _appRepository = appRepository; + } + + public List GetApps() => apps; + public void SetApps(List apps) => this.apps = apps; + public List GetSources() => sources; + public void SetSources(List sources) => this.sources = sources; + public List GetTypes() => types; + public void SetTypes(List types) => this.types = types; + public Config GetConfig() => config; + public void SetConfig(Config config) => this.config = config; + + + public void UpdateApps() => this.apps = _appRepository.Load(); + + + } +} diff --git a/ModVersionChecker/service/VersionService.cs b/ModVersionChecker/service/VersionService.cs index 4347525..fdf556b 100644 --- a/ModVersionChecker/service/VersionService.cs +++ b/ModVersionChecker/service/VersionService.cs @@ -9,121 +9,25 @@ namespace ModVersionChecker.service { public class VersionService: IVersionService { - private readonly IApiService _apiService; - private readonly IAppsManager _appsManager; - private readonly INotifyIconService _notifyIconService; private readonly Config _globalConfig; public VersionService( - IApiService apiVersionService, - IAppsManager appsManager, - IConfigManager configManager, - INotifyIconService notifyIconService) - { - _apiService = apiVersionService; - _appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager)); - _notifyIconService = notifyIconService ?? throw new ArgumentNullException(nameof(notifyIconService)); + IConfigRepository configManager + ) { _globalConfig = configManager.Load() ?? new Config(); } - public App CheckApp(App app) + public string GetCurrentVersion(App app) { - var status = AppStatus.NONE; - if (app.LatestVersion== null) + var typeConfig = _globalConfig.Types.FirstOrDefault(t => t.ShortName == app.Type); + if (typeConfig == null) { - app.Status = AppStatus.ERROR; - _appsManager.Update(app); - return app; + throw new InvalidOperationException($"No type config found for app type: {app.Type}"); } - var currentVersion = app.CurrentVersion; - var updateMessage = ""; - if (isUpdateAvailable(currentVersion, app.LatestVersion)) - { - updateMessage = $"{app.Name}: New version {app.LatestVersion} (current: {currentVersion})"; - status = AppStatus.UPDATE_AVAILABLE; - } - app.Status = status; - app.LastCheckedAt = TimeUtils.GetUnixTimeMillis(null); - _appsManager.Update(app); - return app; + return VersionUtils.GetCurrentVersion(app, typeConfig); } - public async Task CheckAllApps() - { - - var apps = _appsManager.Load(); - var sources = await _apiService.GetSources(); - var appVersionsMap = await _apiService.GetAppVersionsAsync(apps); - List errorMessages = new List(); - List updateMessages = new List(); - - if (apps == null || apps.Count == 0) - { - return; - } - foreach (App app in apps) - { - - var sourceId = app.Source; - - if ( - app.Status != AppStatus.ERROR && app.LastCheckedAt != 0 && app.LastCheckedAt < TimeUtils.GetUnixTimeMillis(DateTime.UtcNow.AddMinutes(-60)) || - !app.Active || string.IsNullOrWhiteSpace(sourceId) - ) - { - continue; - } - - try - { - var latesstVersion = appVersionsMap.FirstOrDefault(a => a.Id == app.Id)?.LatestVersion; - var source = sources.FirstOrDefault(s => s.Id == sourceId); - if (source == null) - { - errorMessages.Add($"{app.Name} has an invalid source: {sourceId}"); - continue; - } - var typeConfig = _globalConfig.Types.FirstOrDefault(t => t.ShortName == app.Type); - if (typeConfig == null) - { - errorMessages.Add($"{app.Name} has no valid type config."); - continue; - } - app.CurrentVersion = VersionUtils.GetCurrentVersion(app, typeConfig); - - var updatedApp = CheckApp(app); - if (updatedApp.Status == AppStatus.UPDATE_AVAILABLE) - { - updateMessages.Add($"{app.Name}: New version {app.LatestVersion} (current: {app.CurrentVersion})"); - } - } - catch (Exception ex) - { - errorMessages.Add($"Failed to check {app.Name}: {ex.Message}"); - } - } - - if (updateMessages.Count > 0) - { - _notifyIconService.ShowBalloonTip( - 10000, - "Updates Available", - string.Join("\n", updateMessages), - ToolTipIcon.Info - ); - } - if (errorMessages.Count > 0) - { - _notifyIconService.ShowBalloonTip( - 10000, - "Errors", - string.Join("\n", errorMessages), - ToolTipIcon.Error - ); - } - } - - private bool isUpdateAvailable(string currentVersion, string latestVersion) + public bool IsUpdateAvailable(string currentVersion, string latestVersion) { try { diff --git a/ModVersionChecker/service/interfaces/IApiService.cs b/ModVersionChecker/service/interfaces/IApiService.cs index 9f8c8da..71a3e78 100644 --- a/ModVersionChecker/service/interfaces/IApiService.cs +++ b/ModVersionChecker/service/interfaces/IApiService.cs @@ -12,8 +12,7 @@ namespace ModVersionChecker.service.interfaces Task> GetSources(); Task GetAppLatestVersionAsync(App app); Task AuthenticateAsync(string username, string password); - Task> GetAppsByIds(App[] apps); - Task?> SearchApps(string searchText); - + Task> GetAppsByIds(List apps); + Task> SearchApps(string searchText); } } \ No newline at end of file diff --git a/ModVersionChecker/service/interfaces/IAppService.cs b/ModVersionChecker/service/interfaces/IAppService.cs new file mode 100644 index 0000000..a1c2d9e --- /dev/null +++ b/ModVersionChecker/service/interfaces/IAppService.cs @@ -0,0 +1,20 @@ +namespace ModVersionChecker.service.interfaces +{ + public interface IAppService + { + // List GetAppsById(List apps); + // bool SaveApps(List apps); + // App? GetAppById(string id); + + bool CreateApp(App? app); + bool UpdateApp(App? app); + + bool DeleteApp(App? app); + Task> GetAndUpdateCurrentApps(); + + App CheckAppStatus(App app); + void CheckAllApps(); + + List PurgeExisitingApps(List apps); + } +} diff --git a/ModVersionChecker/service/interfaces/INotifyIconService.cs b/ModVersionChecker/service/interfaces/INotificationService.cs similarity index 88% rename from ModVersionChecker/service/interfaces/INotifyIconService.cs rename to ModVersionChecker/service/interfaces/INotificationService.cs index 062a0f0..99fe140 100644 --- a/ModVersionChecker/service/interfaces/INotifyIconService.cs +++ b/ModVersionChecker/service/interfaces/INotificationService.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace ModVersionChecker.service.interfaces { - public interface INotifyIconService + public interface INotificationService { void SetNotifyIcon(NotifyIcon icon); void ShowBalloonTip(int millis, string title, string message, ToolTipIcon icon); diff --git a/ModVersionChecker/service/interfaces/IStateService.cs b/ModVersionChecker/service/interfaces/IStateService.cs new file mode 100644 index 0000000..7dfa78e --- /dev/null +++ b/ModVersionChecker/service/interfaces/IStateService.cs @@ -0,0 +1,20 @@ +using ModVersionChecker.repository.api.dto; +using ModVersionChecker.model; + + +namespace ModVersionChecker.service.interfaces +{ + public interface IStateService + { + List GetApps(); + void SetApps(List apps); + + void UpdateApps(); + List GetSources(); + void SetSources(List sources); + List GetTypes(); + void SetTypes(List types); + Config GetConfig(); + void SetConfig(Config config); + } +} diff --git a/ModVersionChecker/service/interfaces/IVersionService.cs b/ModVersionChecker/service/interfaces/IVersionService.cs index 734cdb2..d147e07 100644 --- a/ModVersionChecker/service/interfaces/IVersionService.cs +++ b/ModVersionChecker/service/interfaces/IVersionService.cs @@ -8,8 +8,12 @@ namespace ModVersionChecker.service.interfaces { public interface IVersionService { - App CheckApp(App app); + //App CheckAppStatus(App app); - Task CheckAllApps(); + //Task CheckAllApps(); + + string GetCurrentVersion(App app); + + bool IsUpdateAvailable(string currentVersion, string latestVersion); } } diff --git a/ModVersionChecker/ui/forms/AppDetailsForm.cs b/ModVersionChecker/ui/forms/AppDetailsForm.cs index 7a544f3..e6630a1 100644 --- a/ModVersionChecker/ui/forms/AppDetailsForm.cs +++ b/ModVersionChecker/ui/forms/AppDetailsForm.cs @@ -9,15 +9,18 @@ namespace ModVersionChecker.ui.forms private ListBox _resultsList; private Button _addButton; private readonly IApiService _apiService; - private readonly IAppsManager _appsManager; + private readonly IAppService _appService; public App? SelectedApp { get; private set; } public event EventHandler OnAppAdded; - public AppDetailsForm(IApiService apiService, IAppsManager appsManager) + public AppDetailsForm( + IApiService apiService, + IAppService appService + ) { _apiService = apiService ?? throw new ArgumentNullException(nameof(apiService)); - _appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager)); + _appService = appService ?? throw new ArgumentNullException(nameof(appService)); InitializeComponent(); } @@ -27,6 +30,7 @@ namespace ModVersionChecker.ui.forms Width = 400; Height = 500; Padding = new Padding(20); + StartPosition = FormStartPosition.CenterParent; _searchBox = new TextBox { Dock = DockStyle.Top, PlaceholderText = "Search..." }; _resultsList = new ListBox { Dock = DockStyle.Fill }; @@ -54,8 +58,8 @@ namespace ModVersionChecker.ui.forms _resultsList.DataSource = null; return; } - var results = await _apiService.SearchApps(query); - _resultsList.DataSource = results; + var apiResults = await _apiService.SearchApps(query); + _resultsList.DataSource = _appService.PurgeExisitingApps(apiResults); _resultsList.DisplayMember = "Name"; } @@ -64,7 +68,7 @@ namespace ModVersionChecker.ui.forms if (_resultsList.SelectedItem is App app) { SelectedApp = app; - _appsManager.Insert(app); + _appService.CreateApp(app); DialogResult = DialogResult.OK; OnAppAdded?.Invoke(this, "App saved"); Close(); diff --git a/ModVersionChecker/ui/forms/FormFactory.cs b/ModVersionChecker/ui/forms/FormFactory.cs index 09b55f3..e814c4b 100644 --- a/ModVersionChecker/ui/forms/FormFactory.cs +++ b/ModVersionChecker/ui/forms/FormFactory.cs @@ -16,8 +16,8 @@ namespace ModVersionChecker.ui.forms public AppDetailsForm CreateAppDetailsForm(App? app, bool isEditable, EventHandler? onAppSaved) { var apiService = _serviceProvider.GetRequiredService(); - var appsManager = _serviceProvider.GetRequiredService(); - var form = new AppDetailsForm(apiService, appsManager); + var appService= _serviceProvider.GetRequiredService(); + var form = new AppDetailsForm(apiService, appService); if (onAppSaved != null) { form.OnAppAdded += onAppSaved; @@ -27,15 +27,15 @@ namespace ModVersionChecker.ui.forms public GlobalConfigForm CreateGlobalConfigForm() { - var configManager = _serviceProvider.GetRequiredService(); + var configManager = _serviceProvider.GetRequiredService(); return new GlobalConfigForm(configManager); } public TypeConfigForm CreateTypeConfigForm() { - var typeManager = _serviceProvider.GetRequiredService(); + var typeManager = _serviceProvider.GetRequiredService(); var apiService = _serviceProvider.GetRequiredService(); - var configManager = _serviceProvider.GetRequiredService(); + var configManager = _serviceProvider.GetRequiredService(); return new TypeConfigForm(typeManager, apiService, configManager); } diff --git a/ModVersionChecker/ui/forms/GlobalConfigForm.cs b/ModVersionChecker/ui/forms/GlobalConfigForm.cs index f096934..11a1c00 100644 --- a/ModVersionChecker/ui/forms/GlobalConfigForm.cs +++ b/ModVersionChecker/ui/forms/GlobalConfigForm.cs @@ -5,7 +5,7 @@ namespace ModVersionChecker.ui.forms { public class GlobalConfigForm : Form { - private IConfigManager _configManager; + private IConfigRepository _configManager; private Config _config; private Label _millislabel, _checkStartupLabel, _runOnStartupLabel; @@ -15,7 +15,7 @@ namespace ModVersionChecker.ui.forms private TableLayoutPanel _mainLayout, _configsPanel; private FlowLayoutPanel _buttonPanel; - public GlobalConfigForm(IConfigManager configManager) + public GlobalConfigForm(IConfigRepository configManager) { _configManager = configManager; _config = _configManager.GetConfig(); diff --git a/ModVersionChecker/ui/forms/MainForm.cs b/ModVersionChecker/ui/forms/MainForm.cs index dfda2a9..f95975a 100644 --- a/ModVersionChecker/ui/forms/MainForm.cs +++ b/ModVersionChecker/ui/forms/MainForm.cs @@ -1,7 +1,6 @@ using ModVersionChecker.enums; using ModVersionChecker.managers.interfaces; using ModVersionChecker.model; -using ModVersionChecker.repository.api.dto; using ModVersionChecker.service.interfaces; using ModVersionChecker.utils; @@ -10,15 +9,13 @@ namespace ModVersionChecker.ui.forms { public class MainForm : Form { - private readonly IAppsManager _appsManager; + private readonly IStateService _stateService; private readonly IFormFactory _formFactory; - private readonly IFlightSimsManager _fsManager; private readonly IApiService _apiService; - private readonly IVersionService _versionService; + private readonly IAppService _appService; private readonly TableLayoutPanel _mainLayout; private readonly Config _globalConfig; - private List _apps = new List(); private ListView _listView; private ImageList _statusImageList = new ImageList(); @@ -26,27 +23,20 @@ namespace ModVersionChecker.ui.forms public event EventHandler OnRecheck; private EventHandler onAppSavedHandler; private MenuStrip _menuStrip; - private List _fsMods; private readonly Dictionary _fsModPathTextBoxes = new Dictionary(); - private List _sources = new List(); - private List _typesDef = new List(); - public MainForm( - IConfigManager configManager, - IAppsManager appsManager, + IStateService stateService, + IAppService appService, + IConfigRepository configManager, IFormFactory formFactory, - IFlightSimsManager fsManager, - IApiService apiService, - ITypeManager typeConfigManager, - IVersionService versionService) + IApiService apiService + ) { - _appsManager = appsManager ?? throw new ArgumentNullException(nameof(appsManager)); _formFactory = formFactory ?? throw new ArgumentNullException(nameof(formFactory)); - _fsManager = fsManager ?? throw new ArgumentNullException(nameof(fsManager)); _apiService = apiService ?? throw new ArgumentNullException(nameof(apiService)); - _versionService = versionService ?? throw new ArgumentNullException(nameof(versionService)); - _fsMods = _fsManager.Load(); + _appService = appService ?? throw new ArgumentNullException(nameof(appService)); + _stateService = stateService ?? throw new ArgumentNullException(nameof(stateService)); _statusImageList.Images.Add("none", new Icon("Resources/ok-icon.ico")); _statusImageList.Images.Add("update", new Icon("Resources/up-icon.ico")); @@ -74,6 +64,7 @@ namespace ModVersionChecker.ui.forms var app = form.SelectedApp; UpdateCurrentVersion(app); + _stateService.UpdateApps(); UpdateListView(); OnConfigChanged?.Invoke(this, EventArgs.Empty); }; @@ -81,6 +72,22 @@ namespace ModVersionChecker.ui.forms this.Load += MainForm_LoadAsync; } + + private async void MainForm_LoadAsync(object? sender, EventArgs e) + { + await _apiService.AuthenticateAsync("user", "user"); + + var apps = await _appService.GetAndUpdateCurrentApps(); + var sources = await _apiService.GetSources(); + var types = await _apiService.GetTypes(); + + _stateService.SetApps(apps); + _stateService.SetSources(sources); + _stateService.SetTypes(types); + _stateService.SetConfig(_globalConfig); + UpdateListView(); + } + private void UpdateCurrentVersion(App app) { TypeConfig? typeConfig = _globalConfig.Types.FirstOrDefault(tc => app.Type == tc.ShortName); @@ -92,21 +99,12 @@ namespace ModVersionChecker.ui.forms app.CurrentVersion = versionInDisk; app.LastCheckedAt = TimeUtils.GetUnixTimeMillis(DateTime.Now); - _versionService.CheckApp(app); + _appService.CheckAppStatus(app); + _appService.UpdateApp(app); } } - - private async void MainForm_LoadAsync(object? sender, EventArgs e) - { - await _apiService.AuthenticateAsync("user", "user"); - _apps = await _apiService.GetAppsByIds([]); - _sources = await _apiService.GetSources(); - _typesDef = await _apiService.GetTypes(); - UpdateListView(); - } - private TableLayoutPanel GetMainLayout() { // Initialize the main layout panel @@ -197,10 +195,10 @@ namespace ModVersionChecker.ui.forms }; // Add recheck logic here - recheckButton.Click += async (s, e) => + recheckButton.Click += (s, e) => { recheckButton.Enabled = false; - await _versionService.CheckAllApps(); + _appService.CheckAllApps(); UpdateListView(); //OnRecheck.Invoke(this, "User initiated recheck from ConfigForm"); recheckButton.Enabled = true; @@ -212,7 +210,7 @@ namespace ModVersionChecker.ui.forms public void UpdateListView() { - _apps = _appsManager.Load(); + var _apps = _stateService.GetApps(); _listView.Items.Clear(); foreach (var app in _apps) { @@ -252,10 +250,13 @@ namespace ModVersionChecker.ui.forms private void DeleteApp(App app) { - var result = MessageBox.Show($"Are you sure you want to delete '{app?.Name ?? ""}'?", "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); + if (app == null) return; + + var result = MessageBox.Show($"Are you sure you want to delete '{app.Name ?? ""}'?", "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (result == DialogResult.Yes) { - _appsManager.Delete((_listView.SelectedItems[0].Tag as App).Id); + _appService.DeleteApp((_listView.SelectedItems[0].Tag as App)); + _stateService.UpdateApps(); UpdateListView(); OnConfigChanged?.Invoke(this, EventArgs.Empty); } diff --git a/ModVersionChecker/ui/forms/TypeConfigForm.cs b/ModVersionChecker/ui/forms/TypeConfigForm.cs index cb3eacd..42dcb5d 100644 --- a/ModVersionChecker/ui/forms/TypeConfigForm.cs +++ b/ModVersionChecker/ui/forms/TypeConfigForm.cs @@ -19,13 +19,13 @@ namespace ModVersionChecker.ui.forms private FlowLayoutPanel _mainPanel; private Button _saveButton, _cancelButton; private readonly IApiService _apiService; - private readonly IConfigManager _configManager; - private readonly ITypeManager _typeManager; + private readonly IConfigRepository _configManager; + private readonly ITypeConfigRepository _typeManager; public TypeConfigForm( - ITypeManager typeManager, + ITypeConfigRepository typeManager, IApiService apiService, - IConfigManager configManager + IConfigRepository configManager ) { _apiService = apiService ?? throw new ArgumentNullException(nameof(apiService));