Example #1
0
        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);
            });
        }
Example #2
0
        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");
                });
 }
Example #6
0
 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;
 }
Example #8
0
 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);
 }
Example #9
0
        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);
        }
Example #12
0
 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);
 }
Example #14
0
 public override Task ProcessRequest(ITransportConnection connection)
 {
     if (IsAbortRequest)
     {
         return(connection.Abort(ConnectionId));
     }
     else
     {
         return(AcceptWebSocketRequest(connection));
     }
 }
Example #15
0
 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);
 }
Example #16
0
        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));
        }
Example #20
0
        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));
        }
Example #21
0
        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);
        }
Example #23
0
        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;
     }
 }
Example #25
0
        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();
                       });
        }
Example #29
0
 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());
         }
     });
 }
Example #30
0
        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);
        }
Example #31
0
        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));
            }
        }
Example #32
0
        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;
                }
Example #33
0
 public override Task ProcessRequest(ITransportConnection connection)
 {
     if (IsAbortRequest)
     {
         Context.Response.ContentType = "text/plain";
         return(connection.Abort(ConnectionId));
     }
     else
     {
         return(AcceptWebSocketRequest(socket =>
         {
             return ProcessRequestCore(connection);
         }));
     }
 }
Example #34
0
        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);
        }
Example #35
0
        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);
        }
Example #42
0
        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);
                });
            }
        }
Example #43
0
        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);
            });
        }
Example #49
0
        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();
            }
        }
Example #50
0
        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;
        }
Example #51
0
        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);
            }
        }
Example #52
0
 protected virtual Task InitializeResponse(ITransportConnection connection)
 {
     return TaskAsyncHelper.Empty;
 }
Example #53
0
 public virtual Task ProcessRequest(ITransportConnection connection)
 {
     return ProcessRequestCore(connection);
 }
Example #54
0
        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;
        }
Example #55
0
        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();
            }
        }
Example #56
0
        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 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);
 }
Example #58
0
        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;
        }
Example #60
0
        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);
        }