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;
}
}