protected virtual Task InitializePersistentState() { _hostShutdownToken = _context.Environment.GetShutdownToken(); _requestLifeTime = new HttpRequestLifeTime(this, WriteQueue, Trace, ConnectionId); // Create the TCS that completes when the task returned by PersistentConnection.OnConnected does. _connectTcs = new DispatchingTaskCompletionSource <object>(); // Create a token that represents the end of this connection's life _connectionEndTokenSource = new SafeCancellationTokenSource(); _connectionEndToken = _connectionEndTokenSource.Token; // Handle the shutdown token's callback so we can end our token if it trips _hostRegistration = _hostShutdownToken.SafeRegister(state => { ((SafeCancellationTokenSource)state).Cancel(); }, _connectionEndTokenSource); // When the connection ends release the request _connectionEndRegistration = CancellationToken.SafeRegister(state => { ((HttpRequestLifeTime)state).Complete(); }, _requestLifeTime); return(InitializeMessageId()); }
/// <summary> /// Starts the <see cref="Connection"/>. /// </summary> /// <param name="transport">The transport to use.</param> /// <returns>A task that represents when the connection has started.</returns> public Task Start(IClientTransport transport) { if (transport == null) { throw new ArgumentNullException("transport"); } lock (_startLock) { if (!ChangeState(ConnectionState.Disconnected, ConnectionState.Connecting)) { return(_connectTask ?? TaskAsyncHelper.Empty); } _disconnectCts = new CancellationTokenSource(); _startTcs = new DispatchingTaskCompletionSource <object>(); _receiveQueueMonitor = new TaskQueueMonitor(this, DeadlockErrorTimeout); _receiveQueue = new TaskQueue(_startTcs.Task, _receiveQueueMonitor); _lastQueuedReceiveTask = TaskAsyncHelper.Empty; _transport = transport; _connectTask = Negotiate(transport); } return(_connectTask); }
public override Task Send(IConnection connection, string data, string connectionData) { if (connection == null) { throw new ArgumentNullException("connection"); } var webSocket = _webSocket; if (webSocket == null) { Exception ex; if (connection.State != ConnectionState.Disconnected) { // Make this a faulted task and trigger the OnError even to maintain consistency with the HttpBasedTransports ex = new InvalidOperationException(ResourcesStore.GetResourceString("Error_DataCannotBeSentDuringWebSocketReconnect")); connection.OnError(ex); } else { ex = new InvalidOperationException(ResourcesStore.GetResourceString("Error_DataCannotBeSentDuringWebSocketReconnect")); } var tcs = new DispatchingTaskCompletionSource <object>(); tcs.SetException(ex); return(tcs.Task); } return(Send(webSocket, data)); }
private Task ExecuteHubEvent(IRequest request, string connectionId, Func <IHub, Task> action) { var hubs = GetHubs(request, connectionId).ToList(); var operations = hubs.Select(instance => action(instance).OrEmpty().Catch(Trace)).ToArray(); if (operations.Length == 0) { DisposeHubs(hubs); return(TaskAsyncHelper.Empty); } var tcs = new DispatchingTaskCompletionSource <object>(); Task.Factory.ContinueWhenAll(operations, tasks => { DisposeHubs(hubs); var faulted = tasks.FirstOrDefault(t => t.IsFaulted); if (faulted != null) { tcs.TrySetUnwrappedException(faulted.Exception); } else if (tasks.Any(t => t.IsCanceled)) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(null); } }); return(tcs.Task); }
public virtual Task <int> ExecuteNonQueryAsync() { var tcs = new DispatchingTaskCompletionSource <int>(); Execute(cmd => cmd.ExecuteNonQueryAsync(), tcs); return(tcs.Task); }
public SendContext(ScaleoutStream stream, Func <object, Task> send, object state) { Stream = stream; TaskCompletionSource = new DispatchingTaskCompletionSource <object>(); _send = send; _state = state; }
private static Task <T> FromAsync <T>(Func <AsyncCallback, IAsyncResult> begin, Func <IAsyncResult, T> end) { var tcs = new DispatchingTaskCompletionSource <T>(); try { var result = begin(ar => { if (!ar.CompletedSynchronously) { CompleteAsync(tcs, ar, end); } }); if (result.CompletedSynchronously) { CompleteAsync(tcs, result, end); } } catch (Exception ex) { tcs.TrySetException(ex); } return(tcs.Task); }
private void Execute <T>(Func <IDbCommand, Task <T> > commandFunc, DispatchingTaskCompletionSource <T> tcs) { IDbConnection connection = null; try { connection = _dbProviderFactory.CreateConnection(); connection.ConnectionString = ConnectionString; var command = CreateCommand(connection); connection.Open(); commandFunc(command) .Then(result => tcs.SetResult(result)) .Catch(ex => tcs.SetUnwrappedException(ex), Trace) .Finally(state => { var conn = (DbConnection)state; if (conn != null) { conn.Dispose(); } }, connection); } catch (Exception) { if (connection != null) { connection.Dispose(); } throw; } }
public static Task <string> ReadAsString(this IResponse response, Func <ArraySegment <byte>, bool> onChunk) { if (response == null) { throw new ArgumentNullException("response"); } var stream = response.GetStream(); var reader = new AsyncStreamReader(stream); var result = new StringBuilder(); var resultTcs = new DispatchingTaskCompletionSource <string>(); reader.Data = buffer => { if (onChunk(buffer)) { result.Append(Encoding.UTF8.GetString(buffer.Array, buffer.Offset, buffer.Count)); } }; reader.Closed = exception => { response.Dispose(); resultTcs.TrySetResult(result.ToString()); }; reader.Start(); return(resultTcs.Task); }
public HttpRequestLifeTime(TransportDisconnectBase transport, TaskQueue writeQueue, TraceSource trace, string connectionId) { _lifetimeTcs = new DispatchingTaskCompletionSource <object>(); _transport = transport; _trace = trace; _connectionId = connectionId; _writeQueue = writeQueue; }
public Task StartReceiving() { var tcs = new DispatchingTaskCompletionSource <object>(); ThreadPool.QueueUserWorkItem(Receive, tcs); return(tcs.Task); }
public Task Start(IConnection connection, string connectionData, CancellationToken disconnectToken) { var tcs = new DispatchingTaskCompletionSource <object>(); // Resolve the transport ResolveTransport(connection, connectionData, disconnectToken, tcs, _startIndex); return(tcs.Task); }
private void Execute <T>(Func <IQuery, Task <T> > commandFunc, DispatchingTaskCompletionSource <T> tcs) { using (var session = SessionFactoryInfo.SessionFactory.OpenSession()) { var command = CreateCommand(session); commandFunc(command) .Then(result => tcs.SetResult(result)) .Catch(ex => tcs.SetUnwrappedException(ex), Trace); } }
// This method is being used to buld a callback with reflection private static void ContinueWith <T>(Task <T> task, DispatchingTaskCompletionSource <object> tcs) { if (task.IsCompleted) { // Fast path for tasks that completed synchronously ContinueSync <T>(task, tcs); } else { ContinueAsync <T>(task, tcs); } }
internal static Task <object> Incoming(IHubIncomingInvokerContext context) { var tcs = new DispatchingTaskCompletionSource <object>(); try { object result = context.MethodDescriptor.Invoker(context.Hub, context.Args.ToArray()); Type returnType = context.MethodDescriptor.ReturnType; if (typeof(Task).IsAssignableFrom(returnType)) { var task = (Task)result; if (!returnType.IsGenericType) { task.ContinueWith(tcs); } else { // Get the <T> in Task<T> Type resultType = returnType.GetGenericArguments().Single(); Type genericTaskType = typeof(Task <>).MakeGenericType(resultType); // Get the correct ContinueWith overload var parameter = Expression.Parameter(typeof(object)); // TODO: Cache this whole thing // Action<object> callback = result => ContinueWith((Task<T>)result, tcs); MethodInfo continueWithMethod = _continueWithMethod.MakeGenericMethod(resultType); Expression body = Expression.Call(continueWithMethod, Expression.Convert(parameter, genericTaskType), Expression.Constant(tcs)); var continueWithInvoker = Expression.Lambda <Action <object> >(body, parameter).Compile(); continueWithInvoker.Invoke(result); } } else { tcs.TrySetResult(result); } } catch (Exception ex) { tcs.TrySetUnwrappedException(ex); } return(tcs.Task); }
public TransportInitializationHandler(IHttpClient httpClient, IConnection connection, string connectionData, string transport, CancellationToken disconnectToken, TransportHelper transportHelper) { if (connection == null) { throw new ArgumentNullException("connection"); } _connection = connection; _httpClient = httpClient; _connectionData = connectionData; _transport = transport; _transportHelper = transportHelper; _initializationTask = new DispatchingTaskCompletionSource <object>(); _initializationInvoker = new ThreadSafeInvoker(); // Default event OnFailure = () => { }; // We want to fail if the disconnect token is tripped while we're waiting on initialization try { _tokenCleanup = disconnectToken.SafeRegister( _ => Fail(new OperationCanceledException(Resources.Error_ConnectionCancelled, disconnectToken)), state: null); } catch (ObjectDisposedException) { // We only dispose this token after cancelling it, so consider this cancellation. // The ODE is only thrown on .NET 4.5.2 and below (.NET 4.6 no longer throws ODE from CTS.Register) Fail(new OperationCanceledException(Resources.Error_ConnectionCancelled, disconnectToken)); } TaskAsyncHelper.Delay(connection.TotalTransportConnectTimeout) .Then(() => { // don't timeout once connect request has finished if (Interlocked.CompareExchange(ref _state, InitializationState.Failed, InitializationState.Initial) == InitializationState.Initial) { Fail(new TimeoutException(Resources.Error_TransportTimedOutTryingToConnect)); } }); }
private static void ContinueSync <T>(Task <T> task, DispatchingTaskCompletionSource <object> tcs) { if (task.IsFaulted) { tcs.TrySetUnwrappedException(task.Exception); } else if (task.IsCanceled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(task.Result); } }
private static void CompleteAsync <T>(DispatchingTaskCompletionSource <T> tcs, IAsyncResult ar, Func <IAsyncResult, T> end) { try { tcs.TrySetResult(end(ar)); } catch (OperationCanceledException) { tcs.TrySetCanceled(); } catch (Exception ex) { tcs.TrySetException(ex); } }
/// <summary> /// Sends messages to the backplane /// </summary> /// <param name="messages">The list of messages to send</param> /// <returns></returns> protected virtual Task Send(IList <Message> messages) { // If we're only using a single stream then just send if (StreamCount == 1) { return(StreamManager.Send(0, messages)); } var taskCompletionSource = new DispatchingTaskCompletionSource <object>(); // Group messages by source (connection id) var messagesBySource = messages.GroupBy(m => m.Source); SendImpl(messagesBySource.GetEnumerator(), taskCompletionSource); return(taskCompletionSource.Task); }
private static void ContinueAsync <T>(Task <T> task, DispatchingTaskCompletionSource <object> tcs) { task.ContinueWithPreservedCulture(t => { if (t.IsFaulted) { tcs.TrySetUnwrappedException(t.Exception); } else if (t.IsCanceled) { tcs.TrySetCanceled(); } else { tcs.TrySetResult(t.Result); } }); }
public virtual Task <int> ExecuteNonQueryAsync() { var tcs = new DispatchingTaskCompletionSource <int>(); return(new Task <int>(() => { int a; try { a = ExecuteNonQuery(); tcs.SetResult(a); return a; } catch (Exception ex) { tcs.SetUnwrappedException(ex); throw; } })); }
private void SendImpl(IEnumerator <IGrouping <string, Message> > enumerator, DispatchingTaskCompletionSource <object> taskCompletionSource) { send: if (!enumerator.MoveNext()) { taskCompletionSource.TrySetResult(null); } else { IGrouping <string, Message> group = enumerator.Current; // Get the channel index we're going to use for this message int index = (int)((uint)_sipHashBasedComparer.GetHashCode(group.Key) % StreamCount); Debug.Assert(index >= 0, "Hash function resulted in an index < 0."); Task sendTask = StreamManager.Send(index, group.ToArray()).Catch(_trace); if (sendTask.IsCompleted) { try { sendTask.Wait(); goto send; } catch (Exception ex) { taskCompletionSource.SetUnwrappedException(ex); } } else { sendTask.Then((enumer, tcs) => SendImpl(enumer, tcs), enumerator, taskCompletionSource) .ContinueWithNotComplete(taskCompletionSource); } } }
public Task <JSONNode> Invoke(string method, Action <JSONNode> onProgress, params object[] args) { if (method == null) { throw new ArgumentNullException("method"); } if (args == null) { throw new ArgumentNullException("args"); } JSONArray ArgsArray = new JSONArray(); for (int i = 0; i < args.Length; i++) { ArgsArray.Add(JSON.FromData(args[i])); } var tcs = new DispatchingTaskCompletionSource <JSONNode>(); var callbackId = _connection.RegisterCallback(result => { if (result != null) { if (result.Error != null) { if (result.IsHubException) { // A HubException was thrown tcs.TrySetException(new HubException(result.Error, result.ErrorData)); } else { tcs.TrySetException(new InvalidOperationException(result.Error)); } } else { try { if (result.State != null) { foreach (var pair in result.State) { this[pair.Key] = pair.Value; } } if (result.ProgressUpdate != null) { onProgress?.Invoke(result.ProgressUpdate.Data); } else if (result.Result != null) { tcs.TrySetResult(result.Result); } else { tcs.TrySetResult(new JSONNonexistent()); } } catch (Exception ex) { // If we failed to set the result for some reason or to update // state then just fail the tcs. tcs.TrySetUnwrappedException(ex); } } } else { tcs.TrySetCanceled(); } }); var hubData = new HubInvocation { Hub = _hubName, Method = method, Args = ArgsArray, CallbackId = callbackId }; if (_state.Count != 0) { hubData.State = _state; } var value = hubData.ToJson().Serialize(); _connection.Send(value).ContinueWith(task => { if (task.IsCanceled) { _connection.RemoveCallback(callbackId); tcs.TrySetCanceled(); } else if (task.IsFaulted) { _connection.RemoveCallback(callbackId); tcs.TrySetUnwrappedException(task.Exception); } }, TaskContinuationOptions.NotOnRanToCompletion); return(tcs.Task); }
private void ResolveTransport(IConnection connection, string data, CancellationToken disconnectToken, DispatchingTaskCompletionSource <object> tcs, int index) { // Pick the current transport IClientTransport transport = _transports[index]; transport.Start(connection, data, disconnectToken).ContinueWith(task => { if (task.IsFaulted || task.IsCanceled) { Exception ex; if (task.IsCanceled) { ex = new OperationCanceledException(Resources.Error_TaskCancelledException); } else { ex = task.Exception.GetBaseException(); } connection.Trace(TraceLevels.Events, "Auto: Failed to connect to using transport {0}. {1}", transport.Name, ex); // If that transport fails to initialize, then fallback. // If it is that /start request that failed, do not fallback. var next = index + 1; if (next < _transports.Count && !(ex is StartException)) { // Try the next transport ResolveTransport(connection, data, disconnectToken, tcs, next); } else { // If there's nothing else to try then just fail tcs.SetException(ex); } } else { // Set the active transport _transport = transport; // Complete the process tcs.SetResult(null); } }, TaskContinuationOptions.ExecuteSynchronously); }
public LifetimeContext(TransportDisconnectBase transport, DispatchingTaskCompletionSource <object> lifeTimetcs, Exception error) { _transport = transport; _lifetimeTcs = lifeTimetcs; _error = error; }
public Task <TResult> Invoke <TResult, TProgress>(string method, Action <TProgress> onProgress, params object[] args) { if (method == null) { throw new ArgumentNullException("method"); } if (args == null) { throw new ArgumentNullException("args"); } var tokenifiedArguments = new JToken[args.Length]; for (int i = 0; i < tokenifiedArguments.Length; i++) { tokenifiedArguments[i] = args[i] != null ? JToken.FromObject(args[i], JsonSerializer) : JValue.CreateNull(); } var tcs = new DispatchingTaskCompletionSource <TResult>(); var callbackId = _connection.RegisterCallback(result => { if (result != null) { if (result.Error != null) { if (result.IsHubException.HasValue && result.IsHubException.Value) { // A HubException was thrown tcs.TrySetException(new HubException(result.Error, result.ErrorData)); } else { tcs.TrySetException(new InvalidOperationException(result.Error)); } } else { try { if (result.State != null) { foreach (var pair in result.State) { this[pair.Key] = pair.Value; } } if (result.ProgressUpdate != null) { onProgress(result.ProgressUpdate.Data.ToObject <TProgress>(JsonSerializer)); } else if (result.Result != null) { tcs.TrySetResult(result.Result.ToObject <TResult>(JsonSerializer)); } else { tcs.TrySetResult(default(TResult)); } } catch (Exception ex) { // If we failed to set the result for some reason or to update // state then just fail the tcs. tcs.TrySetUnwrappedException(ex); } } } else { tcs.TrySetCanceled(); } }); var hubData = new HubInvocation { Hub = _hubName, Method = method, Args = tokenifiedArguments, CallbackId = callbackId }; if (_state.Count != 0) { hubData.State = _state; } var value = _connection.JsonSerializeObject(hubData); _connection.Send(value).ContinueWith(task => { if (task.IsCanceled) { _connection.RemoveCallback(callbackId); tcs.TrySetCanceled(); } else if (task.IsFaulted) { _connection.RemoveCallback(callbackId); tcs.TrySetUnwrappedException(task.Exception); } }, TaskContinuationOptions.NotOnRanToCompletion); return(tcs.Task); }
private void ResolveTransport( IConnection connection, string data, CancellationToken disconnectToken, DispatchingTaskCompletionSource <object> tcs, Exception lastError, int index) { IClientTransport transport = null; var next = index; // Pick the current transport while (next < _transports.Count && transport == null) { var candidateTransport = _transports[next++]; // If the current transport is WebSockets and it's not supported by the server, try the next transport. if (_tryWebSockets || !"webSockets".Equals(candidateTransport.Name, StringComparison.Ordinal)) { transport = candidateTransport; } } if (transport is null) { // If there's nothing else to try, then just fail with the error from the last transport. // For the lastError to be null, the AutoTransport must have been initialized with an empty transport list or only WebSockets. tcs.TrySetException(lastError ?? new Exception(Resources.Error_NoCompatibleTransportFound)); return; } transport.Start(connection, data, disconnectToken).ContinueWith(task => { if (task.IsFaulted || task.IsCanceled) { Exception ex; if (task.IsCanceled) { ex = new OperationCanceledException(Resources.Error_TaskCancelledException); } else { ex = task.Exception.GetBaseException(); } connection.Trace(TraceLevels.Events, "Auto: Failed to connect to using transport {0}. {1}", transport.Name, ex); // If that transport fails to initialize, then fallback. // If it is that /start request that failed, do not fallback. if (ex is StartException) { tcs.TrySetException(ex); } else { // Try the next transport ResolveTransport(connection, data, disconnectToken, tcs, ex, next); } } else { // Set the active transport _transport = transport; // Complete the process tcs.TrySetResult(null); } }, TaskContinuationOptions.ExecuteSynchronously); }