private async Task<ConnectionDescriptor> EnsureConnectionAsync(ClientActionContext context, SessionDescriptor sessionDescriptor) { if (sessionDescriptor.State == ProxyState.Open) { context.ActionResult = sessionDescriptor.InitSessionResult; return sessionDescriptor.ServerConnection; } if (sessionDescriptor.State == ProxyState.Closed) { throw new ProxyClosedException(); } using (await sessionDescriptor.LockAsync()) { // check connections tate again when under lock if (sessionDescriptor.State == ProxyState.Open) { context.ActionResult = sessionDescriptor.InitSessionResult; return sessionDescriptor.ServerConnection; } if (sessionDescriptor.State == ProxyState.Closed) { throw new ProxyClosedException(); } ClientActionContext initSessionContext = context; if (context.Action != sessionDescriptor.Contract.InitSession) { // we are not initializaing proxy explicitely, so we need to check whether proxy has been initalized before if (sessionDescriptor.RequiresInitParameters) { if (sessionDescriptor.InitSessionParameters == null) { // we can not reuse initialization parameters, so throw throw new BoltClientException( "Proxy need to be initialized before it can be used.", ClientErrorCode.ProxyNotInitialized, context.Action, null); } } // create init session context and reuse init parameters initSessionContext = new ClientActionContext( context.Proxy, context.Contract, sessionDescriptor.Contract.InitSession, sessionDescriptor.InitSessionParameters); } else if (sessionDescriptor.RequiresInitParameters) { try { BoltFramework.ValidateParameters(sessionDescriptor.Contract.InitSession, initSessionContext.Parameters); } catch (Exception e) { // we can not reuse initialization parameters, so throw throw new BoltClientException( $"Proxy is beeing initialized with invalid parameters. If session initialization has non empty parameters you should initialize it first by calling '{initSessionContext.Action.Name}' with proper parameters.", ClientErrorCode.InvalidInitSessionParameters, context.Action, e); } } try { // execute whole pipeline await Next(initSessionContext); // extract connection and session id from response string sessionId = ClientSessionHandler.GetSessionIdentifier(initSessionContext.Response); if (sessionId == null) { throw new BoltServerException( ServerErrorCode.SessionIdNotReceived, sessionDescriptor.Contract.InitSession, initSessionContext.Request?.RequestUri?.ToString()); } if (initSessionContext.ServerConnection == null) { throw new BoltClientException(ClientErrorCode.ConnectionUnavailable, initSessionContext.Action); } sessionDescriptor.InitSessionResult = initSessionContext.ActionResult; sessionDescriptor.InitSessionParameters = initSessionContext.Parameters; sessionDescriptor.SessionId = sessionId; sessionDescriptor.ServerConnection = initSessionContext.ServerConnection; sessionDescriptor.ChangeState(context.Proxy, ProxyState.Open); } catch (Exception e) { Exception handled = HandleOpenConnectionError(initSessionContext, e, sessionDescriptor); if (handled == e) { throw; } if (handled != null) { throw handled; } throw; } finally { // we should not dispose original context if (context.Action != sessionDescriptor.Contract.InitSession) { initSessionContext.Dispose(); } } return sessionDescriptor.ServerConnection; } }
protected virtual Exception HandleOpenConnectionError(ClientActionContext context, Exception error, SessionDescriptor session) { session.ClearSession(); ErrorHandlingResult handlingResult = ErrorHandling.Handle(context, error); switch (handlingResult) { case ErrorHandlingResult.Close: session.ChangeState(context.Proxy, ProxyState.Closed); break; case ErrorHandlingResult.Recover: case ErrorHandlingResult.Rethrow: session.ChangeState(context.Proxy, ProxyState.Ready); break; default: throw new ArgumentOutOfRangeException(); } return error; }