From 329eae3a25ee57df041f660c67c8682b4369886d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Kaan=20K=C3=B6se?= Date: Wed, 17 Jul 2024 22:36:10 +0200 Subject: [PATCH] UIMessage communication. Single instancing for server and re-connection mechanism on suspension. --- Wino.BackgroundTasks/SessionConnectedTask.cs | 55 +++---- Wino.Core.Domain/Interfaces/IServerMessage.cs | 1 + .../IWinoServerConnectionManager.cs | 8 +- Wino.Core.UWP/CoreUWPContainerSetup.cs | 1 - .../Services/BackgroundSynchronizer.cs | 144 ------------------ .../Services/WinoServerConnectionManager.cs | 113 +++++++++++++- Wino.Core.UWP/Wino.Core.UWP.csproj | 5 +- Wino.Core/Requests/ArchiveRequest.cs | 2 +- Wino.Core/Requests/ChangeFlagRequest.cs | 2 +- Wino.Core/Requests/CreateDraftRequest.cs | 2 +- Wino.Core/Requests/DeleteRequest.cs | 2 +- Wino.Core/Requests/EmptyFolderRequest.cs | 2 +- Wino.Core/Requests/MarkFolderAsReadRequest.cs | 2 +- Wino.Core/Requests/MarkReadRequest.cs | 2 +- Wino.Core/Requests/MoveRequest.cs | 2 +- Wino.Core/Requests/RenameFolderRequest.cs | 2 +- Wino.Core/Requests/SendDraftRequest.cs | 2 +- Wino.Core/Services/AccountService.cs | 2 +- Wino.Core/Services/FolderService.cs | 2 +- Wino.Core/Services/MailService.cs | 2 +- Wino.Core/Services/WinoRequestDelegator.cs | 1 + Wino.Core/Wino.Core.csproj | 2 +- .../AccountDetailsPageViewModel.cs | 2 +- .../AccountManagementViewModel.cs | 2 +- Wino.Mail.ViewModels/AppShellViewModel.cs | 13 +- Wino.Mail.ViewModels/BaseViewModel.cs | 6 +- Wino.Mail.ViewModels/MailListPageViewModel.cs | 2 + .../MergedAccountDetailsPageViewModel.cs | 2 +- .../Wino.Mail.ViewModels.csproj | 2 +- .../Activation/BackgroundActivationHandler.cs | 20 +-- Wino.Mail/App.xaml.cs | 15 +- Wino.Mail/AppShell.xaml | 2 +- Wino.Mail/Services/DialogService.cs | 2 +- .../Views/NewAccountManagementPage.xaml.cs | 2 +- Wino.Mail/Wino.Mail.csproj | 8 +- .../Accounts/AccountMenuItemExtended.cs | 2 +- .../Accounts/AccountMenuItemsReordered.cs | 2 +- .../Accounts/AccountsMenuRefreshRequested.cs | 2 +- .../ProtocolAuthorizationCallbackReceived.cs | 2 +- .../Mails/CancelRenderingContentRequested.cs | 2 +- .../Mails/ClearMailSelectionsRequested.cs | 2 +- .../Mails/CreateNewComposeMailRequested.cs | 2 +- .../Mails/DisposeRenderingFrameRequested.cs | 2 +- .../Client/Mails/HtmlRenderingRequested.cs | 2 +- .../Mails/ImapSetupBackNavigationRequested.cs | 2 +- .../Client/Mails/ImapSetupDismissRequested.cs | 2 +- .../Mails/ImapSetupNavigationRequested.cs | 2 +- .../Mails/MailItemNavigationRequested.cs | 2 +- .../Client/Mails/NavigateMailFolderEvent.cs | 2 +- .../Mails/RefreshUnreadCountsMessage.cs | 2 +- .../Client/Mails/SaveAsPDFRequested.cs | 2 +- .../Client/Mails/SelectedMailItemsChanged.cs | 2 +- .../BackBreadcrumNavigationRequested.cs | 2 +- .../BreadcrumbNavigationRequested.cs | 2 +- .../Navigation/NavigateSettingsRequested.cs | 2 +- .../Client/Shell/ApplicationThemeChanged.cs | 2 +- ...ateNewMailWithMultipleAccountsRequested.cs | 2 +- .../Client/Shell/InfoBarMessageRequested.cs | 2 +- Wino.Messages/Client/Shell/LanguageChanged.cs | 2 +- .../Shell/MailtoProtocolMessageRequested.cs | 2 +- .../Client/Shell/NavigationPaneModeChanged.cs | 2 +- .../Client/Shell/ShellStateUpdated.cs | 2 +- .../AccountSynchronizationCompleted.cs | 2 +- .../AccountSynchronizerStateChanged.cs | 2 +- .../NewSynchronizationRequested.cs | 2 +- Wino.Messages/Enums/MessageType.cs | 8 + Wino.Messages/MessageConstants.cs | 9 ++ Wino.Messages/Server/AccountCreatedMessage.cs | 5 +- Wino.Messages/Server/AccountRemovedMessage.cs | 5 +- Wino.Messages/Server/AccountUpdatedMessage.cs | 5 +- Wino.Messages/Server/DraftCreated.cs | 5 +- Wino.Messages/Server/DraftFailed.cs | 5 +- Wino.Messages/Server/DraftMapped.cs | 6 +- Wino.Messages/Server/FolderRenamed.cs | 7 +- .../Server/FolderSynchronizationEnabled.cs | 7 +- Wino.Messages/Server/MailAddedMessage.cs | 5 +- Wino.Messages/Server/MailDownloadedMessage.cs | 5 +- Wino.Messages/Server/MailRemovedMessage.cs | 5 +- Wino.Messages/Server/MailUpdatedMessage.cs | 5 +- Wino.Messages/Server/MergedInboxRenamed.cs | 5 +- Wino.Messages/Server/ServerMessageBase.cs | 6 + ....Messages.csproj => Wino.Messaging.csproj} | 1 + Wino.Server/App.xaml.cs | 60 +++++++- Wino.Server/ServerContext.cs | 75 ++++++++- Wino.Server/TrayIconViewModel.cs | 4 +- Wino.Server/Wino.Server.csproj | 2 +- Wino.sln | 4 +- 87 files changed, 412 insertions(+), 321 deletions(-) delete mode 100644 Wino.Core.UWP/Services/BackgroundSynchronizer.cs create mode 100644 Wino.Messages/Enums/MessageType.cs create mode 100644 Wino.Messages/MessageConstants.cs create mode 100644 Wino.Messages/Server/ServerMessageBase.cs rename Wino.Messages/{Wino.Messages.csproj => Wino.Messaging.csproj} (88%) diff --git a/Wino.BackgroundTasks/SessionConnectedTask.cs b/Wino.BackgroundTasks/SessionConnectedTask.cs index 90db6769..84bc2eaa 100644 --- a/Wino.BackgroundTasks/SessionConnectedTask.cs +++ b/Wino.BackgroundTasks/SessionConnectedTask.cs @@ -1,13 +1,4 @@ -using System; -using Microsoft.Extensions.DependencyInjection; -using Serilog; -using Windows.ApplicationModel.Background; -using Windows.Storage; -using Wino.Core; -using Wino.Core.Domain.Interfaces; -using Wino.Core.Services; -using Wino.Core.UWP; -using Wino.Services; +using Windows.ApplicationModel.Background; namespace Wino.BackgroundTasks { @@ -17,32 +8,34 @@ namespace Wino.BackgroundTasks { var def = taskInstance.GetDeferral(); - try - { - var services = new ServiceCollection(); + //try + //{ + // var services = new ServiceCollection(); - services.RegisterCoreServices(); - services.RegisterCoreUWPServices(); + // services.RegisterCoreServices(); + // services.RegisterCoreUWPServices(); - var providere = services.BuildServiceProvider(); + // var providere = services.BuildServiceProvider(); - var backgroundTaskService = providere.GetService(); - var dbService = providere.GetService(); - var logInitializer = providere.GetService(); + // var backgroundTaskService = providere.GetService(); + // var dbService = providere.GetService(); + // var logInitializer = providere.GetService(); - logInitializer.SetupLogger(ApplicationData.Current.LocalFolder.Path); + // logInitializer.SetupLogger(ApplicationData.Current.LocalFolder.Path); - await dbService.InitializeAsync(); - await backgroundTaskService.RunBackgroundSynchronizationAsync(Core.Domain.Enums.BackgroundSynchronizationReason.SessionConnected); - } - catch (Exception ex) - { - Log.Error(ex, "Background synchronization failed from background task."); - } - finally - { - def.Complete(); - } + // await dbService.InitializeAsync(); + // await backgroundTaskService.RunBackgroundSynchronizationAsync(Core.Domain.Enums.BackgroundSynchronizationReason.SessionConnected); + //} + //catch (Exception ex) + //{ + // Log.Error(ex, "Background synchronization failed from background task."); + //} + //finally + //{ + // def.Complete(); + //} + + def.Complete(); } } } diff --git a/Wino.Core.Domain/Interfaces/IServerMessage.cs b/Wino.Core.Domain/Interfaces/IServerMessage.cs index 4668e897..5b644cb0 100644 --- a/Wino.Core.Domain/Interfaces/IServerMessage.cs +++ b/Wino.Core.Domain/Interfaces/IServerMessage.cs @@ -6,5 +6,6 @@ /// They are sent either from processor or view models to signal some other /// parts of the application. /// + public interface IServerMessage; } diff --git a/Wino.Core.Domain/Interfaces/IWinoServerConnectionManager.cs b/Wino.Core.Domain/Interfaces/IWinoServerConnectionManager.cs index 60113a15..6ec12208 100644 --- a/Wino.Core.Domain/Interfaces/IWinoServerConnectionManager.cs +++ b/Wino.Core.Domain/Interfaces/IWinoServerConnectionManager.cs @@ -1,13 +1,17 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using Wino.Core.Domain.Enums; namespace Wino.Core.Domain.Interfaces { public interface IWinoServerConnectionManager { - WinoServerConnectionStatus Status { get; } Task ConnectAsync(); Task DisconnectAsync(); + + WinoServerConnectionStatus Status { get; } + event EventHandler StatusChanged; + void DisposeConnection(); } public interface IWinoServerConnectionManager : IWinoServerConnectionManager, IInitializeAsync diff --git a/Wino.Core.UWP/CoreUWPContainerSetup.cs b/Wino.Core.UWP/CoreUWPContainerSetup.cs index 300e4d6f..cde45f8e 100644 --- a/Wino.Core.UWP/CoreUWPContainerSetup.cs +++ b/Wino.Core.UWP/CoreUWPContainerSetup.cs @@ -25,7 +25,6 @@ namespace Wino.Core.UWP services.AddTransient(); services.AddTransient(); services.AddTransient(); - services.AddTransient(); services.AddTransient(); services.AddTransient(); } diff --git a/Wino.Core.UWP/Services/BackgroundSynchronizer.cs b/Wino.Core.UWP/Services/BackgroundSynchronizer.cs deleted file mode 100644 index 64fbb57b..00000000 --- a/Wino.Core.UWP/Services/BackgroundSynchronizer.cs +++ /dev/null @@ -1,144 +0,0 @@ -using System; -using System.Threading.Tasks; -using Serilog; -using Windows.Storage; -using Wino.Core; -using Wino.Core.Domain.Enums; -using Wino.Core.Domain.Exceptions; -using Wino.Core.Domain.Interfaces; -using Wino.Core.Domain.Models.Synchronization; -using Wino.Core.Synchronizers; - -namespace Wino.Services -{ - public interface IBackgroundSynchronizer - { - Task RunBackgroundSynchronizationAsync(BackgroundSynchronizationReason reason); - void CreateLock(); - void ReleaseLock(); - bool IsBackgroundSynchronizationLocked(); - } - - /// - /// Service responsible for handling background synchronization on timer and session connected events. - /// - public class BackgroundSynchronizer : IBackgroundSynchronizer - { - private const string BackgroundSynchronizationLock = nameof(BackgroundSynchronizationLock); - - private readonly IAccountService _accountService; - private readonly IFolderService _folderService; - private readonly IWinoSynchronizerFactory _winoSynchronizerFactory; - - public BackgroundSynchronizer(IAccountService accountService, - IFolderService folderService, - IWinoSynchronizerFactory winoSynchronizerFactory) - { - _accountService = accountService; - _folderService = folderService; - _winoSynchronizerFactory = winoSynchronizerFactory; - } - - public void CreateLock() => ApplicationData.Current.LocalSettings.Values[BackgroundSynchronizationLock] = true; - public void ReleaseLock() => ApplicationData.Current.LocalSettings.Values[BackgroundSynchronizationLock] = false; - - public bool IsBackgroundSynchronizationLocked() - => ApplicationData.Current.LocalSettings.Values.ContainsKey(BackgroundSynchronizationLock) - && ApplicationData.Current.LocalSettings.Values[BackgroundSynchronizationLock] is bool boolValue && boolValue; - - public async Task RunBackgroundSynchronizationAsync(BackgroundSynchronizationReason reason) - { - Log.Information($"{reason} background synchronization is kicked in."); - - // This should never crash. - // We might be in-process or out-of-process. - - //if (IsBackgroundSynchronizationLocked()) - //{ - // Log.Warning("Background synchronization is locked. Hence another background synchronization is canceled."); - // return; - //} - - try - { - CreateLock(); - - var accounts = await _accountService.GetAccountsAsync(); - - foreach (var account in accounts) - { - // We can't sync broken account. - if (account.AttentionReason != AccountAttentionReason.None) - continue; - - // TODO - // We can't synchronize without system folder setup is done. - //var isSystemFolderSetupDone = await _folderService.CheckSystemFolderSetupDoneAsync(account.Id); - - //// No need to throw here. It's a background process. - //if (!isSystemFolderSetupDone) - // continue; - - var synchronizer = _winoSynchronizerFactory.GetAccountSynchronizer(account.Id); - - if (synchronizer.State != AccountSynchronizerState.Idle) - { - Log.Information("Skipping background synchronization for {Name} since current state is {State}", synchronizer.Account.Name, synchronizer.State); - - return; - } - - await HandleSynchronizationAsync(synchronizer, reason); - } - } - catch (Exception ex) - { - Log.Error($"[BackgroundSynchronization] Failed with message {ex.Message}"); - } - finally - { - ReleaseLock(); - } - } - - private async Task HandleSynchronizationAsync(IBaseSynchronizer synchronizer, BackgroundSynchronizationReason reason) - { - if (synchronizer.State != AccountSynchronizerState.Idle) return; - - var account = synchronizer.Account; - - try - { - // SessionConnected will do Full synchronization for logon, Timer task will do Inbox only. - - var syncType = reason == BackgroundSynchronizationReason.SessionConnected ? SynchronizationType.Full : SynchronizationType.Inbox; - - var options = new SynchronizationOptions() - { - AccountId = account.Id, - Type = syncType, - }; - - await synchronizer.SynchronizeAsync(options); - } - catch (AuthenticationAttentionException authenticationAttentionException) - { - Log.Error(authenticationAttentionException, $"[BackgroundSync] Invalid credentials for account {account.Address}"); - - account.AttentionReason = AccountAttentionReason.InvalidCredentials; - await _accountService.UpdateAccountAsync(account); - } - catch (SystemFolderConfigurationMissingException configMissingException) - { - Log.Error(configMissingException, $"[BackgroundSync] Missing system folder configuration for account {account.Address}"); - - account.AttentionReason = AccountAttentionReason.MissingSystemFolderConfiguration; - await _accountService.UpdateAccountAsync(account); - } - catch (Exception ex) - { - Log.Error(ex, "[BackgroundSync] Synchronization failed."); - } - } - } -} diff --git a/Wino.Core.UWP/Services/WinoServerConnectionManager.cs b/Wino.Core.UWP/Services/WinoServerConnectionManager.cs index 717e178a..2518f092 100644 --- a/Wino.Core.UWP/Services/WinoServerConnectionManager.cs +++ b/Wino.Core.UWP/Services/WinoServerConnectionManager.cs @@ -1,18 +1,36 @@ using System; +using System.Text.Json; using System.Threading.Tasks; -using CommunityToolkit.Mvvm.ComponentModel; +using CommunityToolkit.Mvvm.Messaging; using Windows.ApplicationModel; using Windows.ApplicationModel.AppService; using Windows.Foundation.Metadata; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; +using Wino.Messaging; +using Wino.Messaging.Enums; +using Wino.Messaging.Server; namespace Wino.Core.UWP.Services { - public partial class WinoServerConnectionManager : ObservableObject, IWinoServerConnectionManager + public class WinoServerConnectionManager : IWinoServerConnectionManager { + private WinoServerConnectionStatus status; + + public WinoServerConnectionStatus Status + { + get { return status; } + private set + { + status = value; + StatusChanged?.Invoke(this, value); + } + } + private AppServiceConnection _connection; + public event EventHandler StatusChanged; + public AppServiceConnection Connection { get { return _connection; } @@ -40,9 +58,6 @@ namespace Wino.Core.UWP.Services } } - [ObservableProperty] - private WinoServerConnectionStatus _status; - public async Task ConnectAsync() { if (Status == WinoServerConnectionStatus.Connected) return true; @@ -87,12 +102,98 @@ namespace Wino.Core.UWP.Services private void ServerMessageReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { - // TODO: Handle server messsages. + if (args.Request.Message.TryGetValue(MessageConstants.MessageTypeKey, out object messageTypeObject) && messageTypeObject is int messageTypeInt) + { + var messageType = (MessageType)messageTypeInt; + + if (args.Request.Message.TryGetValue(MessageConstants.MessageDataKey, out object messageDataObject) && messageDataObject is string messageJson) + { + switch (messageType) + { + case MessageType.UIMessage: + if (args.Request.Message.TryGetValue(MessageConstants.MessageDataTypeKey, out object dataTypeObject) && dataTypeObject is string dataTypeName) + { + HandleUIMessage(messageJson, dataTypeName); + } + else + throw new ArgumentException("Message data type is missing."); + + break; + case MessageType.ServerAction: + HandleServerAction(messageJson); + break; + default: + break; + } + } + } + } + + private void HandleServerAction(string messageJson) + { + + } + + /// + /// Unpacks IServerMessage objects and delegate it to Messenger for UI to process. + /// + /// Message data in json format. + private void HandleUIMessage(string messageJson, string typeName) + { + switch (typeName) + { + case nameof(MailAddedMessage): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(MailDownloadedMessage): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(MailRemovedMessage): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(MailUpdatedMessage): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(AccountCreatedMessage): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(AccountRemovedMessage): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(AccountUpdatedMessage): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(DraftCreated): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(DraftFailed): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(DraftMapped): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(FolderRenamed): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(FolderSynchronizationEnabled): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + case nameof(MergedInboxRenamed): + WeakReferenceMessenger.Default.Send(JsonSerializer.Deserialize(messageJson)); + break; + default: + throw new Exception("Invalid data type name passed to client."); + } } private void ServerDisconnected(AppServiceConnection sender, AppServiceClosedEventArgs args) { // TODO: Handle server disconnection. } + + public void DisposeConnection() + { + if (Connection == null) return; + } } } diff --git a/Wino.Core.UWP/Wino.Core.UWP.csproj b/Wino.Core.UWP/Wino.Core.UWP.csproj index 42c2fbf3..f90c481e 100644 --- a/Wino.Core.UWP/Wino.Core.UWP.csproj +++ b/Wino.Core.UWP/Wino.Core.UWP.csproj @@ -130,7 +130,6 @@ - @@ -170,6 +169,10 @@ {e6b1632a-8901-41e8-9ddf-6793c7698b0b} Wino.Core + + {0c307d7e-256f-448c-8265-5622a812fbcc} + Wino.Messaging + diff --git a/Wino.Core/Requests/ArchiveRequest.cs b/Wino.Core/Requests/ArchiveRequest.cs index 6a745b84..ba8d4a4c 100644 --- a/Wino.Core/Requests/ArchiveRequest.cs +++ b/Wino.Core/Requests/ArchiveRequest.cs @@ -7,7 +7,7 @@ using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Requests/ChangeFlagRequest.cs b/Wino.Core/Requests/ChangeFlagRequest.cs index 1785111f..c9d6adfa 100644 --- a/Wino.Core/Requests/ChangeFlagRequest.cs +++ b/Wino.Core/Requests/ChangeFlagRequest.cs @@ -7,7 +7,7 @@ using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Requests/CreateDraftRequest.cs b/Wino.Core/Requests/CreateDraftRequest.cs index 9befbbf4..6a61bb3e 100644 --- a/Wino.Core/Requests/CreateDraftRequest.cs +++ b/Wino.Core/Requests/CreateDraftRequest.cs @@ -7,7 +7,7 @@ using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.MailItem; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Requests/DeleteRequest.cs b/Wino.Core/Requests/DeleteRequest.cs index 0eac46f1..06e6ac3a 100644 --- a/Wino.Core/Requests/DeleteRequest.cs +++ b/Wino.Core/Requests/DeleteRequest.cs @@ -7,7 +7,7 @@ using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Requests/EmptyFolderRequest.cs b/Wino.Core/Requests/EmptyFolderRequest.cs index 566cc178..ccb01591 100644 --- a/Wino.Core/Requests/EmptyFolderRequest.cs +++ b/Wino.Core/Requests/EmptyFolderRequest.cs @@ -5,7 +5,7 @@ using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Requests/MarkFolderAsReadRequest.cs b/Wino.Core/Requests/MarkFolderAsReadRequest.cs index 80304e2e..e679990c 100644 --- a/Wino.Core/Requests/MarkFolderAsReadRequest.cs +++ b/Wino.Core/Requests/MarkFolderAsReadRequest.cs @@ -5,7 +5,7 @@ using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Requests/MarkReadRequest.cs b/Wino.Core/Requests/MarkReadRequest.cs index e689c002..fcdb05c6 100644 --- a/Wino.Core/Requests/MarkReadRequest.cs +++ b/Wino.Core/Requests/MarkReadRequest.cs @@ -7,7 +7,7 @@ using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Requests/MoveRequest.cs b/Wino.Core/Requests/MoveRequest.cs index 7df5629e..010f1af2 100644 --- a/Wino.Core/Requests/MoveRequest.cs +++ b/Wino.Core/Requests/MoveRequest.cs @@ -7,7 +7,7 @@ using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Requests/RenameFolderRequest.cs b/Wino.Core/Requests/RenameFolderRequest.cs index f0b1f7b7..e5717d01 100644 --- a/Wino.Core/Requests/RenameFolderRequest.cs +++ b/Wino.Core/Requests/RenameFolderRequest.cs @@ -2,7 +2,7 @@ using Wino.Core.Domain.Entities; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Requests/SendDraftRequest.cs b/Wino.Core/Requests/SendDraftRequest.cs index 2b846731..fe7c9d85 100644 --- a/Wino.Core/Requests/SendDraftRequest.cs +++ b/Wino.Core/Requests/SendDraftRequest.cs @@ -7,7 +7,7 @@ using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.MailItem; using Wino.Core.Domain.Models.Requests; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Requests { diff --git a/Wino.Core/Services/AccountService.cs b/Wino.Core/Services/AccountService.cs index 213760c9..6e80e32f 100644 --- a/Wino.Core/Services/AccountService.cs +++ b/Wino.Core/Services/AccountService.cs @@ -12,7 +12,7 @@ using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Extensions; using Wino.Core.Messages.Accounts; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Services { diff --git a/Wino.Core/Services/FolderService.cs b/Wino.Core/Services/FolderService.cs index efaa1bf1..bfeb882d 100644 --- a/Wino.Core/Services/FolderService.cs +++ b/Wino.Core/Services/FolderService.cs @@ -16,7 +16,7 @@ using Wino.Core.Domain.Models.MailItem; using Wino.Core.Domain.Models.Synchronization; using Wino.Core.Extensions; using Wino.Core.MenuItems; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Services { diff --git a/Wino.Core/Services/MailService.cs b/Wino.Core/Services/MailService.cs index a75cabbf..27821a27 100644 --- a/Wino.Core/Services/MailService.cs +++ b/Wino.Core/Services/MailService.cs @@ -14,7 +14,7 @@ using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Comparers; using Wino.Core.Domain.Models.MailItem; using Wino.Core.Extensions; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Core.Services { diff --git a/Wino.Core/Services/WinoRequestDelegator.cs b/Wino.Core/Services/WinoRequestDelegator.cs index af1bd00e..6077b34f 100644 --- a/Wino.Core/Services/WinoRequestDelegator.cs +++ b/Wino.Core/Services/WinoRequestDelegator.cs @@ -20,6 +20,7 @@ namespace Wino.Core.Services { private readonly IWinoRequestProcessor _winoRequestProcessor; private readonly IWinoSynchronizerFactory _winoSynchronizerFactory; + private readonly IFolderService _folderService; private readonly IDialogService _dialogService; private readonly ILogger _logger = Log.ForContext(); diff --git a/Wino.Core/Wino.Core.csproj b/Wino.Core/Wino.Core.csproj index 5d1a3e25..f6ed7e7d 100644 --- a/Wino.Core/Wino.Core.csproj +++ b/Wino.Core/Wino.Core.csproj @@ -37,6 +37,6 @@ - + diff --git a/Wino.Mail.ViewModels/AccountDetailsPageViewModel.cs b/Wino.Mail.ViewModels/AccountDetailsPageViewModel.cs index 050a2671..3dd7e535 100644 --- a/Wino.Mail.ViewModels/AccountDetailsPageViewModel.cs +++ b/Wino.Mail.ViewModels/AccountDetailsPageViewModel.cs @@ -12,7 +12,7 @@ using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Folders; using Wino.Core.Domain.Models.Navigation; using Wino.Core.Messages.Navigation; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Mail.ViewModels { diff --git a/Wino.Mail.ViewModels/AccountManagementViewModel.cs b/Wino.Mail.ViewModels/AccountManagementViewModel.cs index 97aff0e0..d1982489 100644 --- a/Wino.Mail.ViewModels/AccountManagementViewModel.cs +++ b/Wino.Mail.ViewModels/AccountManagementViewModel.cs @@ -20,7 +20,7 @@ using Wino.Core.Domain.Models.Synchronization; using Wino.Core.Messages.Authorization; using Wino.Core.Messages.Navigation; using Wino.Mail.ViewModels.Data; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Mail.ViewModels { diff --git a/Wino.Mail.ViewModels/AppShellViewModel.cs b/Wino.Mail.ViewModels/AppShellViewModel.cs index 40bf4fe0..ce83b79c 100644 --- a/Wino.Mail.ViewModels/AppShellViewModel.cs +++ b/Wino.Mail.ViewModels/AppShellViewModel.cs @@ -26,7 +26,7 @@ using Wino.Core.Messages.Navigation; using Wino.Core.Messages.Shell; using Wino.Core.Messages.Synchronization; using Wino.Core.Services; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Mail.ViewModels { @@ -83,6 +83,9 @@ namespace Wino.Mail.ViewModels private readonly SemaphoreSlim accountInitFolderUpdateSlim = new SemaphoreSlim(1); + [ObservableProperty] + private string _activeConnectionStatus = WinoServerConnectionStatus.None.ToString(); + public AppShellViewModel(IDialogService dialogService, IWinoNavigationService navigationService, IWinoSynchronizerFactory synchronizerFactory, @@ -104,6 +107,14 @@ namespace Wino.Mail.ViewModels StatePersistenceService = statePersistanceService; ServerConnectionManager = serverConnectionManager; + ServerConnectionManager.StatusChanged += async (sender, status) => + { + await ExecuteUIThread(() => + { + ActiveConnectionStatus = status.ToString(); + }); + }; + PreferencesService = preferencesService; NavigationService = navigationService; diff --git a/Wino.Mail.ViewModels/BaseViewModel.cs b/Wino.Mail.ViewModels/BaseViewModel.cs index 30fcb184..4f60c448 100644 --- a/Wino.Mail.ViewModels/BaseViewModel.cs +++ b/Wino.Mail.ViewModels/BaseViewModel.cs @@ -6,7 +6,7 @@ using Wino.Core.Domain.Entities; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Folders; using Wino.Core.Domain.Models.Navigation; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Mail.ViewModels { @@ -71,9 +71,7 @@ namespace Wino.Mail.ViewModels protected virtual void OnFolderRenamed(IMailItemFolder mailItemFolder) { } protected virtual void OnFolderSynchronizationEnabled(IMailItemFolder mailItemFolder) { } - public void ReportUIChange(TMessage message) where TMessage : class, IServerMessage - => Messenger.Send(message); - + public void ReportUIChange(TMessage message) where TMessage : class, IServerMessage => Messenger.Send(message); void IRecipient.Receive(AccountCreatedMessage message) => OnAccountCreated(message.Account); void IRecipient.Receive(AccountRemovedMessage message) => OnAccountRemoved(message.Account); void IRecipient.Receive(AccountUpdatedMessage message) => OnAccountUpdated(message.Account); diff --git a/Wino.Mail.ViewModels/MailListPageViewModel.cs b/Wino.Mail.ViewModels/MailListPageViewModel.cs index 423bdd76..1fb1fb2f 100644 --- a/Wino.Mail.ViewModels/MailListPageViewModel.cs +++ b/Wino.Mail.ViewModels/MailListPageViewModel.cs @@ -602,6 +602,8 @@ namespace Wino.Mail.ViewModels { base.OnMailAdded(addedMail); + if (addedMail.AssignedAccount == null || addedMail.AssignedFolder == null) return; + try { await listManipulationSemepahore.WaitAsync(); diff --git a/Wino.Mail.ViewModels/MergedAccountDetailsPageViewModel.cs b/Wino.Mail.ViewModels/MergedAccountDetailsPageViewModel.cs index ec8e1f91..596ec907 100644 --- a/Wino.Mail.ViewModels/MergedAccountDetailsPageViewModel.cs +++ b/Wino.Mail.ViewModels/MergedAccountDetailsPageViewModel.cs @@ -10,7 +10,7 @@ using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Navigation; using Wino.Core.Messages.Navigation; using Wino.Mail.ViewModels.Data; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Mail.ViewModels { diff --git a/Wino.Mail.ViewModels/Wino.Mail.ViewModels.csproj b/Wino.Mail.ViewModels/Wino.Mail.ViewModels.csproj index 3bad0c74..14abc662 100644 --- a/Wino.Mail.ViewModels/Wino.Mail.ViewModels.csproj +++ b/Wino.Mail.ViewModels/Wino.Mail.ViewModels.csproj @@ -17,7 +17,7 @@ - + diff --git a/Wino.Mail/Activation/BackgroundActivationHandler.cs b/Wino.Mail/Activation/BackgroundActivationHandler.cs index 62c6c45c..a8735dd7 100644 --- a/Wino.Mail/Activation/BackgroundActivationHandler.cs +++ b/Wino.Mail/Activation/BackgroundActivationHandler.cs @@ -1,18 +1,15 @@ -using System.Diagnostics; -using System.Threading.Tasks; +using System.Threading.Tasks; using Microsoft.Toolkit.Uwp.Notifications; using Serilog; using Windows.ApplicationModel.Activation; using Windows.ApplicationModel.Background; using Windows.UI.Notifications; -using Wino.Core; using Wino.Core.Domain; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.MailItem; using Wino.Core.Domain.Models.Synchronization; using Wino.Core.UWP.Services; -using Wino.Services; namespace Wino.Activation { @@ -21,7 +18,6 @@ namespace Wino.Activation private const string BackgroundExecutionLogTag = "[BackgroundExecution] "; private readonly IWinoRequestDelegator _winoRequestDelegator; - private readonly IBackgroundSynchronizer _backgroundSynchronizer; private readonly INativeAppService _nativeAppService; private readonly IWinoRequestProcessor _winoRequestProcessor; private readonly IWinoSynchronizerFactory _winoSynchronizerFactory; @@ -30,14 +26,12 @@ namespace Wino.Activation BackgroundTaskDeferral _deferral; public BackgroundActivationHandler(IWinoRequestDelegator winoRequestDelegator, - IBackgroundSynchronizer backgroundSynchronizer, INativeAppService nativeAppService, IWinoRequestProcessor winoRequestProcessor, IWinoSynchronizerFactory winoSynchronizerFactory, IMailService mailService) { _winoRequestDelegator = winoRequestDelegator; - _backgroundSynchronizer = backgroundSynchronizer; _nativeAppService = nativeAppService; _winoRequestProcessor = winoRequestProcessor; _winoSynchronizerFactory = winoSynchronizerFactory; @@ -104,18 +98,6 @@ namespace Wino.Activation } } } - else if (taskName == BackgroundTaskService.BackgroundSynchronizationTimerTaskNameEx) - { - var watch = new Stopwatch(); - watch.Start(); - - // Run timer based background synchronization. - - await _backgroundSynchronizer.RunBackgroundSynchronizationAsync(BackgroundSynchronizationReason.Timer); - - watch.Stop(); - Log.Information($"{BackgroundExecutionLogTag}Background synchronization is completed in {watch.Elapsed.TotalSeconds} seconds."); - } instance.Canceled -= OnBackgroundExecutionCanceled; diff --git a/Wino.Mail/App.xaml.cs b/Wino.Mail/App.xaml.cs index 732a7edf..a65e2992 100644 --- a/Wino.Mail/App.xaml.cs +++ b/Wino.Mail/App.xaml.cs @@ -66,6 +66,8 @@ namespace Wino UnhandledException += OnAppUnhandledException; EnteredBackground += OnEnteredBackground; LeavingBackground += OnLeavingBackground; + + Resuming += OnResuming; Suspending += OnSuspending; Services = ConfigureServices(); @@ -87,6 +89,15 @@ namespace Wino Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); } + private async void OnResuming(object sender, object e) + { + // App Service connection was lost on suspension. + // We must restore it. + // Server might be running already, but re-launching it will trigger a new connection attempt. + + await _appServiceConnectionManager.ConnectAsync(); + } + private void OnSuspending(object sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); @@ -328,10 +339,12 @@ namespace Wino yield return Services.GetService(); } - public void OnBackgroundTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) + public async void OnBackgroundTaskCanceled(IBackgroundTaskInstance sender, BackgroundTaskCancellationReason reason) { Log.Information($"Background task {sender.Task.Name} was canceled. Reason: {reason}"); + await _appServiceConnectionManager.DisconnectAsync(); + backgroundTaskDeferral?.Complete(); backgroundTaskDeferral = null; diff --git a/Wino.Mail/AppShell.xaml b/Wino.Mail/AppShell.xaml index 04f6d1ee..031e964c 100644 --- a/Wino.Mail/AppShell.xaml +++ b/Wino.Mail/AppShell.xaml @@ -521,7 +521,7 @@ Padding="14" HorizontalAlignment="Right" VerticalAlignment="Bottom"> - + diff --git a/Wino.Mail/Services/DialogService.cs b/Wino.Mail/Services/DialogService.cs index 3329c5f8..a6e1ce71 100644 --- a/Wino.Mail/Services/DialogService.cs +++ b/Wino.Mail/Services/DialogService.cs @@ -20,7 +20,7 @@ using Wino.Core.Messages.Shell; using Wino.Core.Messages.Synchronization; using Wino.Core.UWP.Extensions; using Wino.Dialogs; -using Wino.Messages.Server; +using Wino.Messaging.Server; namespace Wino.Services { diff --git a/Wino.Mail/Views/NewAccountManagementPage.xaml.cs b/Wino.Mail/Views/NewAccountManagementPage.xaml.cs index 69ee9e7d..d0731946 100644 --- a/Wino.Mail/Views/NewAccountManagementPage.xaml.cs +++ b/Wino.Mail/Views/NewAccountManagementPage.xaml.cs @@ -8,7 +8,7 @@ using Windows.UI.Xaml.Navigation; using Wino.Core.Domain.Enums; using Wino.Core.Messages.Navigation; using Wino.Mail.ViewModels.Data; -using Wino.Messages.Server; +using Wino.Messaging.Server; using Wino.Views.Abstract; using Wino.Views.Account; using Wino.Views.Settings; diff --git a/Wino.Mail/Wino.Mail.csproj b/Wino.Mail/Wino.Mail.csproj index 03453b38..267333b0 100644 --- a/Wino.Mail/Wino.Mail.csproj +++ b/Wino.Mail/Wino.Mail.csproj @@ -801,9 +801,9 @@ {d62f1c03-da57-4709-a640-0283296a8e66} Wino.Mail.ViewModels - + {0c307d7e-256f-448c-8265-5622a812fbcc} - Wino.Messages + Wino.Messaging @@ -811,9 +811,7 @@ Windows Desktop Extensions for the UWP - - - + 14.0 diff --git a/Wino.Messages/Client/Accounts/AccountMenuItemExtended.cs b/Wino.Messages/Client/Accounts/AccountMenuItemExtended.cs index 539209a4..38fa2f6a 100644 --- a/Wino.Messages/Client/Accounts/AccountMenuItemExtended.cs +++ b/Wino.Messages/Client/Accounts/AccountMenuItemExtended.cs @@ -1,7 +1,7 @@ using System; using Wino.Core.Domain.Models.MailItem; -namespace Wino.Messages.Client.Accounts +namespace Wino.Messaging.Client.Accounts { /// /// When menu item for the account is requested to be extended. diff --git a/Wino.Messages/Client/Accounts/AccountMenuItemsReordered.cs b/Wino.Messages/Client/Accounts/AccountMenuItemsReordered.cs index 673107a9..71b53d80 100644 --- a/Wino.Messages/Client/Accounts/AccountMenuItemsReordered.cs +++ b/Wino.Messages/Client/Accounts/AccountMenuItemsReordered.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Wino.Messages.Client.Accounts +namespace Wino.Messaging.Client.Accounts { /// /// Emitted when account menu items are reordered. diff --git a/Wino.Messages/Client/Accounts/AccountsMenuRefreshRequested.cs b/Wino.Messages/Client/Accounts/AccountsMenuRefreshRequested.cs index 2aeb29c9..bd167466 100644 --- a/Wino.Messages/Client/Accounts/AccountsMenuRefreshRequested.cs +++ b/Wino.Messages/Client/Accounts/AccountsMenuRefreshRequested.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Accounts +namespace Wino.Messaging.Client.Accounts { /// /// When a full menu refresh for accounts menu is requested. diff --git a/Wino.Messages/Client/Authorization/ProtocolAuthorizationCallbackReceived.cs b/Wino.Messages/Client/Authorization/ProtocolAuthorizationCallbackReceived.cs index 4dad646d..7be93e4c 100644 --- a/Wino.Messages/Client/Authorization/ProtocolAuthorizationCallbackReceived.cs +++ b/Wino.Messages/Client/Authorization/ProtocolAuthorizationCallbackReceived.cs @@ -1,6 +1,6 @@ using System; -namespace Wino.Messages.Client.Authorization +namespace Wino.Messaging.Client.Authorization { /// /// When Google authentication makes a callback to the app via protocol activation to the app. diff --git a/Wino.Messages/Client/Mails/CancelRenderingContentRequested.cs b/Wino.Messages/Client/Mails/CancelRenderingContentRequested.cs index 8b0e9cdb..c7c83869 100644 --- a/Wino.Messages/Client/Mails/CancelRenderingContentRequested.cs +++ b/Wino.Messages/Client/Mails/CancelRenderingContentRequested.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When rendered html is requested to cancel. diff --git a/Wino.Messages/Client/Mails/ClearMailSelectionsRequested.cs b/Wino.Messages/Client/Mails/ClearMailSelectionsRequested.cs index 90d57e1b..263b03b8 100644 --- a/Wino.Messages/Client/Mails/ClearMailSelectionsRequested.cs +++ b/Wino.Messages/Client/Mails/ClearMailSelectionsRequested.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When reset all mail selections requested. diff --git a/Wino.Messages/Client/Mails/CreateNewComposeMailRequested.cs b/Wino.Messages/Client/Mails/CreateNewComposeMailRequested.cs index a8b37d4a..a582d98c 100644 --- a/Wino.Messages/Client/Mails/CreateNewComposeMailRequested.cs +++ b/Wino.Messages/Client/Mails/CreateNewComposeMailRequested.cs @@ -1,6 +1,6 @@ using Wino.Core.Domain.Models.Reader; -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When a new composing requested. diff --git a/Wino.Messages/Client/Mails/DisposeRenderingFrameRequested.cs b/Wino.Messages/Client/Mails/DisposeRenderingFrameRequested.cs index 45f4581c..85135e85 100644 --- a/Wino.Messages/Client/Mails/DisposeRenderingFrameRequested.cs +++ b/Wino.Messages/Client/Mails/DisposeRenderingFrameRequested.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When rendering frame should be disposed. diff --git a/Wino.Messages/Client/Mails/HtmlRenderingRequested.cs b/Wino.Messages/Client/Mails/HtmlRenderingRequested.cs index 735bac28..dfc114b5 100644 --- a/Wino.Messages/Client/Mails/HtmlRenderingRequested.cs +++ b/Wino.Messages/Client/Mails/HtmlRenderingRequested.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When existing a new html is requested to be rendered due to mail selection or signature. diff --git a/Wino.Messages/Client/Mails/ImapSetupBackNavigationRequested.cs b/Wino.Messages/Client/Mails/ImapSetupBackNavigationRequested.cs index 6cdeab7c..7e232c63 100644 --- a/Wino.Messages/Client/Mails/ImapSetupBackNavigationRequested.cs +++ b/Wino.Messages/Client/Mails/ImapSetupBackNavigationRequested.cs @@ -1,6 +1,6 @@ using System; -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When IMAP setup dialog requestes back breadcrumb navigation. diff --git a/Wino.Messages/Client/Mails/ImapSetupDismissRequested.cs b/Wino.Messages/Client/Mails/ImapSetupDismissRequested.cs index 1b32ca10..20abbc9f 100644 --- a/Wino.Messages/Client/Mails/ImapSetupDismissRequested.cs +++ b/Wino.Messages/Client/Mails/ImapSetupDismissRequested.cs @@ -1,6 +1,6 @@ using Wino.Core.Domain.Entities; -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When user asked to dismiss IMAP setup dialog. diff --git a/Wino.Messages/Client/Mails/ImapSetupNavigationRequested.cs b/Wino.Messages/Client/Mails/ImapSetupNavigationRequested.cs index cfc36207..e70b562f 100644 --- a/Wino.Messages/Client/Mails/ImapSetupNavigationRequested.cs +++ b/Wino.Messages/Client/Mails/ImapSetupNavigationRequested.cs @@ -1,6 +1,6 @@ using System; -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When IMAP setup dialog breadcrumb navigation requested. diff --git a/Wino.Messages/Client/Mails/MailItemNavigationRequested.cs b/Wino.Messages/Client/Mails/MailItemNavigationRequested.cs index 2f0e8af4..b3ea8c2f 100644 --- a/Wino.Messages/Client/Mails/MailItemNavigationRequested.cs +++ b/Wino.Messages/Client/Mails/MailItemNavigationRequested.cs @@ -1,6 +1,6 @@ using System; -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When a IMailItem needs to be navigated (or selected) diff --git a/Wino.Messages/Client/Mails/NavigateMailFolderEvent.cs b/Wino.Messages/Client/Mails/NavigateMailFolderEvent.cs index 0f2a6ecc..896ee3e3 100644 --- a/Wino.Messages/Client/Mails/NavigateMailFolderEvent.cs +++ b/Wino.Messages/Client/Mails/NavigateMailFolderEvent.cs @@ -2,7 +2,7 @@ using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Navigation; -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// Selects the given FolderMenuItem in the shell folders list. diff --git a/Wino.Messages/Client/Mails/RefreshUnreadCountsMessage.cs b/Wino.Messages/Client/Mails/RefreshUnreadCountsMessage.cs index 015b4bd6..280c00f2 100644 --- a/Wino.Messages/Client/Mails/RefreshUnreadCountsMessage.cs +++ b/Wino.Messages/Client/Mails/RefreshUnreadCountsMessage.cs @@ -1,6 +1,6 @@ using System; -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { public record RefreshUnreadCountsMessage(Guid AccountId); } diff --git a/Wino.Messages/Client/Mails/SaveAsPDFRequested.cs b/Wino.Messages/Client/Mails/SaveAsPDFRequested.cs index d59f7a96..ac72ee81 100644 --- a/Wino.Messages/Client/Mails/SaveAsPDFRequested.cs +++ b/Wino.Messages/Client/Mails/SaveAsPDFRequested.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.Text; -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When mail save as PDF requested. diff --git a/Wino.Messages/Client/Mails/SelectedMailItemsChanged.cs b/Wino.Messages/Client/Mails/SelectedMailItemsChanged.cs index 6ee76c96..11ca361f 100644 --- a/Wino.Messages/Client/Mails/SelectedMailItemsChanged.cs +++ b/Wino.Messages/Client/Mails/SelectedMailItemsChanged.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Mails +namespace Wino.Messaging.Client.Mails { /// /// When selected mail count is changed. diff --git a/Wino.Messages/Client/Navigation/BackBreadcrumNavigationRequested.cs b/Wino.Messages/Client/Navigation/BackBreadcrumNavigationRequested.cs index ac843ed2..1459d094 100644 --- a/Wino.Messages/Client/Navigation/BackBreadcrumNavigationRequested.cs +++ b/Wino.Messages/Client/Navigation/BackBreadcrumNavigationRequested.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Navigation +namespace Wino.Messaging.Client.Navigation { /// /// When back navigation is requested for breadcrumb pages. diff --git a/Wino.Messages/Client/Navigation/BreadcrumbNavigationRequested.cs b/Wino.Messages/Client/Navigation/BreadcrumbNavigationRequested.cs index afd3e839..9299660f 100644 --- a/Wino.Messages/Client/Navigation/BreadcrumbNavigationRequested.cs +++ b/Wino.Messages/Client/Navigation/BreadcrumbNavigationRequested.cs @@ -1,6 +1,6 @@ using Wino.Core.Domain.Enums; -namespace Wino.Messages.Client.Navigation +namespace Wino.Messaging.Client.Navigation { /// /// When Breadcrumb control navigation requested. diff --git a/Wino.Messages/Client/Navigation/NavigateSettingsRequested.cs b/Wino.Messages/Client/Navigation/NavigateSettingsRequested.cs index 74b4b969..10aeea06 100644 --- a/Wino.Messages/Client/Navigation/NavigateSettingsRequested.cs +++ b/Wino.Messages/Client/Navigation/NavigateSettingsRequested.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Navigation +namespace Wino.Messaging.Client.Navigation { /// /// Navigates to settings page. diff --git a/Wino.Messages/Client/Shell/ApplicationThemeChanged.cs b/Wino.Messages/Client/Shell/ApplicationThemeChanged.cs index b1033570..49d2e715 100644 --- a/Wino.Messages/Client/Shell/ApplicationThemeChanged.cs +++ b/Wino.Messages/Client/Shell/ApplicationThemeChanged.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Shell +namespace Wino.Messaging.Client.Shell { /// /// When the application theme changed. diff --git a/Wino.Messages/Client/Shell/CreateNewMailWithMultipleAccountsRequested.cs b/Wino.Messages/Client/Shell/CreateNewMailWithMultipleAccountsRequested.cs index 21c7d4fa..b1c5fc70 100644 --- a/Wino.Messages/Client/Shell/CreateNewMailWithMultipleAccountsRequested.cs +++ b/Wino.Messages/Client/Shell/CreateNewMailWithMultipleAccountsRequested.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using Wino.Core.Domain.Entities; -namespace Wino.Messages.Client.Shell +namespace Wino.Messaging.Client.Shell { /// /// When diff --git a/Wino.Messages/Client/Shell/InfoBarMessageRequested.cs b/Wino.Messages/Client/Shell/InfoBarMessageRequested.cs index 8e931519..fa2f6ef2 100644 --- a/Wino.Messages/Client/Shell/InfoBarMessageRequested.cs +++ b/Wino.Messages/Client/Shell/InfoBarMessageRequested.cs @@ -1,7 +1,7 @@ using System; using Wino.Core.Domain.Enums; -namespace Wino.Messages.Client.Shell +namespace Wino.Messaging.Client.Shell { /// /// For displaying right sliding notification message in shell. diff --git a/Wino.Messages/Client/Shell/LanguageChanged.cs b/Wino.Messages/Client/Shell/LanguageChanged.cs index da5537cc..69953cb2 100644 --- a/Wino.Messages/Client/Shell/LanguageChanged.cs +++ b/Wino.Messages/Client/Shell/LanguageChanged.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Shell +namespace Wino.Messaging.Client.Shell { /// /// When application language is updated. diff --git a/Wino.Messages/Client/Shell/MailtoProtocolMessageRequested.cs b/Wino.Messages/Client/Shell/MailtoProtocolMessageRequested.cs index 2b57f8c4..4992b8df 100644 --- a/Wino.Messages/Client/Shell/MailtoProtocolMessageRequested.cs +++ b/Wino.Messages/Client/Shell/MailtoProtocolMessageRequested.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Shell +namespace Wino.Messaging.Client.Shell { public class MailtoProtocolMessageRequested { } } diff --git a/Wino.Messages/Client/Shell/NavigationPaneModeChanged.cs b/Wino.Messages/Client/Shell/NavigationPaneModeChanged.cs index 389e810e..5f20208c 100644 --- a/Wino.Messages/Client/Shell/NavigationPaneModeChanged.cs +++ b/Wino.Messages/Client/Shell/NavigationPaneModeChanged.cs @@ -1,6 +1,6 @@ using Wino.Core.Domain.Enums; -namespace Wino.Messages.Client.Shell +namespace Wino.Messaging.Client.Shell { /// /// When navigation pane mode is changed. diff --git a/Wino.Messages/Client/Shell/ShellStateUpdated.cs b/Wino.Messages/Client/Shell/ShellStateUpdated.cs index fc09519f..3a8cbd6a 100644 --- a/Wino.Messages/Client/Shell/ShellStateUpdated.cs +++ b/Wino.Messages/Client/Shell/ShellStateUpdated.cs @@ -1,4 +1,4 @@ -namespace Wino.Messages.Client.Shell +namespace Wino.Messaging.Client.Shell { /// /// When reading mail state or reader pane narrowed state is changed. diff --git a/Wino.Messages/Client/Synchronization/AccountSynchronizationCompleted.cs b/Wino.Messages/Client/Synchronization/AccountSynchronizationCompleted.cs index b4cb2742..aedc5ea5 100644 --- a/Wino.Messages/Client/Synchronization/AccountSynchronizationCompleted.cs +++ b/Wino.Messages/Client/Synchronization/AccountSynchronizationCompleted.cs @@ -1,7 +1,7 @@ using System; using Wino.Core.Domain.Enums; -namespace Wino.Messages.Client.Synchronization +namespace Wino.Messaging.Client.Synchronization { public record AccountSynchronizationCompleted(Guid AccountId, SynchronizationCompletedState Result, Guid? SynchronizationTrackingId); } diff --git a/Wino.Messages/Client/Synchronization/AccountSynchronizerStateChanged.cs b/Wino.Messages/Client/Synchronization/AccountSynchronizerStateChanged.cs index 90e7566e..e4fa16e3 100644 --- a/Wino.Messages/Client/Synchronization/AccountSynchronizerStateChanged.cs +++ b/Wino.Messages/Client/Synchronization/AccountSynchronizerStateChanged.cs @@ -1,7 +1,7 @@ using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Client.Synchronization +namespace Wino.Messaging.Client.Synchronization { /// /// Emitted when synchronizer state is updated. diff --git a/Wino.Messages/Client/Synchronization/NewSynchronizationRequested.cs b/Wino.Messages/Client/Synchronization/NewSynchronizationRequested.cs index 5a00164c..87c297b1 100644 --- a/Wino.Messages/Client/Synchronization/NewSynchronizationRequested.cs +++ b/Wino.Messages/Client/Synchronization/NewSynchronizationRequested.cs @@ -1,6 +1,6 @@ using Wino.Core.Domain.Models.Synchronization; -namespace Wino.Messages.Client.Synchronization +namespace Wino.Messaging.Client.Synchronization { /// /// Triggers a new synchronization if possible. diff --git a/Wino.Messages/Enums/MessageType.cs b/Wino.Messages/Enums/MessageType.cs new file mode 100644 index 00000000..a1feb2ca --- /dev/null +++ b/Wino.Messages/Enums/MessageType.cs @@ -0,0 +1,8 @@ +namespace Wino.Messaging.Enums +{ + public enum MessageType + { + UIMessage, // For database changes that needs to be reflected in the UI. + ServerAction, // + } +} diff --git a/Wino.Messages/MessageConstants.cs b/Wino.Messages/MessageConstants.cs new file mode 100644 index 00000000..29d75401 --- /dev/null +++ b/Wino.Messages/MessageConstants.cs @@ -0,0 +1,9 @@ +namespace Wino.Messaging +{ + public static class MessageConstants + { + public const string MessageTypeKey = "MessageType"; + public const string MessageDataKey = "MessageData"; + public const string MessageDataTypeKey = "MessageDataType"; + } +} diff --git a/Wino.Messages/Server/AccountCreatedMessage.cs b/Wino.Messages/Server/AccountCreatedMessage.cs index d62015ad..b00a55c5 100644 --- a/Wino.Messages/Server/AccountCreatedMessage.cs +++ b/Wino.Messages/Server/AccountCreatedMessage.cs @@ -1,7 +1,6 @@ using Wino.Core.Domain.Entities; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record AccountCreatedMessage(MailAccount Account) : IServerMessage; + public record AccountCreatedMessage(MailAccount Account) : ServerMessageBase; } diff --git a/Wino.Messages/Server/AccountRemovedMessage.cs b/Wino.Messages/Server/AccountRemovedMessage.cs index 92ee7fe6..1813f89b 100644 --- a/Wino.Messages/Server/AccountRemovedMessage.cs +++ b/Wino.Messages/Server/AccountRemovedMessage.cs @@ -1,7 +1,6 @@ using Wino.Core.Domain.Entities; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record AccountRemovedMessage(MailAccount Account) : IServerMessage; + public record AccountRemovedMessage(MailAccount Account) : ServerMessageBase; } diff --git a/Wino.Messages/Server/AccountUpdatedMessage.cs b/Wino.Messages/Server/AccountUpdatedMessage.cs index ff84aed4..acb1835e 100644 --- a/Wino.Messages/Server/AccountUpdatedMessage.cs +++ b/Wino.Messages/Server/AccountUpdatedMessage.cs @@ -1,7 +1,6 @@ using Wino.Core.Domain.Entities; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record AccountUpdatedMessage(MailAccount Account) : IServerMessage; + public record AccountUpdatedMessage(MailAccount Account) : ServerMessageBase; } diff --git a/Wino.Messages/Server/DraftCreated.cs b/Wino.Messages/Server/DraftCreated.cs index b6418800..7c75b0cb 100644 --- a/Wino.Messages/Server/DraftCreated.cs +++ b/Wino.Messages/Server/DraftCreated.cs @@ -1,7 +1,6 @@ using Wino.Core.Domain.Entities; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record DraftCreated(MailCopy DraftMail, MailAccount Account) : IServerMessage; + public record DraftCreated(MailCopy DraftMail, MailAccount Account) : ServerMessageBase; } diff --git a/Wino.Messages/Server/DraftFailed.cs b/Wino.Messages/Server/DraftFailed.cs index 93d204b8..b77b471b 100644 --- a/Wino.Messages/Server/DraftFailed.cs +++ b/Wino.Messages/Server/DraftFailed.cs @@ -1,7 +1,6 @@ using Wino.Core.Domain.Entities; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record DraftFailed(MailCopy DraftMail, MailAccount Account) : IServerMessage; + public record DraftFailed(MailCopy DraftMail, MailAccount Account) : ServerMessageBase; } diff --git a/Wino.Messages/Server/DraftMapped.cs b/Wino.Messages/Server/DraftMapped.cs index e5bc45c8..d1a09041 100644 --- a/Wino.Messages/Server/DraftMapped.cs +++ b/Wino.Messages/Server/DraftMapped.cs @@ -1,6 +1,4 @@ -using Wino.Core.Domain.Interfaces; - -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record DraftMapped(string LocalDraftCopyId, string RemoteDraftCopyId) : IServerMessage; + public record DraftMapped(string LocalDraftCopyId, string RemoteDraftCopyId) : ServerMessageBase; } diff --git a/Wino.Messages/Server/FolderRenamed.cs b/Wino.Messages/Server/FolderRenamed.cs index e34216c7..6ed7a27c 100644 --- a/Wino.Messages/Server/FolderRenamed.cs +++ b/Wino.Messages/Server/FolderRenamed.cs @@ -1,7 +1,6 @@ -using Wino.Core.Domain.Interfaces; -using Wino.Core.Domain.Models.Folders; +using Wino.Core.Domain.Models.Folders; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record FolderRenamed(IMailItemFolder MailItemFolder) : IServerMessage; + public record FolderRenamed(IMailItemFolder MailItemFolder) : ServerMessageBase; } diff --git a/Wino.Messages/Server/FolderSynchronizationEnabled.cs b/Wino.Messages/Server/FolderSynchronizationEnabled.cs index 027d442e..13327f8d 100644 --- a/Wino.Messages/Server/FolderSynchronizationEnabled.cs +++ b/Wino.Messages/Server/FolderSynchronizationEnabled.cs @@ -1,7 +1,6 @@ -using Wino.Core.Domain.Interfaces; -using Wino.Core.Domain.Models.Folders; +using Wino.Core.Domain.Models.Folders; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record FolderSynchronizationEnabled(IMailItemFolder MailItemFolder) : IServerMessage; + public record FolderSynchronizationEnabled(IMailItemFolder MailItemFolder) : ServerMessageBase; } diff --git a/Wino.Messages/Server/MailAddedMessage.cs b/Wino.Messages/Server/MailAddedMessage.cs index 307eb7ee..6efabb8b 100644 --- a/Wino.Messages/Server/MailAddedMessage.cs +++ b/Wino.Messages/Server/MailAddedMessage.cs @@ -1,7 +1,6 @@ using Wino.Core.Domain.Entities; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record MailAddedMessage(MailCopy AddedMail) : IServerMessage; + public record MailAddedMessage(MailCopy AddedMail) : ServerMessageBase; } diff --git a/Wino.Messages/Server/MailDownloadedMessage.cs b/Wino.Messages/Server/MailDownloadedMessage.cs index a03ee8bd..8902ad7c 100644 --- a/Wino.Messages/Server/MailDownloadedMessage.cs +++ b/Wino.Messages/Server/MailDownloadedMessage.cs @@ -1,7 +1,6 @@ using Wino.Core.Domain.Entities; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record MailDownloadedMessage(MailCopy DownloadedMail) : IServerMessage; + public record MailDownloadedMessage(MailCopy DownloadedMail) : ServerMessageBase; } diff --git a/Wino.Messages/Server/MailRemovedMessage.cs b/Wino.Messages/Server/MailRemovedMessage.cs index 1d3b6a44..8b36c954 100644 --- a/Wino.Messages/Server/MailRemovedMessage.cs +++ b/Wino.Messages/Server/MailRemovedMessage.cs @@ -1,7 +1,6 @@ using Wino.Core.Domain.Entities; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record MailRemovedMessage(MailCopy RemovedMail) : IServerMessage; + public record MailRemovedMessage(MailCopy RemovedMail) : ServerMessageBase; } diff --git a/Wino.Messages/Server/MailUpdatedMessage.cs b/Wino.Messages/Server/MailUpdatedMessage.cs index e9ad9441..8e685efa 100644 --- a/Wino.Messages/Server/MailUpdatedMessage.cs +++ b/Wino.Messages/Server/MailUpdatedMessage.cs @@ -1,7 +1,6 @@ using Wino.Core.Domain.Entities; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record MailUpdatedMessage(MailCopy UpdatedMail) : IServerMessage; + public record MailUpdatedMessage(MailCopy UpdatedMail) : ServerMessageBase; } diff --git a/Wino.Messages/Server/MergedInboxRenamed.cs b/Wino.Messages/Server/MergedInboxRenamed.cs index 937035dc..001b06fe 100644 --- a/Wino.Messages/Server/MergedInboxRenamed.cs +++ b/Wino.Messages/Server/MergedInboxRenamed.cs @@ -1,7 +1,6 @@ using System; -using Wino.Core.Domain.Interfaces; -namespace Wino.Messages.Server +namespace Wino.Messaging.Server { - public record MergedInboxRenamed(Guid MergedInboxId, string NewName) : IServerMessage; + public record MergedInboxRenamed(Guid MergedInboxId, string NewName) : ServerMessageBase; } diff --git a/Wino.Messages/Server/ServerMessageBase.cs b/Wino.Messages/Server/ServerMessageBase.cs new file mode 100644 index 00000000..b9cc0a29 --- /dev/null +++ b/Wino.Messages/Server/ServerMessageBase.cs @@ -0,0 +1,6 @@ +using Wino.Core.Domain.Interfaces; + +namespace Wino.Messaging.Server +{ + public record ServerMessageBase : IServerMessage { } +} diff --git a/Wino.Messages/Wino.Messages.csproj b/Wino.Messages/Wino.Messaging.csproj similarity index 88% rename from Wino.Messages/Wino.Messages.csproj rename to Wino.Messages/Wino.Messaging.csproj index f224dbb2..55e9d658 100644 --- a/Wino.Messages/Wino.Messages.csproj +++ b/Wino.Messages/Wino.Messaging.csproj @@ -14,6 +14,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Wino.Server/App.xaml.cs b/Wino.Server/App.xaml.cs index 6a48a883..b0a9260a 100644 --- a/Wino.Server/App.xaml.cs +++ b/Wino.Server/App.xaml.cs @@ -1,18 +1,70 @@ -using System.Windows; +using System.Threading; +using System.Windows; using H.NotifyIcon; namespace Wino.Server { + /// + /// Single instance Wino Server. + /// Instancing is done using Mutex. + /// App will not start if another instance is already running. + /// App will let running server know that server execution is triggered, which will + /// led server to start new connection to requesting UWP app. + /// public partial class App : Application { + private const string WinoServerAppName = "Wino.Server"; + private const string WinoServerActiatedName = "Wino.Server.Activated"; + private TaskbarIcon? notifyIcon; + private static Mutex _mutex = null; + private EventWaitHandle _eventWaitHandle; protected override void OnStartup(StartupEventArgs e) { - base.OnStartup(e); + bool isCreatedNew; - notifyIcon = (TaskbarIcon)FindResource("NotifyIcon"); - notifyIcon.ForceCreate(enablesEfficiencyMode: true); + _mutex = new Mutex(true, WinoServerAppName, out isCreatedNew); + _eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, WinoServerActiatedName); + + if (isCreatedNew) + { + // Spawn a thread which will be waiting for our event + var thread = new Thread(() => + { + while (_eventWaitHandle.WaitOne()) + { + if (notifyIcon == null) return; + + Current.Dispatcher.BeginInvoke(() => + { + if (notifyIcon.DataContext is TrayIconViewModel trayIconViewModel) + { + trayIconViewModel.Reconnect(); + } + }); + } + }); + + // It is important mark it as background otherwise it will prevent app from exiting. + thread.IsBackground = true; + + thread.Start(); + + base.OnStartup(e); + + // Create taskbar icon for the new server. + notifyIcon = (TaskbarIcon)FindResource("NotifyIcon"); + notifyIcon.ForceCreate(enablesEfficiencyMode: true); + } + else + { + // Notify other instance so it could bring itself to foreground. + _eventWaitHandle.Set(); + + // Terminate this instance. + Shutdown(); + } } protected override void OnExit(ExitEventArgs e) diff --git a/Wino.Server/ServerContext.cs b/Wino.Server/ServerContext.cs index c1a40b23..305df65c 100644 --- a/Wino.Server/ServerContext.cs +++ b/Wino.Server/ServerContext.cs @@ -1,12 +1,21 @@ using System; +using System.Text.Json; +using System.Threading.Tasks; using Windows.ApplicationModel; using Windows.ApplicationModel.AppService; using Windows.Foundation.Collections; +using Wino.Core.Domain.Entities; +using Wino.Core.Domain.Interfaces; +using Wino.Messaging; +using Wino.Messaging.Enums; +using Wino.Messaging.Server; namespace Wino.Server { public class ServerContext { + private static object connectionLock = new object(); + private AppServiceConnection connection = null; public ServerContext() @@ -14,15 +23,33 @@ namespace Wino.Server InitializeAppServiceConnection(); } + private string GetAppPackagFamilyName() + { + // If running as a standalone app, Package will throw exception. + // Return hardcoded value for debugging purposes. + // Connection will not be available in this case. + + try + { + return Package.Current.Id.FamilyName; + } + catch (Exception) + { + return "Debug.Wino.Server.FamilyName"; + } + } + /// /// Open connection to UWP app service /// public async void InitializeAppServiceConnection() { + if (connection != null) DisposeConnection(); + connection = new AppServiceConnection { AppServiceName = "WinoInteropService", - PackageFamilyName = Package.Current.Id.FamilyName + PackageFamilyName = GetAppPackagFamilyName() }; connection.RequestReceived += OnWinRTMessageReceived; @@ -33,13 +60,33 @@ namespace Wino.Server if (status != AppServiceConnectionStatus.Success) { // TODO: Handle connection error + + DisposeConnection(); } } - public async void SendMessage() + public Task SendTestMessageAsync() { - var set = new ValueSet(); - set.Add("Hello", "World"); + var message = new MailAddedMessage(new MailCopy()); + return SendMessageAsync(MessageType.UIMessage, message); + } + + private async Task SendMessageAsync(MessageType messageType, object message) + { + if (connection == null) return; + + if (message is not IServerMessage serverMessage) + throw new ArgumentException("Server message must be a type of IServerMessage"); + + string json = JsonSerializer.Serialize(message); + + var set = new ValueSet + { + { MessageConstants.MessageTypeKey, (int)messageType }, + { MessageConstants.MessageDataKey, json }, + { MessageConstants.MessageDataTypeKey, message.GetType().Name } + }; + await connection.SendMessageAsync(set); } @@ -47,12 +94,30 @@ namespace Wino.Server { // TODO: Handle connection closed. - // UWP app might've been terminated. + // UWP app might've been terminated or suspended. + // At this point, we must keep active synchronizations going, but connection is lost. + // As long as this process is alive, database will be kept updated, but no messages will be sent. + + DisposeConnection(); } private void OnWinRTMessageReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { // TODO: Handle incoming messages from UWP/WINUI Application. } + + private void DisposeConnection() + { + lock (connectionLock) + { + if (connection == null) return; + + connection.RequestReceived -= OnWinRTMessageReceived; + connection.ServiceClosed -= OnConnectionClosed; + + connection.Dispose(); + connection = null; + } + } } } diff --git a/Wino.Server/TrayIconViewModel.cs b/Wino.Server/TrayIconViewModel.cs index 145f1cd9..2c89ea39 100644 --- a/Wino.Server/TrayIconViewModel.cs +++ b/Wino.Server/TrayIconViewModel.cs @@ -11,7 +11,7 @@ namespace Wino.Server [RelayCommand] public void LaunchWino() { - _context.SendMessage(); + _context.SendTestMessageAsync(); } /// @@ -24,5 +24,7 @@ namespace Wino.Server Application.Current.Shutdown(); } + + public void Reconnect() => _context.InitializeAppServiceConnection(); } } diff --git a/Wino.Server/Wino.Server.csproj b/Wino.Server/Wino.Server.csproj index 1ae8d7d5..ee95a4bc 100644 --- a/Wino.Server/Wino.Server.csproj +++ b/Wino.Server/Wino.Server.csproj @@ -25,6 +25,6 @@ - + \ No newline at end of file diff --git a/Wino.sln b/Wino.sln index 8123069b..41817d8f 100644 --- a/Wino.sln +++ b/Wino.sln @@ -15,11 +15,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wino.BackgroundTasks", "Win EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Mail.ViewModels", "Wino.Mail.ViewModels\Wino.Mail.ViewModels.csproj", "{D62F1C03-DA57-4709-A640-0283296A8E66}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Messages", "Wino.Messages\Wino.Messages.csproj", "{0C307D7E-256F-448C-8265-5622A812FBCC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Messaging", "Wino.Messages\Wino.Messaging.csproj", "{0C307D7E-256F-448C-8265-5622A812FBCC}" EndProject Project("{C7167F0D-BC9F-4E6E-AFE1-012C56B48DB5}") = "Wino.Packaging", "Wino.Packaging\Wino.Packaging.wapproj", "{760F5F31-8EE3-4B83-80F3-0E4FFBCC737C}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wino.Server", "Wino.Server\Wino.Server.csproj", "{3D1942E5-1A3B-4062-B4BB-156A40DA47FE}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Wino.Server", "Wino.Server\Wino.Server.csproj", "{3D1942E5-1A3B-4062-B4BB-156A40DA47FE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution