using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using Serilog; namespace ZB.MOM.WW.LmxProxy.Host.Services { /// /// Manages client sessions for the gRPC service. /// Tracks active sessions with unique session IDs. /// public class SessionManager : IDisposable { private static readonly ILogger Logger = Log.ForContext(); private readonly ConcurrentDictionary _sessions = new(); private bool _disposed; /// /// Gets the number of active sessions. /// public int ActiveSessionCount => _sessions.Count; /// /// Creates a new session for a client. /// /// The client identifier. /// The API key used for authentication (optional). /// The session ID for the new session. /// Thrown if the manager is disposed. public string CreateSession(string clientId, string apiKey = null) { if (_disposed) { throw new ObjectDisposedException(nameof(SessionManager)); } var sessionId = Guid.NewGuid().ToString("N"); var sessionInfo = new SessionInfo { SessionId = sessionId, ClientId = clientId ?? string.Empty, ApiKey = apiKey ?? string.Empty, ConnectedAt = DateTime.UtcNow, LastActivity = DateTime.UtcNow }; _sessions[sessionId] = sessionInfo; Logger.Information("Created session {SessionId} for client {ClientId}", sessionId, clientId); return sessionId; } /// /// Validates a session ID and updates the last activity timestamp. /// /// The session ID to validate. /// True if the session is valid; otherwise, false. public bool ValidateSession(string sessionId) { if (_disposed) { return false; } if (string.IsNullOrEmpty(sessionId)) { return false; } if (_sessions.TryGetValue(sessionId, out SessionInfo sessionInfo)) { sessionInfo.LastActivity = DateTime.UtcNow; return true; } return false; } /// /// Gets the session information for a session ID. /// /// The session ID. /// The session information, or null if not found. public SessionInfo GetSession(string sessionId) { if (_disposed || string.IsNullOrEmpty(sessionId)) { return null; } _sessions.TryGetValue(sessionId, out SessionInfo sessionInfo); return sessionInfo; } /// /// Terminates a session. /// /// The session ID to terminate. /// True if the session was terminated; otherwise, false. public bool TerminateSession(string sessionId) { if (_disposed || string.IsNullOrEmpty(sessionId)) { return false; } if (_sessions.TryRemove(sessionId, out SessionInfo sessionInfo)) { Logger.Information("Terminated session {SessionId} for client {ClientId}", sessionId, sessionInfo.ClientId); return true; } return false; } /// /// Gets all active sessions. /// /// A list of all active session information. public IReadOnlyList GetAllSessions() { return _sessions.Values.ToList(); } /// /// Disposes the session manager and clears all sessions. /// public void Dispose() { if (_disposed) { return; } _disposed = true; var count = _sessions.Count; _sessions.Clear(); Logger.Information("SessionManager disposed, cleared {Count} sessions", count); } } /// /// Contains information about a client session. /// public class SessionInfo { /// /// Gets or sets the unique session identifier. /// public string SessionId { get; set; } = string.Empty; /// /// Gets or sets the client identifier. /// public string ClientId { get; set; } = string.Empty; /// /// Gets or sets the API key used for this session. /// public string ApiKey { get; set; } = string.Empty; /// /// Gets or sets the time when the session was created. /// public DateTime ConnectedAt { get; set; } /// /// Gets or sets the time of the last activity on this session. /// public DateTime LastActivity { get; set; } /// /// Gets the connected time as UTC ticks for the gRPC response. /// public long ConnectedSinceUtcTicks => ConnectedAt.Ticks; } }