using System; using System.Collections.Generic; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Mvvm.Messaging; using Wino.Core.Domain.Entities.Shared; using Wino.Core.Domain.Enums; using Wino.Core.Domain.Interfaces; using Wino.Core.Domain.Models.Accounts; using Wino.Core.Requests.Bundles; using Wino.Messaging.UI; namespace Wino.Core.Synchronizers { public abstract class BaseSynchronizer { protected SemaphoreSlim synchronizationSemaphore = new(1); protected CancellationToken activeSynchronizationCancellationToken; protected List changeRequestQueue = []; public MailAccount Account { get; } private AccountSynchronizerState state; public AccountSynchronizerState State { get { return state; } set { state = value; WeakReferenceMessenger.Default.Send(new AccountSynchronizerStateChanged(Account.Id, value)); } } protected BaseSynchronizer(MailAccount account) { Account = account; } /// /// Queues a single request to be executed in the next synchronization. /// /// Request to execute. public void QueueRequest(IRequestBase request) => changeRequestQueue.Add(request); /// /// Runs existing queued requests in the queue. /// /// Batched requests to execute. Integrator methods will only receive batched requests. /// Cancellation token public abstract Task ExecuteNativeRequestsAsync(List> batchedRequests, CancellationToken cancellationToken = default); // TODO: What if account is deleted during synchronization? public bool CancelActiveSynchronization() => true; /// /// Refreshes remote mail account profile if possible. /// Profile picture, sender name and mailbox settings (todo) will be handled in this step. /// public virtual Task GetProfileInformationAsync() => default; /// /// Safely updates account's profile information. /// Database changes are reflected after this call. /// protected async Task SynchronizeProfileInformationInternalAsync() { var profileInformation = await GetProfileInformationAsync(); if (profileInformation != null) { Account.SenderName = profileInformation.SenderName; Account.Base64ProfilePictureData = profileInformation.Base64ProfilePictureData; if (!string.IsNullOrEmpty(profileInformation.AccountAddress)) { Account.Address = profileInformation.AccountAddress; } } return profileInformation; } /// /// Returns the base64 encoded profile picture of the account from the given URL. /// /// URL to retrieve picture from. /// base64 encoded profile picture protected async Task GetProfilePictureBase64EncodedAsync(string url) { using var client = new HttpClient(); var response = await client.GetAsync(url).ConfigureAwait(false); var byteContent = await response.Content.ReadAsByteArrayAsync().ConfigureAwait(false); return Convert.ToBase64String(byteContent); } public List> ForEachRequest(IEnumerable requests, Func action) where TWinoRequestType : IRequestBase { List> ret = []; foreach (var request in requests) ret.Add(new HttpRequestBundle(action(request), request)); return ret; } } }