343 lines
16 KiB
C#
343 lines
16 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
using System.Threading.Tasks;
|
|
using gehGassi.Dto;
|
|
using gehGassi.Dto.DogWalkers;
|
|
using gehGassiApp.Core.Data;
|
|
using gehGassiApp.Core.Interfaces;
|
|
using gehGassiApp.Core.Interfaces.Synchronization;
|
|
using gehGassiApp.Core.Mapper;
|
|
using gehGassiApp.Domain.Common;
|
|
using gehGassiApp.Domain.Users;
|
|
|
|
namespace gehGassiApp.Core.Services
|
|
{
|
|
/// <summary>
|
|
/// Service der die Verwaltung von Walker-Profilen ermöglicht
|
|
/// </summary>
|
|
public class WalkerProfileService : ServiceBase<DogWalkerProfile>, IWalkerProfileService
|
|
{
|
|
private readonly ICommunicationService _communicationService;
|
|
private readonly ISyncInfoPushService _pushService;
|
|
private readonly ISyncInfoPullService _pullService;
|
|
|
|
/// <summary>
|
|
/// Erstellt eine Instanz
|
|
/// </summary>
|
|
/// <param name="unitOfWork">Instanz eines IUnitOfWork</param>
|
|
/// <param name="communicationService">Instanz eines ICommunicationService</param>
|
|
/// <param name="pushService">Instanz eines ISyncInfoPushService</param>
|
|
/// <param name="pullService">Instanz eines ISyncInfoPullService</param>
|
|
public WalkerProfileService(IUnitOfWork unitOfWork, ICommunicationService communicationService, ISyncInfoPushService pushService, ISyncInfoPullService pullService) : base(unitOfWork)
|
|
{
|
|
_communicationService = communicationService;
|
|
_pushService = pushService;
|
|
_pullService = pullService;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Entität anhand der eindeutigen Id zurück
|
|
/// </summary>
|
|
/// <param name="id">Id der Entität</param>
|
|
/// <param name="noTracking">Gibt an ob NoTRacking verwendet werden soll. Es werden keine Entitäten im EF-Speicher gehalten</param>
|
|
/// <returns>Entität oder null, wenn nicht gefunden</returns>
|
|
public override DogWalkerProfile Get(object id, bool noTracking = true)
|
|
{
|
|
//Bewusst nicht implementiert
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt eine Entität anhand der eindeutigen Id zurück
|
|
/// </summary>
|
|
/// <param name="id">Id der Entität</param>
|
|
/// <param name="noTracking">Gibt an ob NoTRacking verwendet werden soll. Es werden keine Entitäten im EF-Speicher gehalten</param>
|
|
/// <returns>Entität oder null, wenn nicht gefunden</returns>
|
|
public override async Task<DogWalkerProfile> GetAsync(object id, bool noTracking = true)
|
|
{
|
|
//Bewusst nicht implementiert
|
|
await Task.Delay(1);
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt das aktuelle Walkerprofil zurück.
|
|
/// </summary>
|
|
/// <returns>DogWalkerProfile oder null wenn nicht gefunden</returns>
|
|
public async Task<DogWalkerProfile> GetAsync()
|
|
{
|
|
var profile = await Repository.FirstOrDefaultAsync(c => c.Id != "", false).ConfigureAwait(false);
|
|
return profile;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gibt das aktuelle Walkerprofil zurück.
|
|
/// Versucht auch online - wenn lokal nicht vorhanden
|
|
/// </summary>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <param name="forceOnline">Wenn true, wird in jedem Fall die Online-Abfrage verwendet</param>
|
|
/// <returns>DogWalkerProfile oder null wenn nicht gefunden</returns>
|
|
public async Task<DogWalkerProfile> GetAsync(string accessToken, CancellationToken token, bool forceOnline)
|
|
{
|
|
//Zuerst Online wenn gewünscht
|
|
if (forceOnline)
|
|
{
|
|
var isConnected = await _communicationService.IsConnected();
|
|
if (isConnected)
|
|
{
|
|
var profileResult = await _communicationService.GetWalkerProfileAsync(accessToken, token);
|
|
if (profileResult.Success)
|
|
{
|
|
var profileUpdated = await CreateOrUpdateAsync(profileResult.Value);
|
|
await _pullService.AddOrUpddateAsync(nameof(DogWalkerProfile), DateTimeOffset.UtcNow);
|
|
return profileUpdated;
|
|
}
|
|
}
|
|
}
|
|
|
|
var profile = await Repository.FirstOrDefaultAsync(c => c.Id != "").ConfigureAwait(false);
|
|
if (profile != null)
|
|
return profile;
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Hinzufügen oder aktualisieren eines Walkerprofils
|
|
/// </summary>
|
|
/// <param name="walkerProfile">Walker-Profil</param>
|
|
/// <returns>AppUser</returns>
|
|
public async Task<DogWalkerProfile> CreateOrUpdateAsync(DogWalkerProfile walkerProfile)
|
|
{
|
|
var foundProfile = await Repository.FirstOrDefaultAsync(c => c.Id != "", true).ConfigureAwait(false);
|
|
if (foundProfile == null)
|
|
{
|
|
Repository.Add(walkerProfile);
|
|
await CommitAsync();
|
|
return walkerProfile;
|
|
}
|
|
|
|
if (walkerProfile.UpdatedAt > foundProfile.UpdatedAt)
|
|
{
|
|
foundProfile.Radius = walkerProfile.Radius;
|
|
foundProfile.About = walkerProfile.About;
|
|
foundProfile.AllowedRequests = walkerProfile.AllowedRequests;
|
|
foundProfile.PuppyAllowed = walkerProfile.PuppyAllowed;
|
|
foundProfile.DifficultAllowed = walkerProfile.DifficultAllowed;
|
|
foundProfile.AggressionLevel = walkerProfile.AggressionLevel;
|
|
foundProfile.AcceptedSize = walkerProfile.AcceptedSize;
|
|
foundProfile.PriceWalk = walkerProfile.PriceWalk;
|
|
foundProfile.PriceDay = walkerProfile.PriceDay;
|
|
foundProfile.PriceSitting = walkerProfile.PriceSitting;
|
|
foundProfile.NotAvailable = walkerProfile.NotAvailable;
|
|
foundProfile.NotAvailableInfo = walkerProfile.NotAvailableInfo;
|
|
foundProfile.UpdatedAt = walkerProfile.UpdatedAt;
|
|
foundProfile.Deleted = walkerProfile.Deleted;
|
|
|
|
Repository.Update(foundProfile);
|
|
var changes = await CommitAsync().ConfigureAwait(false);
|
|
}
|
|
|
|
return await GetAsync();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Aktualisieren eines Walker-Profils.
|
|
/// Online wird versucht. Wenn nicht möglich wird ein Delta erstellt.
|
|
/// </summary>
|
|
/// <param name="walkerProfile">Walker-Profil</param>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>DogWalkerProfile</returns>
|
|
public async Task<DogWalkerProfile> UpdateAsync(DogWalkerProfile walkerProfile, string accessToken, CancellationToken token)
|
|
{
|
|
//Zuerst in der DB aktualisieren
|
|
|
|
var foundProfile = await Repository.FirstOrDefaultAsync(c => c.Id == walkerProfile.Id, false);
|
|
foundProfile.Radius = walkerProfile.Radius;
|
|
foundProfile.About = walkerProfile.About;
|
|
foundProfile.AllowedRequests = walkerProfile.AllowedRequests;
|
|
foundProfile.PuppyAllowed = walkerProfile.PuppyAllowed;
|
|
foundProfile.DifficultAllowed = walkerProfile.DifficultAllowed;
|
|
foundProfile.AggressionLevel = walkerProfile.AggressionLevel;
|
|
foundProfile.AcceptedSize = walkerProfile.AcceptedSize;
|
|
foundProfile.PriceWalk = walkerProfile.PriceWalk;
|
|
foundProfile.PriceDay = walkerProfile.PriceDay;
|
|
foundProfile.PriceSitting = walkerProfile.PriceSitting;
|
|
foundProfile.NotAvailable = walkerProfile.NotAvailable;
|
|
foundProfile.NotAvailableInfo = walkerProfile.NotAvailableInfo;
|
|
foundProfile.UpdatedAt = DateTimeOffset.UtcNow;
|
|
|
|
Repository.Update(foundProfile);
|
|
|
|
await CommitAsync().ConfigureAwait(false);
|
|
|
|
var profileDto = foundProfile.ToDto();
|
|
|
|
var isConnected = await _communicationService.IsConnected();
|
|
if (isConnected)
|
|
{
|
|
var updateResult = await _communicationService.UpdateWalkerProfileAsync(profileDto, accessToken, token);
|
|
if (updateResult.Success)
|
|
{
|
|
//Alles gut nichts weglegen
|
|
//Für den Pull-Service das Update-Datum setzen
|
|
await _pullService.AddOrUpddateAsync(nameof(DogWalkerProfile), foundProfile.UpdatedAt).ConfigureAwait(false);
|
|
}
|
|
else
|
|
{
|
|
//Weglegen und später versuchen
|
|
await _pushService.AddAsync(nameof(DogWalkerProfile), foundProfile.Id, SyncOperation.Edit, foundProfile).ConfigureAwait(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Weglegen und später versuchen
|
|
await _pushService.AddAsync(nameof(DogWalkerProfile), foundProfile.Id, SyncOperation.Edit, foundProfile).ConfigureAwait(false);
|
|
}
|
|
|
|
return foundProfile;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Holen der Daten vom lokalen Speicher die noch nicht synchronisiert wurden und senden an den Server
|
|
/// </summary>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>Task</returns>
|
|
public async Task<SyncResult<DogWalkerProfile>> PushAsync(string accessToken, CancellationToken token)
|
|
{
|
|
var result = new SyncResult<DogWalkerProfile>();
|
|
|
|
if (await _pushService.HasOpenAsync(nameof(DogWalkerProfile)) > 0)
|
|
{
|
|
var deltas = await _pushService.GetAllAsync(nameof(DogWalkerProfile)).ConfigureAwait(false);
|
|
if (deltas.Any())
|
|
{
|
|
var isConnected = await _communicationService.IsConnected();
|
|
|
|
if (!isConnected) return result;
|
|
|
|
deltas = deltas.OrderBy(c => c.DateTime).ToList();
|
|
foreach (var syncInfoPush in deltas)
|
|
{
|
|
//Es gibt hier ur Update... daher alles andere ignorieren
|
|
if (syncInfoPush.Operation != SyncOperation.Edit)
|
|
{
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
if (!string.IsNullOrWhiteSpace(syncInfoPush.Value))
|
|
{
|
|
var profile = JsonSerializer.Deserialize<DogWalkerProfile>(syncInfoPush.Value, new JsonSerializerOptions(JsonSerializerDefaults.Web));
|
|
|
|
//Jetzt Update senden...
|
|
var profileDto = profile.ToDto();
|
|
|
|
var updateResult = await _communicationService.UpdateWalkerProfileAsync(profileDto, accessToken, token);
|
|
if (updateResult.Success)
|
|
{
|
|
//Aktualisierung durchgeführt.
|
|
await _pullService.AddOrUpddateAsync(nameof(DogWalkerProfile), profile.UpdatedAt).ConfigureAwait(false);
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
}
|
|
else
|
|
{
|
|
//TODO: Prüfen!!!!
|
|
//Derzeiut egal welcher Fehler vorliegt, weg damit
|
|
//Aktualisierung durchgeführt.
|
|
await _pullService.AddOrUpddateAsync(nameof(DogWalkerProfile), profile.UpdatedAt).ConfigureAwait(false);
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
}
|
|
//Else ist nichts tun, konnte nicht übertragen werden.
|
|
}
|
|
else
|
|
{
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
System.Diagnostics.Debug.WriteLine(ex.Message);
|
|
await _pushService.RemoveAsync(syncInfoPush.Id).ConfigureAwait(false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Es gibt hier kein Push!
|
|
await Task.Delay(1);
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Holen der letzten Daten vom Server und Synchronisieren mit den lokalen Daten
|
|
/// </summary>
|
|
/// <param name="language">Sprache</param>
|
|
/// <param name="accessToken">Aktuelles Accesstoken</param>
|
|
/// <param name="token">CancellationToken</param>
|
|
/// <returns>Task</returns>
|
|
public async Task<SyncResult<DogWalkerProfile>> PullAsync(string language, string accessToken, CancellationToken token)
|
|
{
|
|
var result = new SyncResult<DogWalkerProfile>();
|
|
|
|
//Zuerst immer online...
|
|
var isConnected = await _communicationService.IsConnected();
|
|
|
|
if (isConnected)
|
|
{
|
|
//Zuerst lezte Aktivität holen...
|
|
DateTimeOffset? lastUpdate = null;
|
|
var lastSyncInfo = await _pullService.GetAsync(nameof(DogWalkerProfile)).ConfigureAwait(false);
|
|
if (lastSyncInfo != null)
|
|
lastUpdate = lastSyncInfo.LastUpdate;
|
|
|
|
var ctsQuery = new CancellationTokenSource(Common.Constants.PushPullTimeout);
|
|
var profileResult = await _communicationService.GetWalkerProfileSyncAsync(lastUpdate, accessToken, token);
|
|
if (profileResult.Success)
|
|
{
|
|
if (profileResult.Value != null)
|
|
{
|
|
var profile = await Repository.GetAsync(profileResult.Value.Id).ConfigureAwait(false);
|
|
if (profile != null)
|
|
{
|
|
profile.Radius = profileResult.Value.Radius;
|
|
profile.About = profileResult.Value.About;
|
|
profile.AllowedRequests = profileResult.Value.AllowedRequests;
|
|
profile.PuppyAllowed = profileResult.Value.PuppyAllowed;
|
|
profile.DifficultAllowed = profileResult.Value.DifficultAllowed;
|
|
profile.AggressionLevel = profileResult.Value.AggressionLevel;
|
|
profile.AcceptedSize = profileResult.Value.AcceptedSize;
|
|
profile.PriceWalk = profileResult.Value.PriceWalk;
|
|
profile.PriceDay = profileResult.Value.PriceDay;
|
|
profile.PriceSitting = profileResult.Value.PriceSitting;
|
|
profile.NotAvailable = profileResult.Value.NotAvailable;
|
|
profile.NotAvailableInfo = profileResult.Value.NotAvailableInfo;
|
|
profile.UpdatedAt = DateTimeOffset.UtcNow;
|
|
|
|
Repository.Update(profile);
|
|
await CommitAsync().ConfigureAwait(false);
|
|
|
|
result.Updated.Add(profile);
|
|
result.LastUpdate = profileResult.Value.UpdatedAt;
|
|
await _pullService.AddOrUpddateAsync(nameof(DogWalkerProfile), profileResult.Value.UpdatedAt).ConfigureAwait(false);
|
|
}
|
|
}
|
|
}
|
|
|
|
result.LastUpdate ??= lastUpdate;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|