/// <inheritdoc /> public async Task TryToStartGameAsync(INetworkSigningAccount networkSigningAccount, ContractAddress gameContract, INetworkBlockHeader blockHeader, CancellationToken cancellationToken) { if (!this._contractInfo.Addresses.TryGetValue(key: networkSigningAccount.Network, out ContractAddress? gameManagerContractAddress)) { // Contract not supported on the network return; } await using (IObjectLock <EthereumAddress>?gameManagerLock = await this._gameManagerLockManager.TakeLockAsync(gameManagerContractAddress)) { if (gameManagerLock == null) { // something else has the game manager locked so is probably doing something important with it return; } bool canGameBeStarted = await this._gameRoundDataManager.CanStartAGameAsync(gameManagerContract: gameManagerContractAddress, (int)GameRoundParameters.InterGameDelay.TotalSeconds); if (!canGameBeStarted) { // Has active games don't start a new one return; } this._logger.LogInformation($"{blockHeader.Network.Name}: Starting new game of game contract {gameContract} using game manager: {gameManagerContractAddress}"); await this._gameManager.StartGameAsync(account : networkSigningAccount, gameContract : gameContract, networkBlockHeader : blockHeader, cancellationToken : cancellationToken); } }
private async Task EndGameRoundAsync(INetworkBlockHeader blockHeader, GameRound gameRound, CancellationToken cancellationToken) { await using (IObjectLock <GameRoundId>?gameRoundLock = await this._gameRoundLockManager.TakeLockAsync(gameRound.GameRoundId)) { if (gameRoundLock == null) { // something else has the game round locked this._logger.LogInformation($"{gameRound.Network.Name}: could not get lock for {gameRound.GameRoundId}"); return; } try { INetworkSigningAccount signingAccount = this._ethereumAccountManager.GetAccount(new NetworkAccount(network: gameRound.Network, address: gameRound.CreatedByAccount)); this._logger.LogInformation($"{gameRound.Network.Name}: End using game round: {gameRound.GameRoundId}"); await this._gameManager.EndGameAsync(account : signingAccount, gameRoundId : gameRound.GameRoundId, networkBlockHeader : blockHeader, cancellationToken : cancellationToken); } catch (Exception exception) { this._logger.LogError(new EventId(exception.HResult), exception: exception, $"{gameRound.Network.Name}: Failed to end game {gameRound.GameRoundId}: {exception.Message}"); } } }
/// <inheritdoc /> public async Task <bool> HandleAsync(EventMiningContext eventMiningContext, NetworkEventLog <TEvent> eventOutput) { try { this.Logger.LogInformation($"{eventOutput.Network.Name}: Event {this.GetType().Name} Game {eventOutput.Event.GameRoundId}"); CancellationToken cancellationToken = CancellationToken.None; await using (IObjectLock <GameRoundId>?gameRoundLock = await this._gameRoundLockManager.TakeLockAsync(eventOutput.Event.GameRoundId)) { if (gameRoundLock == null) { this.Logger.LogWarning( $"{eventOutput.Network.Name}: Event {this.GetType().Name} Game {eventOutput.Event.GameRoundId} - Could not acquire lock, for event in block {eventMiningContext.NetworkBlockHeader.Number.Value} ({eventMiningContext.NetworkBlockHeader.Hash}). Transaction will need retrying... TX: {eventMiningContext.TransactionHash}."); return(false); } GameRound?gameRound = await this.GameRoundDataManager.GetAsync(eventOutput.Event.GameRoundId); if (gameRound == null) { // Game doesn't exist return(true); } if (gameRound.Status == GameRoundStatus.COMPLETED) { // Game already completed - don't need to do anything here. return(true); } bool result = await this.ProcessEventUnderLockAsync(gameRound : gameRound, eventData : eventOutput.Event, transactionHash : eventMiningContext.TransactionHash, networkBlockHeader : eventMiningContext.NetworkBlockHeader, cancellationToken : cancellationToken); if (!result) { this.Logger.LogWarning( $"{eventOutput.Network.Name}: Event {this.GetType().Name} Game {eventOutput.Event.GameRoundId} - Event Handler Returned False: Incomplete, for event in block {eventMiningContext.NetworkBlockHeader.Number.Value} ({eventMiningContext.NetworkBlockHeader.Hash}). Transaction will need retrying... TX: {eventMiningContext.TransactionHash}."); } return(result); } } catch (Exception exception) { this.Logger.LogWarning(new EventId(exception.HResult), exception: exception, $"{eventOutput.Network.Name}: Event {this.GetType().Name} Game {eventOutput.Event.GameRoundId} - Event Handler failed to process, for event in block {eventMiningContext.NetworkBlockHeader.Number.Value} ({eventMiningContext.NetworkBlockHeader.Hash}). Transaction will need retrying... TX: {eventMiningContext.TransactionHash}."); return(false); } }
public Locked( T model, IEnumerable <LockedObject> lockables, ILockResolver resolver) { this.model = model; this.relatives = lockables; this.lockList = new ThreadLocal <LinkedList <ILockStateInternal> >(() => new LinkedList <ILockStateInternal>(new Locked().Yield())); if (resolver == null) { this.@lock = new FastObjectLock(); } else { this.@lock = new ResolveableObjectLock(model, resolver); } }
TResult ILockStateInternal.Unlock <T, TResult>( LinkedList <ILockStateInternal> lockList, IObjectLock @lock, T obj, Func <T, TResult> fn) { var state = new SharedUnlocked(); lockList.AddLast(state); @lock.TakeSharedLock(state); var r = fn(obj); @lock.ExitSharedLock(); lockList.RemoveLast(); return(r); }
TResult ILockStateInternal.UnlockExclusive <TResult>(LinkedList <ILockStateInternal> lockList, IObjectLock @lock, Func <TResult> fn) { var state = new ExclusiveUnlocked(); lockList.AddLast(state); @lock.TakeExclusiveLock(state); var r = fn(); @lock.ExitExclusiveLock(); lockList.RemoveLast(); return(r); }
TResult ILockStateInternal.UnlockUpgradeable <T, TResult>(LinkedList <ILockStateInternal> lockList, IObjectLock @lock, T obj, Func <T, TResult> fn) { return(fn(obj)); }
TResult ILockStateInternal.Unlock <TResult>(LinkedList <ILockStateInternal> lockList, IObjectLock @lock, Func <TResult> fn) { return(fn()); }
TResult ILockStateInternal.UnlockExclusive <T, TResult>(LinkedList <ILockStateInternal> lockList, IObjectLock @lock, T obj, Func <T, TResult> fn) { // Will throw LockRecursionException @lock.TakeExclusiveLock(new ExclusiveUnlocked()); return(fn(obj)); }