/// <summary>
        /// Opens the <see cref="StreamingConnection"/> and listens for incoming requests, which will
        /// be assembled and sent to the provided <see cref="RequestHandler"/>.
        /// </summary>
        /// <param name="requestHandler"><see cref="RequestHandler"/> to which incoming requests will be sent.</param>
        /// <param name="cancellationToken"><see cref="CancellationToken"/> that signals the need to stop the connection.
        /// Once the token is cancelled, the connection will be gracefully shut down, finishing pending sends and receives.</param>
        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
        public virtual async Task ListenAsync(RequestHandler requestHandler, CancellationToken cancellationToken = default)
        {
            if (requestHandler == null)
            {
                throw new ArgumentNullException(nameof(requestHandler));
            }

            var duplexPipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

            // Create transport and application
            _transport = CreateStreamingTransport(duplexPipePair.Application);
            var application = new TransportHandler(duplexPipePair.Transport, Logger);

            // Create session
            _session = new StreamingSession(requestHandler, application, Logger, cancellationToken);

            // Start transport and application
            var transportTask   = _transport.ConnectAsync(cancellationToken);
            var applicationTask = application.ListenAsync(cancellationToken);

            var tasks = new List <Task> {
                transportTask, applicationTask
            };

            // Signal that session is ready to be used
            _sessionInitializedTask.SetResult(true);

            // Let application and transport run
            await Task.WhenAll(tasks).ConfigureAwait(false);
        }
Ejemplo n.º 2
0
        private async Task ListenImplAsync(Func <WebSocketTransport, Task> socketConnectFunc, RequestHandler requestHandler, CancellationToken cancellationToken = default(CancellationToken))
        {
            var duplexPipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

            // Create transport and application
            var transport   = new WebSocketTransport(duplexPipePair.Application, _logger);
            var application = new TransportHandler(duplexPipePair.Transport, _logger);

            // Create session
            _session = new StreamingSession(requestHandler, application, _logger, cancellationToken);

            // Start transport and application
            var transportTask   = socketConnectFunc(transport);
            var applicationTask = application.ListenAsync(cancellationToken);

            var tasks = new List <Task>()
            {
                transportTask, applicationTask
            };

            // Signal that session is ready to be used
            _sessionInitializedTask.SetResult(true);

            // Let application and transport run
            await Task.WhenAll(tasks).ConfigureAwait(false);
        }
Ejemplo n.º 3
0
        public void StreamingSession_Receivestream_ParameterValidation(Header header, byte[] payload, Type exceptionType)
        {
            // Arrange
            var transportHandler = new Mock <TransportHandler>(new Mock <IDuplexPipe>().Object, NullLogger.Instance);
            var session          = new StreamingSession(new Mock <RequestHandler>().Object, transportHandler.Object, NullLogger.Instance);

            // Act + Assert
            Assert.Throws(exceptionType, () => session.ReceiveStream(header, new ArraySegment <byte>(payload)));
        }
Ejemplo n.º 4
0
        public void StreamingSession_ReceiveResponse_ParameterValidation(Header header, ReceiveResponse response, Type exceptionType)
        {
            // Arrange
            var transportHandler = new Mock <TransportHandler>(new Mock <IDuplexPipe>().Object, NullLogger.Instance);
            var session          = new StreamingSession(new Mock <RequestHandler>().Object, transportHandler.Object, NullLogger.Instance);

            // Act + Assert
            Assert.Throws(exceptionType, () => session.ReceiveResponse(header, response));
        }
Ejemplo n.º 5
0
        public async Task StreamingSession_SendResponse_ParameterValidation(Header header, StreamingResponse response, Type exceptionType)
        {
            // Arrange
            var transportHandler = new Mock <TransportHandler>(new Mock <IDuplexPipe>().Object, NullLogger.Instance);
            var session          = new StreamingSession(new Mock <RequestHandler>().Object, transportHandler.Object, NullLogger.Instance);

            // Act + Assert
            await Assert.ThrowsAsync(exceptionType, () => session.SendResponseAsync(header, response, CancellationToken.None));
        }
Ejemplo n.º 6
0
        public async Task StreamingSession_SendRequest_ParameterValidation()
        {
            // Arrange
            var transportHandler = new Mock <TransportHandler>(new Mock <IDuplexPipe>().Object, NullLogger.Instance);
            var session          = new StreamingSession(new Mock <RequestHandler>().Object, transportHandler.Object, NullLogger.Instance);

            // Act + Assert
            await Assert.ThrowsAsync <ArgumentNullException>(() => session.SendRequestAsync(null, CancellationToken.None));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Starts or continues previous media straiming session.
        /// </summary>
        /// <param name="userId">User identifier</param>
        /// <param name="ip">Ip address</param>
        /// <returns>Streaming session info object, containing playing media and milliseconds playing at.</returns>
        public SessionInfo StartSession(Guid userId, string ip)
        {
            var session = (from ss in _dataContext.Get <StreamingSession>()
                           where ss.UserId == userId
                           select ss).FirstOrDefault();

            if (session == null)
            {
                session = new StreamingSession
                {
                    DateStarted   = DateTime.UtcNow,
                    IsActive      = true,
                    StateInfoJson = string.Empty,
                    UserId        = userId,
                    UserIp        = ip
                };

                _dataContext.Add(session);
                _dataContext.SaveChanges();
            }
            else
            if (!session.IsActive)
            {
                session.IsActive     = true;
                session.DateStarted  = DateTime.UtcNow;
                session.DateFinished = null;

                _dataContext.Update(session);
                _dataContext.SaveChanges();
            }

            return(new SessionInfo
            {
                SessionKey = session.Id.ToString(),
                PlayingMediaId = session.PlayingMediaId?.ToString() ?? string.Empty,
                PlayingAtMSec = (session.PlayingMediaId.HasValue ? session.PlayingAtMSec : 0)
            });
        }
        public async Task Get2()
        {
            Response.StatusCode  = 206;
            Response.ContentType = "multipart/x-mixed-replace; boundary=frame";
            Response.Headers.Add("Connection", "Keep-Alive");


            StreamingSession session = this.cam.StreamOn(data =>
            {
                if (Request.HttpContext.RequestAborted.IsCancellationRequested)
                {
                    throw new Exception();
                }

                Response.Body.Write(this.CreateHeader(data.Length));
                Response.Body.Write(data);
                Response.Body.Write(this.CreateFooter());
                Response.Body.Flush();
            });

            await Response.StartAsync();

            await session.WaitAsync();
        }
Ejemplo n.º 9
0
        internal async Task ConnectInternalAsync(Func <WebSocketTransport, Task> connectFunc, CancellationToken cancellationToken)
        {
            CheckDisposed();

            TimerAwaitable timer     = null;
            Task           timerTask = null;

            try
            {
                // Pipes
                _duplexPipePair = DuplexPipe.CreateConnectionPair(PipeOptions.Default, PipeOptions.Default);

                // Transport
                var transport = new WebSocketTransport(_duplexPipePair.Application, _logger);

                // Application
                _transportHandler = new TransportHandler(_duplexPipePair.Transport, _logger);

                // Session
                _session = new StreamingSession(_requestHandler, _transportHandler, _logger, cancellationToken);

                // Set up cancellation
                _disconnectCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);

                // Start transport and application
                var transportTask   = connectFunc(transport);
                var applicationTask = _transportHandler.ListenAsync(_disconnectCts.Token);
                var combinedTask    = Task.WhenAll(transportTask, applicationTask);

                Log.ClientStarted(_logger, _url ?? string.Empty);

                // Periodic task: keep alive
                // Disposed with `timer.Stop()` in the finally block below
                if (_keepAlive.HasValue)
                {
                    timer     = new TimerAwaitable(_keepAlive.Value, _keepAlive.Value);
                    timerTask = TimerLoopAsync(timer);
                }

                // We are connected!
                IsConnected = true;

                // Block until transport or application ends.
                await combinedTask.ConfigureAwait(false);

                // Signal that we're done
                _disconnectCts.Cancel();
                Log.ClientTransportApplicationCompleted(_logger, _url);
            }
            finally
            {
                timer?.Stop();

                if (timerTask != null)
                {
                    await timerTask.ConfigureAwait(false);
                }
            }

            Log.ClientCompleted(_logger, _url ?? string.Empty);
        }
Ejemplo n.º 10
0
        public async Task StreamingSession_SendRequest_ReceiveResponse(int streamLength, int streamCount, int chunkCount)
        {
            // Arrange
            var request = new StreamingRequest()
            {
                Verb    = "GET",
                Path    = "api/version",
                Streams = new List <ResponseMessageStream>()
            };

            request.AddStream(new StringContent("Hello human, I'm Bender!"));

            var requestHandler = new Mock <RequestHandler>();

            var requestCompletionSource = new TaskCompletionSource <bool>();

            requestHandler
            .Setup(r => r.ProcessRequestAsync(It.IsAny <ReceiveRequest>(), null, null, CancellationToken.None))
            .ReturnsAsync(() => new StreamingResponse()
            {
                StatusCode = 200
            })
            .Callback(() => requestCompletionSource.SetResult(true));

            var transportHandler = new Mock <TransportHandler>(new Mock <IDuplexPipe>().Object, NullLogger.Instance);

            var responseCompletionSource = new TaskCompletionSource <bool>();

            var transportHandlerSetup = transportHandler.Setup(t => t.SendRequestAsync(It.IsAny <Guid>(), It.IsAny <RequestModel>(), CancellationToken.None));

            var session = new StreamingSession(requestHandler.Object, transportHandler.Object, NullLogger.Instance);

            Header          responseHeader = null;
            ReceiveResponse response       = null;

            transportHandlerSetup.Callback(
                (Guid requestId, RequestModel requestPayload, CancellationToken cancellationToken) =>
            {
                responseHeader = new Header()
                {
                    Id = requestId, Type = PayloadTypes.Response
                };
                response = new ReceiveResponse()
                {
                    StatusCode = 200, Streams = StreamingDataGenerator.CreateStreams(requestId, streamLength, streamCount, chunkCount, PayloadTypes.Response)
                };

                session.ReceiveResponse(responseHeader, response);

                foreach (AugmentedStreamDefinition definition in response.Streams)
                {
                    var chunkList = definition.Chunks;

                    for (int i = 0; i < chunkCount; i++)
                    {
                        bool isLast = i == chunkCount - 1;

                        session.ReceiveStream(
                            new Header()
                        {
                            End = isLast, Id = definition.Id, PayloadLength = chunkList[i].Length, Type = PayloadTypes.Stream
                        },
                            chunkList[i]);
                    }
                }
            });

            // Act

            var responseTask        = session.SendRequestAsync(request, CancellationToken.None);
            var responseWithTimeout = await Task.WhenAny(responseTask, Task.Delay(TimeSpan.FromSeconds(5)));

            // Assert
            Assert.Equal(responseTask, responseWithTimeout);

            var receivedResponse = await responseTask;

            Assert.Equal(response.StatusCode, receivedResponse.StatusCode);
            Assert.Equal(response.Streams.Count, receivedResponse.Streams.Count);

            Assert.True(response.Streams.SequenceEqual(receivedResponse.Streams));
        }
Ejemplo n.º 11
0
        public async Task StreamingSession_RequestWithStreams_SentToHandler(int streamLength, int streamCount, int chunkCount)
        {
            // Arrange
            var requestId = Guid.NewGuid();

            var request = new ReceiveRequest()
            {
                Verb    = "GET",
                Path    = "api/version",
                Streams = new List <IContentStream>()
            };

            request.Streams = StreamingDataGenerator.CreateStreams(requestId, streamLength, streamCount, chunkCount);

            var requestHandler = new Mock <RequestHandler>();

            var requestCompletionSource = new TaskCompletionSource <bool>();

            requestHandler
            .Setup(r => r.ProcessRequestAsync(It.IsAny <ReceiveRequest>(), null, null, CancellationToken.None))
            .ReturnsAsync(() => new StreamingResponse()
            {
                StatusCode = 200
            })
            .Callback(() => requestCompletionSource.SetResult(true));

            var transportHandler = new Mock <TransportHandler>(new Mock <IDuplexPipe>().Object, NullLogger.Instance);

            var responseCompletionSource = new TaskCompletionSource <bool>();

            transportHandler
            .Setup(t => t.SendResponseAsync(It.IsAny <Guid>(), It.Is <ResponseModel>(r => r.StatusCode == 200), CancellationToken.None))
            .Callback(() => responseCompletionSource.SetResult(true));

            // Act
            var session = new StreamingSession(requestHandler.Object, transportHandler.Object, NullLogger.Instance);

            session.ReceiveRequest(new Header()
            {
                Id = requestId, Type = PayloadTypes.Request
            }, request);

            foreach (AugmentedStreamDefinition definition in request.Streams)
            {
                var chunkList = definition.Chunks;

                for (int i = 0; i < chunkList.Count; i++)
                {
                    bool isLast = i == chunkList.Count - 1;

                    session.ReceiveStream(
                        new Header()
                    {
                        End = isLast, Id = definition.Id, PayloadLength = chunkList[i].Length, Type = PayloadTypes.Stream
                    },
                        chunkList[i]);
                }
            }

            var roundtripTask = Task.WhenAll(requestCompletionSource.Task, responseCompletionSource.Task);
            var result        = await Task.WhenAny(roundtripTask, Task.Delay(TimeSpan.FromSeconds(5)));

            // Assert
            Assert.Equal(result, roundtripTask);
        }