261 lines
8.8 KiB
C#
261 lines
8.8 KiB
C#
using System;
|
||
using System.IO;
|
||
using Электронная_Фармация.Properties;
|
||
|
||
namespace Электронная_Фармация.Classes
|
||
{
|
||
/// <summary>
|
||
/// Shared application paths and API settings.
|
||
/// </summary>
|
||
public static class AppConfig
|
||
{
|
||
public const string DefaultApiBaseUrl = "https://24pharmdata.ru";
|
||
public const string DefaultUpdateCheckBaseUrl = "https://git.24pharmdata.ru";
|
||
public const string DefaultUpdateRepo = "pharmdata/elfisa-pharmacy";
|
||
private const string LegacyApiBaseUrl = "http://195.34.241.84:9988";
|
||
private const string ApiBaseUrlEnvVar = "ELF_API_BASE_URL";
|
||
private static bool _sqliteInteropPrepared;
|
||
private static readonly object _sqliteInteropLock = new object();
|
||
|
||
/// <summary>
|
||
/// Replaces known dead API URLs in saved user settings.
|
||
/// </summary>
|
||
/// <summary>
|
||
/// Carries user settings across AssemblyVersion bumps (new user.config folder).
|
||
/// </summary>
|
||
public static void UpgradeUserSettingsIfNeeded()
|
||
{
|
||
try
|
||
{
|
||
if (Settings.Default.UpgradeSettings)
|
||
{
|
||
Settings.Default.Upgrade();
|
||
Settings.Default.UpgradeSettings = false;
|
||
Settings.Default.Save();
|
||
AppDebugLog.Info("AppConfig", "User settings upgraded from previous version");
|
||
}
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
AppDebugLog.Info("AppConfig", $"Upgrade settings skipped: {ex.Message}");
|
||
}
|
||
}
|
||
|
||
public static void MigrateLegacySettings()
|
||
{
|
||
var current = Settings.Default.ApiBaseUrl;
|
||
if (string.IsNullOrWhiteSpace(current))
|
||
{
|
||
return;
|
||
}
|
||
|
||
var normalized = NormalizeApiBaseUrl(current);
|
||
if (string.Equals(normalized, LegacyApiBaseUrl, StringComparison.OrdinalIgnoreCase) ||
|
||
string.Equals(normalized, "http://195.34.241.84:9988", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
Settings.Default.ApiBaseUrl = DefaultApiBaseUrl;
|
||
Settings.Default.stringToken = string.Empty;
|
||
Settings.Default.Save();
|
||
AppDebugLog.Info("AppConfig", $"ApiBaseUrl мигрирован: {LegacyApiBaseUrl} -> {DefaultApiBaseUrl}");
|
||
}
|
||
}
|
||
|
||
public static string ApiBaseUrl
|
||
{
|
||
get
|
||
{
|
||
var fromSettings = Settings.Default.ApiBaseUrl;
|
||
if (!string.IsNullOrWhiteSpace(fromSettings))
|
||
{
|
||
return NormalizeApiBaseUrl(fromSettings);
|
||
}
|
||
|
||
var fromEnv = Environment.GetEnvironmentVariable(ApiBaseUrlEnvVar);
|
||
if (!string.IsNullOrWhiteSpace(fromEnv))
|
||
{
|
||
return NormalizeApiBaseUrl(fromEnv);
|
||
}
|
||
|
||
return DefaultApiBaseUrl;
|
||
}
|
||
}
|
||
|
||
public static string NormalizeApiBaseUrl(string url)
|
||
{
|
||
if (string.IsNullOrWhiteSpace(url))
|
||
{
|
||
return DefaultApiBaseUrl;
|
||
}
|
||
|
||
url = url.Trim().TrimEnd('/');
|
||
if (!url.StartsWith("http://", StringComparison.OrdinalIgnoreCase) &&
|
||
!url.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
|
||
{
|
||
url = "http://" + url;
|
||
}
|
||
|
||
return url;
|
||
}
|
||
|
||
public static string SqliteDbPath
|
||
{
|
||
get
|
||
{
|
||
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
||
var root = Path.Combine(baseDir, "efClient.db");
|
||
var data = Path.Combine(baseDir, "Data", "efClient.db");
|
||
if (File.Exists(root))
|
||
{
|
||
return root;
|
||
}
|
||
|
||
if (File.Exists(data))
|
||
{
|
||
return data;
|
||
}
|
||
|
||
return root;
|
||
}
|
||
}
|
||
|
||
public static string SqliteConnectionString
|
||
{
|
||
get
|
||
{
|
||
EnsureSQLiteInteropInBaseDir();
|
||
return $"Data Source={SqliteDbPath};Version=3;New=False;";
|
||
}
|
||
}
|
||
|
||
public static string LocationId
|
||
{
|
||
get { return Settings.Default.LocationId ?? string.Empty; }
|
||
}
|
||
|
||
public static void SetLocationId(string locationId)
|
||
{
|
||
Settings.Default.LocationId = (locationId ?? string.Empty).Trim();
|
||
Settings.Default.Save();
|
||
}
|
||
|
||
public static string InvoiceExportPath
|
||
{
|
||
get { return Settings.Default.InvoiceExportPath ?? string.Empty; }
|
||
}
|
||
|
||
public static void SetInvoiceExportPath(string path)
|
||
{
|
||
Settings.Default.InvoiceExportPath = (path ?? string.Empty).Trim();
|
||
Settings.Default.Save();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Gitea base URL for forced update checks (no trailing slash).
|
||
/// </summary>
|
||
public static string UpdateCheckBaseUrl
|
||
{
|
||
get
|
||
{
|
||
var fromEnv = Environment.GetEnvironmentVariable("ELF_UPDATE_CHECK_BASE_URL");
|
||
if (!string.IsNullOrWhiteSpace(fromEnv))
|
||
{
|
||
return NormalizeApiBaseUrl(fromEnv);
|
||
}
|
||
|
||
var fromSettings = Settings.Default.UpdateCheckBaseUrl;
|
||
if (!string.IsNullOrWhiteSpace(fromSettings))
|
||
{
|
||
return NormalizeApiBaseUrl(fromSettings);
|
||
}
|
||
|
||
return DefaultUpdateCheckBaseUrl;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// owner/repo on Gitea, e.g. pharmdata/elfisa-pharmacy.
|
||
/// </summary>
|
||
public static string UpdateRepo
|
||
{
|
||
get
|
||
{
|
||
var fromEnv = Environment.GetEnvironmentVariable("ELF_UPDATE_REPO");
|
||
if (!string.IsNullOrWhiteSpace(fromEnv))
|
||
{
|
||
return fromEnv.Trim().Trim('/');
|
||
}
|
||
|
||
var fromSettings = Settings.Default.UpdateRepo;
|
||
if (!string.IsNullOrWhiteSpace(fromSettings))
|
||
{
|
||
return fromSettings.Trim().Trim('/');
|
||
}
|
||
|
||
return DefaultUpdateRepo;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Optional read-only Gitea token for private release repos.
|
||
/// </summary>
|
||
public static string UpdateApiToken
|
||
{
|
||
get
|
||
{
|
||
var fromEnv = Environment.GetEnvironmentVariable("ELF_UPDATE_API_TOKEN");
|
||
if (!string.IsNullOrWhiteSpace(fromEnv))
|
||
{
|
||
return fromEnv.Trim();
|
||
}
|
||
|
||
return Settings.Default.UpdateApiToken ?? string.Empty;
|
||
}
|
||
}
|
||
|
||
private static void EnsureSQLiteInteropInBaseDir()
|
||
{
|
||
// System.Data.SQLite ожидает SQLite.Interop.dll рядом с exe.
|
||
// Важно: разрядность DLL должна совпадать с процессом (Prefer32Bit => x86).
|
||
if (_sqliteInteropPrepared)
|
||
{
|
||
return;
|
||
}
|
||
|
||
lock (_sqliteInteropLock)
|
||
{
|
||
if (_sqliteInteropPrepared)
|
||
{
|
||
return;
|
||
}
|
||
|
||
var baseDir = AppDomain.CurrentDomain.BaseDirectory;
|
||
var targetDll = Path.Combine(baseDir, "SQLite.Interop.dll");
|
||
var archFolder = Environment.Is64BitProcess ? "x64" : "x86";
|
||
var sourceDll = Path.Combine(baseDir, archFolder, "SQLite.Interop.dll");
|
||
var sourcePdb = Path.Combine(baseDir, archFolder, "SQLite.Interop.pdb");
|
||
|
||
try
|
||
{
|
||
if (File.Exists(sourceDll))
|
||
{
|
||
// Всегда подкладываем DLL нужной разрядности (даже если в корне уже лежит "чужая").
|
||
File.Copy(sourceDll, targetDll, overwrite: true);
|
||
|
||
var targetPdb = Path.Combine(baseDir, "SQLite.Interop.pdb");
|
||
if (File.Exists(sourcePdb))
|
||
{
|
||
File.Copy(sourcePdb, targetPdb, overwrite: true);
|
||
}
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// Если копирование не удалось (права/readonly/и т.п.), дальше будет явное исключение от SQLite.
|
||
}
|
||
|
||
_sqliteInteropPrepared = true;
|
||
}
|
||
}
|
||
}
|
||
}
|