280 lines
9.7 KiB
C#
280 lines
9.7 KiB
C#
using FrontOffice.BFF.Configuration.Protobuf.Protos.AppVersion;
|
|
using Blazored.LocalStorage;
|
|
using Microsoft.JSInterop;
|
|
|
|
namespace FrontOffice.Main.Utilities;
|
|
|
|
/// <summary>
|
|
/// نتیجه بررسی نسخه اپلیکیشن
|
|
/// </summary>
|
|
public class VersionCheckResult
|
|
{
|
|
/// <summary>
|
|
/// آیا نسخه جدیدی وجود دارد
|
|
/// </summary>
|
|
public bool HasNewVersion { get; set; }
|
|
|
|
/// <summary>
|
|
/// آیا آپدیت اجباری است (force update)
|
|
/// </summary>
|
|
public bool IsForceUpdate { get; set; }
|
|
|
|
/// <summary>
|
|
/// نسخه فعلی (local)
|
|
/// </summary>
|
|
public string? OldVersion { get; set; }
|
|
|
|
/// <summary>
|
|
/// نسخه جدید (server)
|
|
/// </summary>
|
|
public string? NewVersion { get; set; }
|
|
|
|
/// <summary>
|
|
/// یادداشتهای انتشار
|
|
/// </summary>
|
|
public string? ReleaseNotes { get; set; }
|
|
|
|
/// <summary>
|
|
/// پیام آپدیت
|
|
/// </summary>
|
|
public string? UpdateMessage { get; set; }
|
|
|
|
/// <summary>
|
|
/// آیا کش باید پاک شود
|
|
/// </summary>
|
|
public bool RequiresCacheClear { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// سرویس مدیریت نسخه اپلیکیشن و کش
|
|
/// وقتی نسخه جدید منتشر بشه، این سرویس متوجه میشه و کش رو پاک میکنه
|
|
/// </summary>
|
|
public class AppVersionService
|
|
{
|
|
private readonly AppVersionContract.AppVersionContractClient _client;
|
|
private readonly ILocalStorageService _localStorage;
|
|
private readonly IJSRuntime _jsRuntime;
|
|
private readonly ILogger<AppVersionService> _logger;
|
|
|
|
private const string APP_NAME = "KaraBazarApp";
|
|
private const string LOCAL_VERSION_KEY = "app_version";
|
|
private const string LAST_CHECK_KEY = "app_version_last_check";
|
|
private const string SKIPPED_VERSION_KEY = "app_version_skipped";
|
|
private const string LAST_DIALOG_SHOWN_KEY = "app_version_last_dialog_shown";
|
|
|
|
public AppVersionService(
|
|
AppVersionContract.AppVersionContractClient client,
|
|
ILocalStorageService localStorage,
|
|
IJSRuntime jsRuntime,
|
|
ILogger<AppVersionService> logger)
|
|
{
|
|
_client = client;
|
|
_localStorage = localStorage;
|
|
_jsRuntime = jsRuntime;
|
|
_logger = logger;
|
|
}
|
|
|
|
/// <summary>
|
|
/// بررسی نسخه اپلیکیشن و برگرداندن نتیجه
|
|
/// </summary>
|
|
/// <param name="ignoreSkipped">اگر true باشه، نسخههای skip شده هم نشون داده میشن (برای آیکون منو)</param>
|
|
/// <param name="forDialog">اگر true باشه، چک میکنه که یک روز از آخرین نمایش گذشته (برای popup)</param>
|
|
public async Task<VersionCheckResult> CheckVersionAsync(bool ignoreSkipped = false, bool forDialog = false)
|
|
{
|
|
var result = new VersionCheckResult();
|
|
|
|
try
|
|
{
|
|
// دریافت نسخه فعلی از localStorage
|
|
var localVersion = await _localStorage.GetItemAsStringAsync(LOCAL_VERSION_KEY);
|
|
var skippedVersion = await _localStorage.GetItemAsStringAsync(SKIPPED_VERSION_KEY);
|
|
var lastDialogShown = await _localStorage.GetItemAsStringAsync(LAST_DIALOG_SHOWN_KEY);
|
|
|
|
result.OldVersion = localVersion;
|
|
|
|
// بررسی نسخه از سرور
|
|
var response = await _client.GetAppVersionAsync(new GetAppVersionRequest
|
|
{
|
|
AppName = APP_NAME,
|
|
CurrentClientVersion = localVersion
|
|
});
|
|
|
|
if (!response.Found)
|
|
{
|
|
_logger.LogWarning("App version not found on server for {AppName}", APP_NAME);
|
|
return result;
|
|
}
|
|
|
|
var serverVersion = response.CurrentVersion;
|
|
result.NewVersion = serverVersion;
|
|
result.ReleaseNotes = response.ReleaseNotes;
|
|
result.UpdateMessage = response.UpdateMessage;
|
|
result.RequiresCacheClear = response.RequiresFullCacheClear;
|
|
result.IsForceUpdate = response.RequiresUpdate; // اگر نسخه کمتر از حداقل باشه
|
|
|
|
// آیا نسخه جدید داریم؟
|
|
if (localVersion != serverVersion)
|
|
{
|
|
result.HasNewVersion = true;
|
|
|
|
// اگر این نسخه رو قبلاً skip کرده و force نیست
|
|
if (!result.IsForceUpdate && skippedVersion == serverVersion && !ignoreSkipped)
|
|
{
|
|
// برای popup: چک کن یک روز گذشته یا نه
|
|
if (forDialog)
|
|
{
|
|
var oneDayPassed = await HasOneDayPassedSinceLastDialogAsync(lastDialogShown);
|
|
if (!oneDayPassed)
|
|
{
|
|
result.HasNewVersion = false;
|
|
}
|
|
// اگه یک روز گذشته، HasNewVersion = true میمونه
|
|
}
|
|
else
|
|
{
|
|
result.HasNewVersion = false;
|
|
}
|
|
}
|
|
|
|
_logger.LogInformation(
|
|
"Version check: {OldVersion} -> {NewVersion}, Force: {Force}, Skipped: {Skipped}",
|
|
localVersion ?? "null", serverVersion, result.IsForceUpdate, skippedVersion);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error checking app version");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// چک کردن اینکه یک روز از آخرین نمایش دیالوگ گذشته یا نه
|
|
/// </summary>
|
|
private async Task<bool> HasOneDayPassedSinceLastDialogAsync(string? lastDialogShown)
|
|
{
|
|
if (string.IsNullOrEmpty(lastDialogShown))
|
|
return true; // اگه هیچوقت نشون نداده، نشون بده
|
|
|
|
if (DateTime.TryParse(lastDialogShown, out var lastShown))
|
|
{
|
|
return DateTime.UtcNow.Subtract(lastShown).TotalDays >= 1;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ثبت زمان نمایش دیالوگ
|
|
/// </summary>
|
|
public async Task RecordDialogShownAsync()
|
|
{
|
|
await _localStorage.SetItemAsStringAsync(LAST_DIALOG_SHOWN_KEY, DateTime.UtcNow.ToString("O"));
|
|
}
|
|
|
|
/// <summary>
|
|
/// اعمال آپدیت - پاک کردن کش و ذخیره نسخه جدید
|
|
/// </summary>
|
|
public async Task ApplyUpdateAsync(string newVersion)
|
|
{
|
|
try
|
|
{
|
|
_logger.LogInformation("Applying update to version {Version}", newVersion);
|
|
|
|
// پاک کردن کش
|
|
await ClearAllCacheAsync();
|
|
|
|
// ذخیره نسخه جدید
|
|
await _localStorage.SetItemAsStringAsync(LOCAL_VERSION_KEY, newVersion);
|
|
await _localStorage.SetItemAsStringAsync(LAST_CHECK_KEY, DateTime.UtcNow.ToString("O"));
|
|
|
|
// پاک کردن نسخه skip شده
|
|
await _localStorage.RemoveItemAsync(SKIPPED_VERSION_KEY);
|
|
|
|
_logger.LogInformation("Update applied successfully to {Version}", newVersion);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error applying update");
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Skip کردن این نسخه (بعداً)
|
|
/// </summary>
|
|
public async Task SkipVersionAsync(string version)
|
|
{
|
|
try
|
|
{
|
|
await _localStorage.SetItemAsStringAsync(SKIPPED_VERSION_KEY, version);
|
|
_logger.LogInformation("Version {Version} skipped by user", version);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error skipping version");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// پاک کردن همه کشهای اپلیکیشن
|
|
/// </summary>
|
|
private async Task ClearAllCacheAsync()
|
|
{
|
|
try
|
|
{
|
|
// پاک کردن کش مرورگر (Cache Storage و Service Worker)
|
|
await _jsRuntime.InvokeVoidAsync("clearBrowserCache");
|
|
|
|
_logger.LogInformation("Browser cache cleared successfully");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error clearing browser cache");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// دریافت اطلاعات نسخه فعلی
|
|
/// </summary>
|
|
public async Task<AppVersionInfo?> GetCurrentVersionInfoAsync()
|
|
{
|
|
try
|
|
{
|
|
var response = await _client.GetAppVersionAsync(new GetAppVersionRequest
|
|
{
|
|
AppName = APP_NAME
|
|
});
|
|
|
|
if (!response.Found)
|
|
return null;
|
|
|
|
return new AppVersionInfo
|
|
{
|
|
CurrentVersion = response.CurrentVersion,
|
|
MinRequiredVersion = response.MinRequiredVersion,
|
|
RequiresUpdate = response.RequiresUpdate,
|
|
UpdateMessage = response.UpdateMessage,
|
|
ReleaseNotes = response.ReleaseNotes,
|
|
LastUpdated = response.LastUpdated?.ToDateTime()
|
|
};
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
_logger.LogError(ex, "Error getting version info");
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
public class AppVersionInfo
|
|
{
|
|
public string CurrentVersion { get; set; } = string.Empty;
|
|
public string MinRequiredVersion { get; set; } = string.Empty;
|
|
public bool RequiresUpdate { get; set; }
|
|
public string? UpdateMessage { get; set; }
|
|
public string? ReleaseNotes { get; set; }
|
|
public DateTime? LastUpdated { get; set; }
|
|
}
|