public override Task ProcessRequest(ITransportConnection connection) { return _context.Request.AcceptWebSocketRequest(socket => { _socket = socket; socket.OnClose = clean => { // If we performed a clean disconnect then we go through the normal disconnect routine. However, // If we performed an unclean disconnect we want to mark the connection as "not alive" and let the // HeartBeat clean it up. This is to maintain consistency across the transports. if (clean) { OnDisconnect(); } _isAlive = false; }; socket.OnMessage = message => { OnReceiving(message); if (Received != null) { Received(message).Catch(); } }; return ProcessRequestCore(connection); }); }
public override Task ProcessRequest(ITransportConnection connection) { if (IsAbortRequest) { return connection.Abort(ConnectionId); } else { var webSocketRequest = _context.Request as IWebSocketRequest; // Throw if the server implementation doesn't support websockets if (webSocketRequest == null) { throw new InvalidOperationException(Resources.Error_WebSocketsNotSupported); } Connection = connection; InitializePersistentState(); return webSocketRequest.AcceptWebSocketRequest(socket => { _socket = socket; socket.OnClose = _closed; socket.OnMessage = _message; socket.OnError = _error; return ProcessReceiveRequest(connection); }, InitializeTcs.Task); } }
public override Task ProcessRequest(ITransportConnection connection) { return _context.Request.AcceptWebSocketRequest(socket => { _socket = socket; socket.OnClose = () => { OnDisconnect(); _isAlive = false; }; socket.OnMessage = message => { OnReceiving(message); if (Received != null) { Received(message).Catch(); } }; return ProcessRequestCore(connection); }); }
public ConnectionRun(RunData runData) : base(runData) { var connectionManager = new ConnectionManager(Resolver); _context = connectionManager.GetConnectionContext<StressConnection>(); _transportConnection = (ITransportConnection)_context.Connection; }
protected override Task InitializeResponse(ITransportConnection connection) { return base.InitializeResponse(connection) .Then(() => { Context.Response.ContentType = "text/event-stream"; return Context.Response.WriteAsync("data: initialized\n\n"); }); }
protected override Task InitializeResponse(ITransportConnection connection) { return(base.InitializeResponse(connection) .Then(initScript => { Context.Response.ContentType = "text/html"; Context.Response.WriteAsync(initScript); }, _initPrefix + Context.Request.QueryString["frameId"] + _initSuffix)); }
public override void SetUp() { base.SetUp(); _websocket = null; _connection = null; _client = null; _fayeServerProcess = new ThinServerProcess(thinPort: THIN_SERVER_PORT, workingDirectory: WorkingDirectory); _socatInterceptor = null; }
protected override Task InitializeResponse(ITransportConnection connection) { return base.InitializeResponse(connection) .Then(initScript => { Context.Response.ContentType = "text/html"; Context.Response.WriteAsync(initScript); }, _initPrefix + Context.Request.QueryString["frameId"] + _initSuffix); }
private static void ReceiveLoop(ITransportConnection connection, string messageId) { connection.ReceiveAsync(messageId, CancellationToken.None, maxMessages: 5000).Then(r => { Interlocked.Add(ref _received, r.TotalCount); Interlocked.Add(ref _avgLastReceivedCount, r.TotalCount); ReceiveLoop(connection, r.MessageId); }); }
protected void SendConnect(string clientId, ITransportConnection connection) { var message = new ConnectRequestMessage(clientId: clientId, connectionType: ONLY_SUPPORTED_CONNECTION_TYPE, id: MessageCounter++); var json = Converter.Serialize(message); connection.Send(json); }
public static async ValueTask <ITransportChannel> CreateChannelAsync(this ITransportConnection connection) { var maybeChannel = await TryCreateChannelAsync(connection).ConfigureAwait(false); if (!maybeChannel.HasValue) { throw new OperationCanceledException(); } return(maybeChannel.Value); }
public static async Task CompleteAsync(this ITransportConnection connection) { connection.TryComplete(); do { while (connection.IncomingChannels.TryRead(out _)) { } } while (await connection.IncomingChannels.WaitReadAvailableAsync().ConfigureAwait(false)); await connection.Completion.ConfigureAwait(false); }
public static async Task CompleteAsync(this ITransportConnection connection) { connection.TryComplete(); while (await connection.IncomingChannels.WaitForNextSafeAsync().ConfigureAwait(false)) { while (connection.IncomingChannels.TryReadSafe(out _)) { } } await connection.Completion.ConfigureAwait(false); }
public override Task ProcessRequest(ITransportConnection connection) { if (IsAbortRequest) { return(connection.Abort(ConnectionId)); } else { return(AcceptWebSocketRequest(connection)); } }
public FayeClient(IWebSocket socket, string connectionId = "standard") : base(messageCounter: FIRST_MESSAGE_INDEX) { _connectionId = connectionId; _transportClient = new WebsocketTransportClient(socket, connectionId); _advice = DefaultAdvice; _transportConnection = null; _logger = LoggerFetcher.GetLogger(connectionId, this); }
public ClientConnection(ITransportConnection connection, ClientConnectionDescriptor clientInfo) { Id = connection.Id; _log = LogManager.GetLogger <ClientConnection>(Id.ToString()); Info = clientInfo; _connection = connection; var listen = new ProducingChannel <ITransportChannel>(1, ListenAsync); IncomingChannels = listen; Completion = TaskRunner.RunInBackground(ProcessAsync); }
public async Task Connection_dies_reestablishes_after_message_send() { // arrange const int inputPort = THIN_SERVER_PORT + 1; _fayeServerProcess.StartThinServer(); _socatInterceptor = StartWritableSocket(hostname: "localhost", inputPort: inputPort); const string urlThroughSocat = "ws://localhost:8133/bayeux"; var socket = new WebSocketClient(uri: urlThroughSocat); SetupWebSocket(socket); InstantiateTransportClient(); _connection = await _client.Connect(); var tcs = new TaskCompletionSource <string>(); _connection.MessageReceived += (sender, args) => tcs.SetResult(args.Message); var lostTcs = new TaskCompletionSource <bool>(); _connection.ConnectionLost += (sender, args) => lostTcs.SetResult(true); // act // ReSharper disable once CSharpWarnings::CS4014 Task.Factory.StartNew(() => { Logger.Info("Killing socat"); _socatInterceptor.Kill(); Logger.Info("Sleeping"); Thread.Sleep(5.Seconds()); Logger.Info("Restarting socat"); _socatInterceptor = StartWritableSocket(hostname: "localhost", inputPort: inputPort); }); Logger.Info("Waiting for websocket to acknowledge disconnect"); await lostTcs.Task.WithTimeout(t => t, 20.Seconds()); Logger.Info("Disconnect acknowledged, sending message"); _connection.Send(TestMessageStr); // assert var response = await tcs.Task.WithTimeout(s => s, 15.Seconds()); dynamic responseObj = JsonConvert.DeserializeObject <JArray>(response)[0]; bool successful = responseObj.successful; successful .Should() .BeTrue(); }
public async Task <AppConnectionDescriptor> AuthenticateAsync(ITransportConnection connection) { Log.Trace("Accepting new connection {0}", connection.Id); var channel = await connection.IncomingChannels.ReadAsync().ConfigureAwait(false); var frame = await channel.In.ReadAsync().ConfigureAwait(false); using (var payload = frame.Payload) using (var connectRequest = _serializer.DeserializeConnectRequest(payload)) { if (!_registryService.IsApplicationDefined(connectRequest.ApplicationId)) { throw new BrokerException($"Connection rejected because application id is unknown to broker: {connectRequest.ApplicationId}"); } if (!_connectionTracker.IsAppInstanceRegistered(connectRequest.ApplicationInstanceId)) { Log.Debug("Connection with unknown application instance id: " + $"ApplicationInstanceId={connectRequest.ApplicationInstanceId}, ApplicationId={connectRequest.ApplicationId}"); _connectionTracker.ReportConnectionError(new AppConnectionDescriptor( UniqueId.Empty, connectRequest.ApplicationId, connectRequest.ApplicationInstanceId, connection.TransportType)); if (_features.HasFlag(BrokerFeatures.CheckAppInstanceId)) { throw new BrokerException("Connection rejected because application instance id is unknown to broker: " + $"ApplicationInstanceId={connectRequest.ApplicationInstanceId}, ApplicationId={connectRequest.ApplicationId}"); } } using (var connectResponse = _messageFactory.CreateConnectResponse(connection.Id)) { var serializedResponse = _serializer.Serialize(connectResponse); try { Log.Trace("Sending connect response ({0} bytes): {1}", connectResponse, serializedResponse.Count); await channel.Out.WriteAsync(new TransportMessageFrame(serializedResponse)).ConfigureAwait(false); } catch { serializedResponse.Dispose(); throw; } channel.Out.TryComplete(); await channel.Completion.ConfigureAwait(false); return(new AppConnectionDescriptor( connectResponse.ConnectionId, connectRequest.ApplicationId, connectRequest.ApplicationInstanceId, connection.TransportType)); } } }
private Task ProcessConnectRequest(ITransportConnection connection) { HeartBeat.AddConnection(this); if (Connected != null) { // Return a task that completes when the connected event task & the receive loop task are both finished return(TaskAsyncHelper.Interleave(ProcessReceiveRequest, Connected, connection)); } return(ProcessReceiveRequest(connection)); }
private static Task SendCommand(ITransportConnection connection, string connectionId, CommandType commandType) { var command = new Command { CommandType = commandType }; var message = new ConnectionMessage(PrefixHelper.GetConnectionId(connectionId), command); return(connection.Send(message)); }
private void ProcessMessages(ITransportConnection connection, Func <Task> postReceive, Action endRequest) { IDisposable subscription = null; var wh = new ManualResetEventSlim(initialState: false); // End the request if the connection end token is triggered CancellationTokenRegistration registration = ConnectionEndToken.Register(() => { wh.Wait(); subscription.Dispose(); }); subscription = connection.Receive(LastMessageId, response => { // We need to wait until post receive has been called wh.Wait(); response.TimedOut = IsTimedOut; if (response.Disconnect || response.TimedOut || response.Aborted || ConnectionEndToken.IsCancellationRequested) { if (response.Aborted) { // If this was a clean disconnect raise the event. OnDisconnect(); } endRequest(); registration.Dispose(); subscription.Dispose(); return(TaskAsyncHelper.False); } else { return(Send(response).Then(() => TaskAsyncHelper.True)); } }, MaxMessages); if (postReceive != null) { postReceive().Catch(_allErrorsTotalCounter, _allErrorsPerSecCounter) .ContinueWith(task => wh.Set()); } else { wh.Set(); } }
private static Task SendCommand(ITransportConnection connection, string connectionId, CommandType commandType) { var command = new Command { CommandType = commandType }; var message = new ConnectionMessage(PrefixHelper.GetConnectionId(connectionId), command); return connection.Send(message); }
private void TransportLayer_OnConnectionClosed(ITransportConnection connection, ConnectionClosedReason reason) { if (connection.ConnectedTo != ServerId) { MelonLogger.LogError("Connection with non-server ID was closed - but we're a client???"); return; } ui.SetState(MultiplayerUIState.PreConnect); MelonLogger.LogError("Got P2P connection error " + reason.ToString()); Disconnect(); }
private async Task ProcessAsync(ITransportConnection connection) { try { await _buffer.Out.WriteAsync(connection).ConfigureAwait(false); } catch (Exception ex) { connection.TryTerminate(ex); throw; } }
private static void ReceiveLoop(CountdownEvent connectionCountDown, ITransportConnection connection, string messageId, CancellationToken cancellationToken) { if (cancellationToken.IsCancellationRequested) { connectionCountDown.Signal(); return; } connection.ReceiveAsync(messageId, cancellationToken, maxMessages: 5000).Then(r => { ReceiveLoop(connectionCountDown, connection, r.MessageId, cancellationToken); }); }
public async Task <IClientConnection> ConnectAsync(ClientOptions options, CancellationToken cancellationToken = default) { Log.Trace("Establishing new connection with broker"); ITransportConnection transportConnection = null; try { transportConnection = await options.Transport.CreateAsync(cancellationToken); Log.Debug("Connection {0} established. Performing handshake: {1}", transportConnection.Id, options); var channel = await transportConnection.CreateChannelAsync().ConfigureAwait(false); var protocolSerializer = options.Protocol.Serializer; using (var connectRequest = options.Protocol.MessageFactory.CreateConnectRequest(options.ApplicationId, options.ApplicationInstanceId)) { var serializedRequest = protocolSerializer.Serialize(connectRequest); try { await channel.Out.WriteAsync(new TransportMessageFrame(serializedRequest)).ConfigureAwait(false); channel.Out.TryComplete(); } catch { serializedRequest.Dispose(); throw; } } Log.Trace("Connection {0} receiving connection response.", transportConnection.Id); using (var serializedResponse = await channel.In.ReadAsync().ConfigureAwait(false)) using (var connectResponse = protocolSerializer.DeserializeConnectResponse(serializedResponse.Payload)) { await channel.Completion.ConfigureAwait(false); Log.Debug("Successfully authenticated: {0}", connectResponse); return(new ClientConnection(connectResponse.ConnectionId, transportConnection)); } } catch (Exception ex) { if (transportConnection != null) { Log.Error("Connection failed {0}", transportConnection); } else { Log.Warn(ex, "Connection failed"); } throw; } }
public async Task Expected_server_disconnect() { // arrange _fayeServerProcess.StartThinServer(); var socket = new WebSocketClient(uri: TEST_SERVER_URL); SetupWebSocket(socket); InstantiateTransportClient(); _connection = await _client.Connect(); var handshakeTcs = new TaskCompletionSource <string>(); MessageReceived handshakeHandler = (sender, args) => handshakeTcs.SetResult(args.Message); _connection.MessageReceived += handshakeHandler; _connection.Send(TestMessageStr); var response = await handshakeTcs.Task.WithTimeout(s => s, 5.Seconds()); dynamic responseObj = JsonConvert.DeserializeObject <JArray>(response)[0]; string clientId = responseObj.clientId; var triggerServerDisconnectMessage = new { channel = "/meta/disconnect", clientId }; var disconnectJson = JsonConvert.SerializeObject(triggerServerDisconnectMessage); var disconnectTcs = new TaskCompletionSource <string>(); MessageReceived disconnectHandler = (sender, args) => disconnectTcs.SetResult(args.Message); _connection.MessageReceived -= handshakeHandler; _connection.MessageReceived += disconnectHandler; var closedTcs = new TaskCompletionSource <bool>(); _connection.ConnectionClosed += (sender, args) => closedTcs.SetResult(true); // act _connection.NotifyOfPendingServerDisconnection(); _connection.Send(disconnectJson); await disconnectTcs.Task.WithTimeout(s => s, 10.Seconds()); await closedTcs.Task.WithTimeout(s => s, 10.Seconds()); // assert _connection .ConnectionState .Should() .Be(ConnectionState.Disconnected); }
protected override Task InitializeResponse(ITransportConnection connection) { return base.InitializeResponse(connection) .Then(() => { Context.Response.ContentType = "text/event-stream"; // "data: initialized\n\n" OutputWriter.WriteLine("data: initialized"); OutputWriter.WriteLine(); OutputWriter.WriteLine(); OutputWriter.Flush(); }); }
public Connection(ITransportConnection transportConnection, IProtocol protocol) { this.SessionID = Guid.NewGuid(); this.TransportConnection = transportConnection; this.Protocol = protocol; this.TransportConnection.Message += new EventHandler <TransportMessageEventArgs>(HandleMessage); this.TransportConnection.Closed += new EventHandler((o, e) => { if (this.Closed != null) { this.Closed(this, new EventArgs()); } }); }
private Task ProcessMessages(ITransportConnection connection, Func <Task> postReceive = null) { var tcs = new TaskCompletionSource <object>(); Action endRequest = () => { tcs.TrySetResult(null); CompleteRequest(); }; ProcessMessages(connection, postReceive, endRequest); return(tcs.Task); }
protected Task ProcessRequestCore(ITransportConnection connection) { Connection = connection; if (Context.Request.Url.LocalPath.EndsWith("/send", StringComparison.OrdinalIgnoreCase)) { return(ProcessSendRequest()); } else if (IsAbortRequest) { return(Connection.Abort(ConnectionId)); } else { InitializePersistentState(); if (IsConnectRequest) { if (Connected != null) { // Return a task that completes when the connected event task & the receive loop task are both finished bool newConnection = Heartbeat.AddConnection(this); // The connected callback Func <Task> connected = () => { if (newConnection) { return(Connected().Then(() => _counters.ConnectionsConnected.Increment())); } return(TaskAsyncHelper.Empty); }; return(TaskAsyncHelper.Interleave(ProcessReceiveRequestWithoutTracking, connected, connection, Completed)); } return(ProcessReceiveRequest(connection)); } if (Reconnected != null) { // Return a task that completes when the reconnected event task & the receive loop task are both finished Func <Task> reconnected = () => Reconnected().Then(() => _counters.ConnectionsReconnected.Increment()); return(TaskAsyncHelper.Interleave(ProcessReceiveRequest, reconnected, connection, Completed)); } return(ProcessReceiveRequest(connection)); } }
private void TransportLayer_OnMessageReceived(ITransportConnection connection, P2PMessage msg) { MessageType type = (MessageType)msg.ReadByte(); switch (type) { case MessageType.GunFireHit: { byte playerId = smallPlayerIds[connection.ConnectedTo]; if (playerObjects.ContainsKey(playerId)) { PlayerRep pr = playerObjects[playerId]; if (pr.rigTransforms.main != null) { GameObject instance = Instantiate(GunResources.HurtSFX, pr.rigTransforms.main); Destroy(instance, 3); } } GunFireHit gff = new GunFireHit() { playerId = playerId }; ServerSendToAllExcept(gff, MessageSendType.Unreliable, connection.ConnectedTo); break; } case MessageType.GunFire: { bool didHit; GunFireMessage gfm = new GunFireMessage(msg); Ray ray = new Ray(gfm.fireOrigin, gfm.fireDirection); if (Physics.Raycast(ray, out RaycastHit hit, int.MaxValue, ~0, QueryTriggerInteraction.Ignore)) { if (hit.transform.root.gameObject == BWUtil.RigManager) { MelonModLogger.Log("Hit BRETT!"); int random = UnityEngine.Random.Range(0, 10); BWUtil.LocalPlayerHealth.TAKEDAMAGE(gfm.bulletDamage, random == 0); GunFireHit gff = new GunFireHit(); ServerSendToAll(gff, MessageSendType.Reliable); } else { MelonModLogger.Log("Hit!"); } didHit = true; }
public override Task ProcessRequest(ITransportConnection connection) { if (IsAbortRequest) { Context.Response.ContentType = "text/plain"; return(connection.Abort(ConnectionId)); } else { return(AcceptWebSocketRequest(socket => { return ProcessRequestCore(connection); })); } }
public ITransportConnection OpenConnection(string host, int port, Context context, Action <Connection> onConnected) { if (port == -1 || host == null) { throw new Error(ErrorCode.CONNECTION_ERROR, "No port and/or IP address is present in configuration."); } ITransportConnection transportConnection = webSocketFactory.Construct("ws://" + host + ":" + port + "/"); transportConnection.Error += (sender, e) => { logger.Warn("Error in connection to " + host + ":" + port, e.Exception); }; transportConnection.Open(); return(transportConnection); }
private void TransportLayer_OnConnectionClosed(ITransportConnection connection, ConnectionClosedReason reason) { if (connection.ConnectedTo != ServerId) { MelonModLogger.LogError("Connection with non-server ID was closed - but we're a client???"); return; } ui.SetState(MultiplayerUIState.PreConnect); MelonModLogger.LogError("Got P2P connection error " + reason.ToString()); foreach (PlayerRep pr in playerObjects.Values) { pr.Destroy(); } }
private Task ProcessReceiveRequest(ITransportConnection connection) { Func <Task> initialize = null; // If this transport isn't replacing an existing transport, oldConnection will be null. ITrackingConnection oldConnection = Heartbeat.AddOrUpdateConnection(this); bool newConnection = oldConnection == null; if (IsConnectRequest) { if (_protocolResolver.SupportsDelayedStart(Context.Request)) { // TODO: Ensure delegate continues to use the C# Compiler static delegate caching optimization. initialize = () => connection.Initialize(ConnectionId); } else { Func <Task> connected; if (newConnection) { connected = Connected ?? _emptyTaskFunc; _counters.ConnectionsConnected.Increment(); } else { // Wait until the previous call to Connected completes. // We don't want to call Connected twice connected = () => oldConnection.ConnectTask; } initialize = () => { return(connected().Then((conn, id) => conn.Initialize(id), connection, ConnectionId)); }; } } else if (!SuppressReconnect) { initialize = Reconnected; _counters.ConnectionsReconnected.Increment(); } initialize = initialize ?? _emptyTaskFunc; Func <Task> fullInit = () => initialize().ContinueWith(_connectTcs); return(ProcessMessages(connection, fullInit)); }
private Task ProcessMessages(ITransportConnection connection, Func <Task> initialize) { var disposer = new Disposer(); if (BeforeCancellationTokenCallbackRegistered != null) { BeforeCancellationTokenCallbackRegistered(); } var cancelContext = new ForeverTransportContext(this, disposer); // Ensure delegate continues to use the C# Compiler static delegate caching optimization. _busRegistration = ConnectionEndToken.SafeRegister(state => Cancel(state), cancelContext); if (BeforeReceive != null) { BeforeReceive(); } try { // Ensure we enqueue the response initialization before any messages are received EnqueueOperation(state => InitializeResponse((ITransportConnection)state), connection) .Catch((ex, state) => ((ForeverTransport)state).OnError(ex), this, Logger); // Ensure delegate continues to use the C# Compiler static delegate caching optimization. IDisposable subscription = connection.Receive(LastMessageId, (response, state) => ((ForeverTransport)state).OnMessageReceived(response), MaxMessages, this); if (AfterReceive != null) { AfterReceive(); } // Ensure delegate continues to use the C# Compiler static delegate caching optimization. initialize().Catch((ex, state) => ((ForeverTransport)state).OnError(ex), this, Logger) .Finally(state => ((SubscriptionDisposerContext)state).Set(), new SubscriptionDisposerContext(disposer, subscription)); } catch (Exception ex) { _transportLifetime.Complete(ex); } return(_requestLifeTime.Task); }
protected override Task InitializeResponse(ITransportConnection connection) { return(base.InitializeResponse(connection) .Then(() => { Context.Response.ContentType = "text/event-stream"; // "data: initialized\n\n" OutputWriter.Write("data: initialized"); OutputWriter.WriteLine(); OutputWriter.WriteLine(); OutputWriter.Flush(); return Context.Response.FlushAsync(); })); }
protected override Task InitializeResponse(ITransportConnection connection) { return base.InitializeResponse(connection) .Then(initScript => { Context.Response.ContentType = "text/html"; return EnqueueOperation(() => { OutputWriter.Write(initScript); OutputWriter.Flush(); return Context.Response.FlushAsync(); }); }, _initPrefix + Context.Request.QueryString["frameId"] + _initSuffix); }
protected async Task ProcessRequestCore(ITransportConnection connection) { Connection = connection; if (IsSendRequest) { await ProcessSendRequest().PreserveCulture(); } else if (IsAbortRequest) { await Connection.Abort(ConnectionId).PreserveCulture(); } else { await InitializePersistentState().PreserveCulture(); await ProcessReceiveRequest(connection).PreserveCulture(); } }
protected internal override Task InitializeResponse(ITransportConnection connection) { uint frameId; string rawFrameId = Context.Request.QueryString["frameId"]; if (String.IsNullOrWhiteSpace(rawFrameId) || !UInt32.TryParse(rawFrameId, NumberStyles.None, CultureInfo.InvariantCulture, out frameId)) { // Invalid frameId passed in throw new InvalidOperationException(Resources.Error_InvalidForeverFrameId); } string initScript = _initPrefix + frameId.ToString(CultureInfo.InvariantCulture) + _initSuffix; var context = new ForeverFrameTransportContext(this, initScript); // Ensure delegate continues to use the C# Compiler static delegate caching optimization. return base.InitializeResponse(connection).Then(s => Initialize(s), context); }
public override Task ProcessRequest(ITransportConnection connection) { if (IsAbortRequest) { return connection.Abort(ConnectionId); } else { return AcceptWebSocketRequest(socket => { _socket = socket; socket.OnClose = _closed; socket.OnMessage = _message; socket.OnError = _error; return ProcessRequestCore(connection); }); } }
public override Task ProcessRequest(ITransportConnection connection) { var webSocketRequest = _context.Request as IWebSocketRequest; // Throw if the server implementation doesn't support websockets if (webSocketRequest == null) { throw new InvalidOperationException(Resources.Error_WebSocketsNotSupported); } return webSocketRequest.AcceptWebSocketRequest(socket => { _socket = socket; socket.OnClose = clean => { Trace.TraceInformation("CloseSocket({0}, {1})", clean, ConnectionId); // If we performed a clean disconnect then we go through the normal disconnect routine. However, // If we performed an unclean disconnect we want to mark the connection as "not alive" and let the // HeartBeat clean it up. This is to maintain consistency across the transports. if (clean) { OnDisconnect(); } _isAlive = false; }; socket.OnMessage = message => { if (Received != null) { Received(message).Catch(); } }; return ProcessRequestCore(connection); }); }
private Task ProcessReceiveRequestWithoutTracking(ITransportConnection connection, Func<Task> postReceive = null) { if (TransportConnected != null) { TransportConnected().Catch(); } // Receive() will async wait until a message arrives then return var receiveTask = IsConnectRequest ? connection.Receive(null, ConnectionEndToken, MaxMessages) : connection.Receive(MessageId, ConnectionEndToken, MaxMessages); return TaskAsyncHelper.Series(() => { if (postReceive != null) { return postReceive(); } return TaskAsyncHelper.Empty; }, () => { return receiveTask.Then(response => { response.TimedOut = IsTimedOut; if (response.Aborted) { // If this was a clean disconnect then raise the event OnDisconnect(); } return Send(response); }); }); }
private Task ProcessReceiveRequest(ITransportConnection connection, Func<Task> postReceive = null) { Heartbeat.AddConnection(this); return ProcessReceiveRequestWithoutTracking(connection, postReceive); }
private Task ProcessConnectRequest(ITransportConnection connection) { if (Connected != null) { bool newConnection = Heartbeat.AddConnection(this); // Return a task that completes when the connected event task & the receive loop task are both finished return TaskAsyncHelper.Interleave(ProcessReceiveRequestWithoutTracking, () => { if (newConnection) { return Connected().Then(() => _counters.ConnectionsConnected.Increment()); } return TaskAsyncHelper.Empty; }, connection, Completed); } return ProcessReceiveRequest(connection); }
public Task ProcessRequest(ITransportConnection connection) { Connection = connection; if (IsSendRequest) { return ProcessSendRequest(); } else if (IsAbortRequest) { return Connection.Abort(ConnectionId); } else { InitializePersistentState(); Task task = null; if (IsConnectRequest) { task = ProcessConnectRequest(connection); } else if (MessageId != null) { if (IsReconnectRequest && Reconnected != null) { // Return a task that completes when the reconnected event task & the receive loop task are both finished Func<Task> reconnected = () => Reconnected().Then(() => _counters.ConnectionsReconnected.Increment()); task = TaskAsyncHelper.Interleave(ProcessReceiveRequest, reconnected, connection, Completed); } else { task = ProcessReceiveRequest(connection); } } if (task != null) { // Mark the request as completed once it's done return task.Finally(() => CompleteRequest()); } } return null; }
private Task ProcessReceiveRequestWithoutTracking(ITransportConnection connection, Action postReceive = null) { if (TransportConnected != null) { TransportConnected().Catch(); } // ReceiveAsync() will async wait until a message arrives then return var receiveTask = IsConnectRequest ? connection.ReceiveAsync(null, ConnectionEndToken, MessageBufferSize) : connection.ReceiveAsync(MessageId, ConnectionEndToken, MessageBufferSize); if (postReceive != null) { postReceive(); } return receiveTask.Then(response => { response.TimedOut = IsTimedOut; if (response.Aborted) { // If this was a clean disconnect then raise the event OnDisconnect(); } return Send(response); }); }
private void ProcessMessages(ITransportConnection connection, Func<Task> postReceive, Action<Exception> endRequest) { IDisposable subscription = null; var wh = new ManualResetEventSlim(initialState: false); var registration = default(CancellationTokenRegistration); bool disposeSubscriptionImmediately = false; try { // End the request if the connection end token is triggered registration = ConnectionEndToken.Register(() => { wh.Wait(); // This is only null if we failed to create the subscription if (subscription != null) { subscription.Dispose(); } }); } catch (ObjectDisposedException) { // If we've ended the connection before we got a chance to register the connection // then dispose the subscription immediately disposeSubscriptionImmediately = true; } try { subscription = connection.Receive(LastMessageId, response => { // We need to wait until post receive has been called wh.Wait(); response.TimedOut = IsTimedOut; // If we're telling the client to disconnect then clean up the instantiated connection. if (response.Disconnect) { // Send the response before removing any connection data return Send(response).Then(() => { // Remove connection without triggering disconnect HeartBeat.RemoveConnection(this); endRequest(null); // Dispose everything registration.Dispose(); subscription.Dispose(); return TaskAsyncHelper.False; }); } else if (response.TimedOut || response.Aborted || ConnectionEndToken.IsCancellationRequested) { if (response.Aborted) { // If this was a clean disconnect raise the event. OnDisconnect(); } endRequest(null); // Dispose everything registration.Dispose(); subscription.Dispose(); return TaskAsyncHelper.False; } else { return Send(response).Then(() => TaskAsyncHelper.True); } }, MaxMessages); } catch (Exception ex) { endRequest(ex); wh.Set(); registration.Dispose(); return; } if (postReceive != null) { postReceive().Catch(_counters.ErrorsAllTotal, _counters.ErrorsAllPerSec) .Catch(ex => endRequest(ex)) .ContinueWith(task => wh.Set()); } else { wh.Set(); } if (disposeSubscriptionImmediately) { subscription.Dispose(); } }
private Task ProcessMessages(ITransportConnection connection, Func<Task> postReceive = null) { var tcs = new TaskCompletionSource<object>(); Action<Exception> endRequest = (ex) => { if (ex != null) { tcs.TrySetException(ex); } else { tcs.TrySetResult(null); } CompleteRequest(); }; ProcessMessages(connection, postReceive, endRequest); return tcs.Task; }
protected Task ProcessRequestCore(ITransportConnection connection) { Connection = connection; if (Context.Request.Url.LocalPath.EndsWith("/send")) { return ProcessSendRequest(); } else if (IsAbortRequest) { return Connection.Abort(ConnectionId); } else { InitializePersistentState(); if (IsConnectRequest) { if (Connected != null) { // Return a task that completes when the connected event task & the receive loop task are both finished bool newConnection = HeartBeat.AddConnection(this); return TaskAsyncHelper.Interleave(ProcessReceiveRequestWithoutTracking, () => { if (newConnection) { return Connected().Then(() => _counters.ConnectionsConnected.Increment()); } return TaskAsyncHelper.Empty; } , connection, Completed); } return ProcessReceiveRequest(connection); } if (Reconnected != null) { // Return a task that completes when the reconnected event task & the receive loop task are both finished Func<Task> reconnected = () => Reconnected().Then(() => _counters.ConnectionsReconnected.Increment()); return TaskAsyncHelper.Interleave(ProcessReceiveRequest, reconnected, connection, Completed); } return ProcessReceiveRequest(connection); } }
protected virtual Task InitializeResponse(ITransportConnection connection) { return TaskAsyncHelper.Empty; }
public virtual Task ProcessRequest(ITransportConnection connection) { return ProcessRequestCore(connection); }
private Task ProcessMessages(ITransportConnection connection, Action postReceive = null) { var tcs = new TaskCompletionSource<object>(); Action endRequest = () => { tcs.TrySetResult(null); CompleteRequest(); }; ProcessMessages(connection, postReceive, endRequest); return tcs.Task; }
private void ProcessMessages(ITransportConnection connection, Action postReceive, Action endRequest) { IDisposable subscription = null; // End the request if the connection end token is triggered ConnectionEndToken.Register(() => { if (subscription != null) { subscription.Dispose(); } }); subscription = connection.Receive(LastMessageId, response => { response.TimedOut = IsTimedOut; if (response.Disconnect || response.TimedOut || response.Aborted || ConnectionEndToken.IsCancellationRequested) { if (response.Aborted) { // If this was a clean disconnect raise the event. OnDisconnect(); } endRequest(); return TaskAsyncHelper.False; } else { return Send(response).Then(() => TaskAsyncHelper.True); } }, MessageBufferSize); if (postReceive != null) { postReceive(); } }
protected internal override Task InitializeResponse(ITransportConnection connection) { // Ensure delegate continues to use the C# Compiler static delegate caching optimization. return base.InitializeResponse(connection) .Then(s => WriteInit(s), this); }
private Task ProcessReceiveRequestWithoutTracking(ITransportConnection connection, Action postReceive = null) { Func<Task> afterReceive = () => { if (TransportConnected != null) { TransportConnected().Catch(_counters.ErrorsAllTotal, _counters.ErrorsAllPerSec); } if (postReceive != null) { try { postReceive(); } catch (Exception ex) { return TaskAsyncHelper.FromError(ex); } } return InitializeResponse(connection); }; return ProcessMessages(connection, afterReceive); }
public Task ProcessRequest(ITransportConnection connection) { Connection = connection; if (IsSendRequest) { return ProcessSendRequest(); } else if (IsAbortRequest) { return Connection.Abort(ConnectionId); } else { if (IsConnectRequest) { return ProcessConnectRequest(connection); } else if (MessageId != null) { if (IsReconnectRequest && Reconnected != null) { // Return a task that completes when the reconnected event task & the receive loop task are both finished return TaskAsyncHelper.Interleave(ProcessReceiveRequest, Reconnected, connection, Completed); } return ProcessReceiveRequest(connection); } } return null; }
private Task ProcessReceiveRequestWithoutTracking(ITransportConnection connection, Action postReceive = null) { Action afterReceive = () => { if (TransportConnected != null) { TransportConnected().Catch(); } if (postReceive != null) { postReceive(); } InitializeResponse(connection).Catch(); }; return ProcessMessages(connection, afterReceive); }