private async void RetryRpc() { OnRetryStarted.OnNext(this); var retryCount = 10; Debug.Log($"Retry rpc connection. (count: {retryCount})"); while (retryCount > 0) { await Task.Delay(5000); _hub = StreamingHubClient.Connect <IActionEvaluationHub, IActionEvaluationHubReceiver>(_channel, this); try { Debug.Log($"Trying to join hub..."); await _hub.JoinAsync(); Debug.Log($"Join complete! Registering disconnect event..."); RegisterDisconnectEvent(_hub); UpdateSubscribeAddresses(); OnRetryEnded.OnNext(this); return; } catch (RpcException re) { Debug.LogWarning($"RpcException occurred. Retrying... {retryCount}\n{re}"); retryCount--; } catch (ObjectDisposedException ode) { Debug.LogWarning($"ObjectDisposedException occurred. Retrying... {retryCount}\n{ode}"); retryCount--; } catch (Exception e) { Debug.LogWarning($"Unexpected error occurred during rpc connection. {e}"); break; } } Connected = false; OnDisconnected.OnNext(this); }
protected override async Task ExecuteAsync(CancellationToken stoppingToken) { await Task.Delay(1000, stoppingToken); _client = StreamingHubClient.Connect <IActionEvaluationHub, IActionEvaluationHubReceiver>( new Channel(_host, _port, ChannelCredentials.Insecure), null ); await _client.JoinAsync(); _blockRenderer.EveryBlock().Subscribe( async pair => await _client.BroadcastRenderBlockAsync( pair.OldTip.Header.Serialize(), pair.NewTip.Header.Serialize() ), stoppingToken ); _blockRenderer.EveryReorg().Subscribe( async ev => await _client.ReportReorgAsync( ev.OldTip.Serialize(), ev.NewTip.Serialize(), ev.Branchpoint.Serialize() ), stoppingToken ); _blockRenderer.EveryReorgEnd().Subscribe( async ev => await _client.ReportReorgEndAsync( ev.OldTip.Serialize(), ev.NewTip.Serialize(), ev.Branchpoint.Serialize() ), stoppingToken ); _actionRenderer.EveryRender <ActionBase>() .Where(ContainsAddressToBroadcast) .Subscribe( async ev => { var formatter = new BinaryFormatter(); using var c = new MemoryStream(); using var df = new DeflateStream(c, System.IO.Compression.CompressionLevel.Fastest); try { formatter.Serialize(df, ev); await _client.BroadcastRenderAsync(c.ToArray()); } catch (SerializationException se) { // FIXME add logger as property Log.Error(se, "Skip broadcasting render since the given action isn't serializable."); } catch (Exception e) { // FIXME add logger as property Log.Error(e, "Skip broadcasting render due to the unexpected exception"); } }, stoppingToken ); _actionRenderer.EveryUnrender <ActionBase>() .Where(ContainsAddressToBroadcast) .Subscribe( async ev => { var formatter = new BinaryFormatter(); using var c = new MemoryStream(); using var df = new DeflateStream(c, System.IO.Compression.CompressionLevel.Fastest); try { formatter.Serialize(df, ev); await _client.BroadcastUnrenderAsync(c.ToArray()); } catch (SerializationException se) { // FIXME add logger as property Log.Error(se, "Skip broadcasting unrender since the given action isn't serializable."); } catch (Exception e) { // FIXME add logger as property Log.Error(e, "Skip broadcasting unrender due to the unexpected exception"); } }, stoppingToken ); _exceptionRenderer.EveryException().Subscribe( async tuple => { var(code, message) = tuple; await _client.ReportExceptionAsync((int)code, message); }, stoppingToken ); _nodeStatusRenderer.EveryChangedStatus().Subscribe( async isPreloadStarted => { if (isPreloadStarted) { await _client.PreloadStartAsync(); } else { await _client.PreloadEndAsync(); } }, stoppingToken ); }
private IEnumerator CoJoin(Action <bool> callback) { Task t = Task.Run(async() => { await _hub.JoinAsync(); }); yield return(new WaitUntil(() => t.IsCompleted)); if (t.IsFaulted) { callback?.Invoke(false); yield break; } Connected = true; // 에이전트의 상태를 한 번 동기화 한다. Currency goldCurrency = new GoldCurrencyState( (Dictionary)GetState(GoldCurrencyState.Address) ).Currency; States.Instance.SetAgentState( GetState(Address) is Bencodex.Types.Dictionary agentDict ? new AgentState(agentDict) : new AgentState(Address)); States.Instance.SetGoldBalanceState( new GoldBalanceState(Address, GetBalance(Address, goldCurrency))); // 랭킹의 상태를 한 번 동기화 한다. for (var i = 0; i < RankingState.RankingMapCapacity; ++i) { var address = RankingState.Derive(i); var mapState = GetState(address) is Bencodex.Types.Dictionary serialized ? new RankingMapState(serialized) : new RankingMapState(address); States.Instance.SetRankingMapStates(mapState); } // 상점의 상태를 한 번 동기화 한다. States.Instance.SetShopState( GetState(ShopState.Address) is Bencodex.Types.Dictionary shopDict ? new ShopState(shopDict) : new ShopState()); if (GetState(GameConfigState.Address) is Dictionary configDict) { States.Instance.SetGameConfigState(new GameConfigState(configDict)); } else { throw new FailedToInstantiateStateException <GameConfigState>(); } if (ArenaHelper.TryGetThisWeekState(BlockIndex, out var weeklyArenaState)) { States.Instance.SetWeeklyArenaState(weeklyArenaState); } else { throw new FailedToInstantiateStateException <WeeklyArenaState>(); } ActionRenderHandler.Instance.GoldCurrency = goldCurrency; // 그리고 모든 액션에 대한 랜더와 언랜더를 핸들링하기 시작한다. BlockRenderHandler.Instance.Start(BlockRenderer); ActionRenderHandler.Instance.Start(ActionRenderer); ActionUnrenderHandler.Instance.Start(ActionRenderer); UpdateSubscribeAddresses(); callback?.Invoke(true); }