using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using PhilExampleCrawler.Common.Models; using PhilExampleCrawler.Common.TCP.Enums; using PhilExampleCrawler.Common.TCP.Packets; namespace PhilExampleCrawler.TCPAPI.Services { internal class UserSessionService { internal IReadOnlyDictionary RunningSessions => new Dictionary(_openSessions); /// represents connectionID, UserSession private readonly Dictionary _openSessions = new(); private readonly List _suspendedSessions = new(); private static int _lastSessionID = 0; private static int NextSessionID() => _lastSessionID++; private static DateTime NextValidUntil() => DateTime.Now.AddMinutes(60); internal UserSessionService() { if (Program.TCPServer == null) throw new InvalidOperationException("Program.TCPServer must not be null when using UserService."); Program.TCPServer.OnDataReceived += TCPServer_OnDataReceived; Program.TCPServer.OnUserDisconnected += TCPServer_OnUserDisconnected; } private void TCPServer_OnUserDisconnected(object? sender, int connectionID) { if(_openSessions.TryGetValue(connectionID, out UserSession? sess)) { if (sess == null) _openSessions.Remove(connectionID); else { _openSessions.Remove(connectionID); _suspendedSessions.Add(sess); } } } private async void TCPServer_OnDataReceived(object? sender, (int connectionID, BasePacket bp) e) { if(e.bp.LoadData.Type == LoadType.RegisterUserSessionLoad && e.bp.LoadData is RegisterUserSessionLoad regLoad) { var newSess = await RegisterUserSession(e.connectionID, regLoad); if (newSess != null) { if (Program.TCPServer.Send(e.connectionID, new BasePacket( new RegisterUserSessionOKLoad() { ForAuthCode = regLoad.AuthCode, ValidUntil = newSess.ValidUntil }))) Console.WriteLine("sent back RegisterUserSessionOKLoad to connectionID:" + e.connectionID); else Console.WriteLine("[Error2] TODO: could not send back RegisterUserSessionOKLoad to connectionID:" + e.connectionID); } else Console.WriteLine("[Error2] TODO: could not send back RegisterUserSessionOKLoad to connectionID:" + e.connectionID); } } private async Task RegisterUserSession(int connectionID, RegisterUserSessionLoad regLoad) { if(TryUnsuspendSession(regLoad.AuthCode, out UserSession? unsuspendedSess) && unsuspendedSess != null) { _openSessions.Add(connectionID, unsuspendedSess); return unsuspendedSess; } var sessID = NextSessionID(); var validUntil = NextValidUntil(); var user = await Program.DB_UserAcces.GetUserAsync(regLoad.AuthCode); var crawlSessions = await Program.DB_CrawlSessionAccess.GetCrawlSessionsAsync(user.ID); var newSess = new UserSession(sessID, user, crawlSessions, validUntil); if (_openSessions.TryGetValue(connectionID, out UserSession? _)) _openSessions[connectionID] = newSess; else _openSessions.Add(connectionID, newSess); return newSess; } /// Removes a session with given authCode from _suspendedSessions and updates its ValidUntil private bool TryUnsuspendSession(string authCode, out UserSession? unsuspendedSess) { unsuspendedSess = _suspendedSessions.FirstOrDefault(x => x.User.AuthCode == authCode); if (unsuspendedSess != null) { unsuspendedSess.ValidUntil = NextValidUntil(); _suspendedSessions.Remove(unsuspendedSess); return true; } else return false; } } }