private async Task <InvocationResultDescriptor> ReadInvocationResultFromSocket <TReturnType>(WebSocket socket) { var message = await ReadMessageFromSocketAsync(socket); var pendingCalls = new Dictionary <string, InvocationRequest>(); pendingCalls.Add(_nextId.ToString(), new InvocationRequest(new CancellationToken(), typeof(TReturnType))); return(MessageSerializer.DeserializeInvocationResultDescriptor(message.Data, pendingCalls)); }
public async Task StartAsync(CancellationToken ct = default(CancellationToken)) { if (_hasStarted) { throw new MorseLException($"Cannot call {nameof(StartAsync)} more than once."); } _hasStarted = true; ct.Register(() => _connectionCts.TrySetCanceled(ct)); await Task.Run(async() => { var stopwatch = new Stopwatch(); stopwatch.Start(); await _clientWebSocket.ConnectAsync(new Uri(_uri), ct).ConfigureAwait(false); stopwatch.Stop(); _logger.LogDebug($"Connection to {_uri} established after {stopwatch.Elapsed.ToString("mm\\:ss\\.ff")}"); _receiveLoopTask = Receive(async stream => { _logger.LogTrace($"Received message stream - beginning processing"); var message = await MessageSerializer.DeserializeAsync <Message>(stream, Encoding.UTF8).ConfigureAwait(false); _logger.LogTrace($"Received \"{message}\""); switch (message.MessageType) { case MessageType.ConnectionEvent: _connectionCts.TrySetResult(null); ConnectionId = message.Data; Connected?.Invoke(); break; case MessageType.ClientMethodInvocation: InvocationDescriptor invocationDescriptor = null; try { invocationDescriptor = MessageSerializer.DeserializeInvocationDescriptor(message.Data, _handlers); } catch (Exception exception) { await HandleUnparseableReceivedInvocationDescriptor(message.Data, exception).ConfigureAwait(false); return; } if (invocationDescriptor == null) { // Valid JSON but unparseable into a known, typed invocation descriptor (unknown method name, invalid parameters) await HandleInvalidReceivedInvocationDescriptor(message.Data).ConfigureAwait(false); return; } await InvokeOn(invocationDescriptor).ConfigureAwait(false); break; case MessageType.InvocationResult: InvocationResultDescriptor resultDescriptor; try { resultDescriptor = MessageSerializer.DeserializeInvocationResultDescriptor(message.Data, _pendingCalls); } catch (Exception exception) { await HandleInvalidInvocationResultDescriptor(message.Data, exception).ConfigureAwait(false); return; } HandleInvokeResult(resultDescriptor); break; case MessageType.Error: await HandleErrorMessage(message).ConfigureAwait(false); break; } }, ct); _receiveLoopTask.ContinueWith(task => { if (task.IsFaulted) { Error?.Invoke(task.Exception); } }); }, ct).ConfigureAwait(false); var timeoutTask = Task.Delay(_options.ConnectionTimeout); await Task.WhenAny(_connectionCts.Task, timeoutTask).ConfigureAwait(false); if (!ct.IsCancellationRequested && !_connectionCts.Task.IsCompleted && timeoutTask.IsCompleted) { throw new TimeoutException($"Connection attempt to {_uri} timed out after {_options.ConnectionTimeout}"); } }