using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using FrameworkDAL.CustomCode.SessionStore; using FrameworkDAL.DTO.SessionStore; using GB5Shared.DTO.Framework.Login; using Microsoft.Extensions.Logging; namespace FrameworkBLL.SessionStore { /// /// Session-management service for MSESSIONSTORE in the GB5 system database. /// /// Mirrors the role of BaseEntityAppService for the session lifecycle: /// Insert → called at login (upsert to handle re-login safely) /// Update → called on activity heartbeat /// Delete → called on logout or force-logout /// Queries → consumed by the auto-logout background job /// /// All writes target the GB5 system DB — never the tenant DB — /// regardless of which client connection is active at call time. /// public class SessionStoreBLL : ISessionStoreBLL { private readonly ISessionStoreDAL _dal; private readonly ILogger _logger; public SessionStoreBLL(ISessionStoreDAL dal, ILogger logger) { _dal = dal; _logger = logger; } /// public async Task InsertSessionAsync(SessionStoreDTO dto, LoginDTO login, CancellationToken ct = default) { if (dto is null) throw new ArgumentNullException(nameof(dto)); // Ensure MachineIp is never null (NVARCHAR column, nullable in DB but cleaner to default) if (string.IsNullOrEmpty(dto.MachineIp)) dto.MachineIp = string.Empty; await _dal.UpsertSessionAsync(dto, ct).ConfigureAwait(false); _logger.LogInformation( "Session inserted | ServerconfigId={ServerconfigId} LoginEventLogId={LoginEventLogId} UserId={UserId}", dto.ServerconfigId, dto.LoginEventLogId, dto.UserId); } /// public async Task UpdateSessionAsync( int serverConfigId, int loginEventLogId, DateTime lastUsedTime, LoginDTO login, CancellationToken ct = default) { await _dal.UpdateSessionAsync(serverConfigId, loginEventLogId, lastUsedTime, ct).ConfigureAwait(false); } /// public async Task DeleteSessionAsync( int serverConfigId, int loginEventLogId, LoginDTO login, CancellationToken ct = default) { if (loginEventLogId <= 0) { _logger.LogWarning("DeleteSession skipped — LoginEventLogId={LoginEventLogId} is invalid.", loginEventLogId); return; } await _dal.DeleteSessionAsync(serverConfigId, loginEventLogId, ct).ConfigureAwait(false); _logger.LogInformation( "Session deleted | ServerconfigId={ServerconfigId} LoginEventLogId={LoginEventLogId}", serverConfigId, loginEventLogId); } /// public async Task LogOutIfPresentAsync( int serverConfigId, int loginEventLogId, LoginDTO login, CancellationToken ct = default) { if (loginEventLogId <= 0) { _logger.LogWarning("LogOutIfPresent skipped — LoginEventLogId={LoginEventLogId} is invalid.", loginEventLogId); return false; } int count = await _dal.GetSessionCountAsync(serverConfigId, loginEventLogId, ct).ConfigureAwait(false); if (count == 0) { _logger.LogInformation( "LogOutIfPresent — no active session | ServerconfigId={ServerconfigId} LoginEventLogId={LoginEventLogId}.", serverConfigId, loginEventLogId); return false; } await _dal.DeleteSessionAsync(serverConfigId, loginEventLogId, ct).ConfigureAwait(false); _logger.LogInformation( "LogOutIfPresent — session removed | ServerconfigId={ServerconfigId} LoginEventLogId={LoginEventLogId}.", serverConfigId, loginEventLogId); return true; } /// public async Task> GetUnusedSessionsAsync( int serverConfigId, int expiryMinutes, LoginDTO login, CancellationToken ct = default) { return await _dal.GetUnusedSessionsAsync(serverConfigId, expiryMinutes, ct).ConfigureAwait(false); } /// public async Task DeleteOldSessionsAsync(DateTime todayDate, LoginDTO login, CancellationToken ct = default) { await _dal.DeleteOldSessionsAsync(todayDate, ct).ConfigureAwait(false); } } }