private static async Task <bool> OnRelease(ArenaSession s) { var l = s.GetLock(); try { using (var t = EndSession(s)) { if (await t) { lock (sessions) { if (s._locks == 0) { s.Session = null; sessions.Remove(s.Email); s.Dispose(); return(true); } } } } } catch (Exception e) { Util.Logging.Log(e); } finally { l.Dispose(); } return(false); }
public async Task AddGame(GameResultModel gameModel) { using (var context = dbContext()) { var game = new GameResult(); game.InjectFrom(gameModel); if (gameModel.Hero != null) { game.Hero = context.Heroes.Find(gameModel.Hero.Id); } if (gameModel.OpponentHero != null) { game.OpponentHero = context.Heroes.Find(gameModel.OpponentHero.Id); } ArenaSessionModel arenaModel = null; ArenaSession arena = null; if (gameModel.ArenaSession != null) { gameModel.Deck = null; game.DeckKey = null; game.Deck = null; arenaModel = gameModel.ArenaSession; arena = context.ArenaSessions.Query().FirstOrDefault(x => x.Id == arenaModel.Id); if (arena == null) { throw new InvalidOperationException("Add arena using gameManager first!"); } // context.Entry(arena).CurrentValues.SetValues(arenaModel); AddGameToArena(game, arena); SetEndDateIfNeeded(arena); arena.Modified = DateTime.Now; } if (gameModel.Deck != null) { game.Deck = context.Decks.Find(gameModel.Deck.Id); } context.Games.Add(game); await context.SaveChangesAsync(); gameModel.InjectFrom(game); events.PublishOnBackgroundThread(new GameResultAdded(this, gameModel)); if (arenaModel != null) { arenaModel.InjectFrom(arena); gameModel.ArenaSession = arenaModel; arenaModel.Games.Add(gameModel); var latestId = context.ArenaSessions.OrderByDescending(x => x.StartDate).Select(x => x.Id).FirstOrDefault(); events.PublishOnBackgroundThread(new ArenaSessionUpdated(arenaModel.Id, latestId == arenaModel.Id)); } } }
public static void MapFrom(this ArenaSessionModel target, ArenaSession source) { target.InjectFrom(source); // target.Games.IsNotifying = false; target.Games.Clear(); target.Games.AddRange(source.Games.Select(g => g.ToModel())); // target.Games.IsNotifying = true; // target.Games.Refresh(); }
private void SetEndDateIfNeeded(ArenaSession arena) { if (arena.IsEnded && arena.EndDate == null) { arena.EndDate = DateTime.Now; } if (!arena.IsEnded && arena.EndDate != null) { arena.EndDate = null; } }
public static ArenaSessionModel ToModel(this ArenaSession arena, int arenaSessionRecurse = 0) { if (arena == null) { return(null); } ArenaSessionModel model = null; model = new ArenaSessionModel(); model.InjectFrom(arena); model.Games.AddRange(arena.Games.Select(x => x.ToModel(arenaSessionRecurse, model))); return(model); }
private static void Release(ArenaSession s) { lock (sessions) { var b = s._locks == 0; if (!b && --s._locks == 0) { s._released = DateTime.UtcNow; b = true; } if (b) { if (!s.HasSession) { var l = s.TryGetLock(); if (l != null) { try { sessions.Remove(s.Email); s.Dispose(); return; } finally { l.Dispose(); } } } } else { return; } if (releasing != null) { releasing.Enqueue(s); } else { releasing = new Queue <ArenaSession>(); releasing.Enqueue(s); ReleaseAsync(); } } }
private static Session GetSession(string email) { ArenaSession s; lock (sessions) { if (!sessions.TryGetValue(email, out s)) { sessions[email] = s = new ArenaSession(email); } ++s._locks; } return(new Session(s)); }
protected void AddGameToArena(GameResult game, ArenaSession arena) { game.ArenaSessionId = arena.Id; game.ArenaSession = arena; arena.Games.Add(game); if (game.Victory) { arena.Wins++; } else { arena.Losses++; } }
private static async Task <bool> VerifySession(ArenaSession s, Settings.PasswordString password, bool ping) { var b = s.HasSession; if (b && ping) { try { b = await s.Session.Ping(); } catch { b = false; } } if (!b) { if (password == null || password.Data.IsEmpty) { return(false); } OnLoginRequest(); using (var t = Tools.ArenaAccount.LoginAccount(s.Email, password.ToSecureString())) { await t; s.Session = t.Result; if (s.Session != null) { s.Password = password; return(true); } else { return(false); } } } return(true); }
public void Dispose() { lock (this) { if (s != null) { Monitor.Enter(s); s._lock = null; Monitor.Pulse(s); Monitor.Exit(s); s = null; } } }
public void Release() { GC.SuppressFinalize(this); ArenaSession s; lock (this) { if (session != null) { s = session; session = null; } else { return; } } s.Release(); }
public async Task <ArenaSessionModel> AddArenaSession(ArenaSessionModel arenaModel) { using (var context = dbContext()) { var arena = new ArenaSession(); arena.InjectFrom(arenaModel); if (arenaModel.Hero != null) { arena.Hero = context.Heroes.Find(arenaModel.Hero.Id); } if (arenaModel.Image1 != null) { var img = context.ArenaDeckImages.Find(arenaModel.Image1.Id); if (img == null) { img = arenaModel.Image1; context.ArenaDeckImages.Add(img); } context.Entry(img).CurrentValues.SetValues(arenaModel.Image1); arena.Image1 = img; } if (arenaModel.Image2 != null) { var img = context.ArenaDeckImages.Find(arenaModel.Image2.Id); if (img == null) { img = arenaModel.Image2; context.ArenaDeckImages.Add(img); } context.Entry(img).CurrentValues.SetValues(arenaModel.Image2); arena.Image2 = img; } context.ArenaSessions.Add(arena); await context.SaveChangesAsync(); arenaModel.InjectFrom(arena); } events.PublishOnBackgroundThread(new ArenaSessionAdded(arenaModel)); return(arenaModel); }
public async Task DeleteGame(Guid id) { using (var context = dbContext()) { var g = context.Games.Query().FirstOrDefault(x => x.Id == id); if (g == null) { events.PublishOnBackgroundThread(new GameResultDeleted(id)); return; // throw new ArgumentException(string.Format("Game with id '{0}' not found", id), "id"); } // work around old bug var deleted = context.DeletedGames.Find(id); if (deleted != null) { context.DeletedGames.Remove(deleted); context.SaveChanges(); } // move to deleted table deleted = new DeletedGameResult(); deleted.InjectFrom(g); deleted.DeletedDate = DateTime.Now; context.DeletedGames.Add(deleted); var arenaId = g.ArenaSessionId; var victory = g.Victory; context.Games.Remove(g); await context.SaveChangesAsync(); ArenaSession arena = null; if (arenaId != null) { arena = context.ArenaSessions.Query().FirstOrDefault(x => x.Id == arenaId); if (arena != null) { //if (victory && arena.IncompleteWins) //{ // arena.Wins--; //} //else if (!victory && arena.IncompleteLosses) //{ // arena.Losses--; //} if (victory) { arena.Wins--; } else { arena.Losses--; } arena.EndDate = null; arena.Modified = DateTime.Now; } } await context.SaveChangesAsync(); events.PublishOnBackgroundThread(new GameResultDeleted(id, arenaId)); if (arena != null) { events.PublishOnBackgroundThread(new ArenaSessionUpdated(arena.Id)); } } }
public Session(ArenaSession session) { this.session = session; }
public async Task UpdateGame(GameResultModel gameModel) { using (var context = dbContext()) { var game = context.Games.FirstOrDefault(x => x.Id == gameModel.Id); if (game == null) { throw new ArgumentException("game does not exist", "gameModel"); } var oldVictory = game.Victory; if (gameModel.ArenaSession != null) { gameModel.Deck = null; } context.Entry(game).CurrentValues.SetValues(gameModel); if (!Equals(gameModel.Hero, game.Hero) && gameModel.Hero != null) { game.Hero = context.Heroes.Find(gameModel.Hero.Id); } if (!Equals(gameModel.OpponentHero, game.OpponentHero) && gameModel.OpponentHero != null) { game.OpponentHero = context.Heroes.Find(gameModel.OpponentHero.Id); } if (!Equals(gameModel.Deck, game.Deck) && gameModel.Deck != null) { game.Deck = context.Decks.Find(gameModel.Deck.Id); } game.Modified = DateTime.Now; await context.SaveChangesAsync(); ArenaSession arena = null; if (gameModel.ArenaSession != null) { arena = context.ArenaSessions.Query().First(x => x.Id == game.ArenaSessionId); if (game.Victory && !oldVictory) { arena.Wins++; arena.Losses--; } else if (!game.Victory && oldVictory) { arena.Wins--; arena.Losses++; } SetEndDateIfNeeded(arena); gameModel.ArenaSession.InjectFrom(arena); arena.Modified = DateTime.Now; await context.SaveChangesAsync(); } gameModel.InjectFrom(game); events.PublishOnBackgroundThread(new GameResultUpdated(gameModel.Id, game.ArenaSessionId)); if (gameModel.ArenaSession != null) { events.PublishOnBackgroundThread(new ArenaSessionUpdated(gameModel.ArenaSession.Id)); } } }
public async Task<ArenaSessionModel> AddArenaSession(ArenaSessionModel arenaModel) { using (var context = this.dbContext()) { var arena = new ArenaSession(); arena.InjectFrom(arenaModel); if (arenaModel.Hero != null) { arena.Hero = context.Heroes.Find(arenaModel.Hero.Id); } if (arenaModel.Image1 != null) { var img = context.ArenaDeckImages.Find(arenaModel.Image1.Id); if (img == null) { img = arenaModel.Image1; context.ArenaDeckImages.Add(img); } context.Entry(img).CurrentValues.SetValues(arenaModel.Image1); arena.Image1 = img; } if (arenaModel.Image2 != null) { var img = context.ArenaDeckImages.Find(arenaModel.Image2.Id); if (img == null) { img = arenaModel.Image2; context.ArenaDeckImages.Add(img); } context.Entry(img).CurrentValues.SetValues(arenaModel.Image2); arena.Image2 = img; } context.ArenaSessions.Add(arena); await context.SaveChangesAsync(); arenaModel.InjectFrom(arena); } this.events.PublishOnBackgroundThread(new ArenaSessionAdded(arenaModel)); return arenaModel; }
private static async void ReleaseAsync() { var delay = true; var last = DateTime.UtcNow; EventHandler onQueueComplete = delegate { last = DateTime.UtcNow; }; AllQueuedLaunchesComplete += onQueueComplete; while (true) { if (delay) { await Task.Delay(20000); } ArenaSession s = null; lock (sessions) { int count = releasing != null ? releasing.Count : 0; if (count == 0) { releasing = null; AllQueuedLaunchesComplete -= onQueueComplete; return; } var now = DateTime.UtcNow; var empty = GetPendingLaunchCount() == 0 && now.Subtract(last).TotalSeconds > 10; while (count-- > 0) { var _s = releasing.Dequeue(); if (_s._locks == 0) { if (!_s.HasSession) { if (_s.IsDisposed) { continue; } //session was never used and can simply be dropped var l = _s.TryGetLock(); if (l != null) { try { sessions.Remove(_s.Email); _s.Dispose(); } finally { l.Dispose(); } continue; } } else if (empty) { //sessions will be dropped after 30s when no accounts are queued if (now.Subtract(_s._released).TotalSeconds > 30) { s = _s; break; } } else if (now.Subtract(_s._released).TotalMinutes > 5) { //assuming it isn't needed s = _s; break; } } else { continue; } releasing.Enqueue(_s); } } if (s != null) { delay = false; var removed = false; try { removed = await OnRelease(s); } catch (Exception e) { Util.Logging.Log(e); } if (!removed) { lock (sessions) { if (s._locks == 0) { releasing.Enqueue(s); } } } } else { delay = true; } } }
/// <summary> /// Ends the session /// </summary> /// <param name="force">Forces logout on sessions in use</param> /// <param name="login">Login if required, otherwise it'll be skipped</param> /// <param name="quick">Only logout</param> private static async Task <bool> EndSession(ArenaSession s, bool force = false, bool login = true, bool quick = false) { if (!s.HasSession) { return(true); } var retry = true; do { var v = Settings.NetworkAuthorization.Value; var removeAll = v.HasFlag(Settings.NetworkAuthorizationFlags.RemoveAll); var removeOthers = removeAll || v.HasFlag(Settings.NetworkAuthorizationFlags.RemovePreviouslyAuthorized); var b = false; try { if (removeOthers && !quick) { //warning: verifying could potentially take a minute if (login && !await VerifySession(s, s.Password, false)) { throw new Exception("Login failed"); } if (!force) { lock (sessions) { if (s._locks > 0) { return(false); } } } b = !s.Session.RequiresAuthentication; } } catch (Exception e) { Util.Logging.Log(e); b = false; } try { if (b) { if (removeOthers) { var networks = await s.Session.GetAuthorizedNetworks(); var count = networks.Length; if (!removeAll) { --count; } for (var i = 0; i < count; i++) { await s.Session.Remove(networks[i]); } } } retry = false; if (s.HasSession) { await s.Session.Logout(); } } catch (Exception e) { Util.Logging.Log(e); if (e is Tools.ArenaAccount.SessionExpiredException && retry && login) { retry = false; continue; } } break; }while (true); return(true); }
/// <summary> /// Logs into the account to check if authentication is required /// </summary> private static VerifyResult DoVerify(ArenaSession s, Settings.IAccount account) { using (var t = VerifySession(s, account.Password, true)) { t.Wait(); if (!t.Result) { throw new Exception("Login failed"); } } if (!s.Session.RequiresAuthentication) { if (account.NetworkAuthorizationState != Settings.NetworkAuthorizationState.Disabled) { account.NetworkAuthorizationState = Settings.NetworkAuthorization.Value.HasFlag(Settings.NetworkAuthorizationFlags.RemoveAll) ? Settings.NetworkAuthorizationState.Unknown : Settings.NetworkAuthorizationState.OK; } return(VerifyResult.OK); } if (account.NetworkAuthorizationState == Settings.NetworkAuthorizationState.OK) { //account was previously authorized, assuming IP was changed - flag all accounts foreach (var _a in Util.Accounts.GetAccounts()) { if (_a.NetworkAuthorizationState == Settings.NetworkAuthorizationState.OK) { _a.NetworkAuthorizationState = Settings.NetworkAuthorizationState.Unknown; } } } switch (s.Session.Authentication) { case Tools.ArenaAccount.AuthenticationType.Email: case Tools.ArenaAccount.AuthenticationType.SMS: break; case Tools.ArenaAccount.AuthenticationType.TOTP: if (account.TotpKey != null) { var now = DateTime.UtcNow.Ticks; byte retry = 0; do { try { if (retry > 0) { OnLoginRequest(); //authorizing can only be attempted once per session using (var t = s.Session.Login(s.Email, account.Password.ToSecureString())) { t.Wait(); if (t.Result) { s.Password = account.Password; if (!s.Session.RequiresAuthentication || s.Session.Authentication != Tools.ArenaAccount.AuthenticationType.TOTP) { break; } } else { break; } } if (retry > 1) { break; } //retrying using the server's time now = s.Session.Date.Ticks; if (now <= 0) { now = DateTime.UtcNow.Ticks; } } var key = Tools.Totp.Generate(account.TotpKey, now); using (var t = s.Session.Authenticate(new string(key))) { t.Wait(); if (t.Result) { break; } } } catch (Exception e) { Util.Logging.Log(e); if (e.InnerException != null) { if (retry == 0 && (e.InnerException is Tools.ArenaAccount.AuthenticationException || e.InnerException is Tools.ArenaAccount.SessionExpiredException)) { retry++; continue; } } retry += 2; } break; }while (true); } break; default: return(VerifyResult.None); } if (s.Session.RequiresAuthentication) { return(VerifyResult.Required); } else { if (account.NetworkAuthorizationState != Settings.NetworkAuthorizationState.Disabled) { account.NetworkAuthorizationState = Settings.NetworkAuthorization.Value.HasFlag(Settings.NetworkAuthorizationFlags.RemoveAll) ? Settings.NetworkAuthorizationState.Unknown : Settings.NetworkAuthorizationState.OK; } return(VerifyResult.Completed); } }
public Lock(ArenaSession s) { this.s = s; }