Ejemplo n.º 1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="ConnectionMonitor"/> class.
        /// </summary>
        /// <param name="endpoints">The collection that contains all the known endpoints.</param>
        /// <param name="verifyConnectionTo">The function that is used to verify connections with remote endpoints.</param>
        /// <param name="timer">The timer which is used to signal the next keep-alive moment.</param>
        /// <param name="now">The function that is used to get the current time and date.</param>
        /// <param name="configuration">The object that stores the configuration for the application.</param>
        /// <param name="keepAliveCustomDataBuilder">The function that is used to provide custom data for the connect message.</param>
        /// <param name="keepAliveResponseDataHandler">The function that is used to return the custom data from a response connect message.</param>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="endpoints"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="verifyConnectionTo"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="timer"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="now"/> is <see langword="null" />.
        /// </exception>
        /// <exception cref="ArgumentNullException">
        ///     Thrown if <paramref name="configuration"/> is <see langword="null" />.
        /// </exception>
        public ConnectionMonitor(
            IStoreInformationAboutEndpoints endpoints,
            VerifyEndpointConnectionStatusWithCustomData verifyConnectionTo,
            ITimer timer,
            Func <DateTimeOffset> now,
            IConfiguration configuration,
            KeepAliveCustomDataBuilder keepAliveCustomDataBuilder     = null,
            KeepAliveResponseDataHandler keepAliveResponseDataHandler = null)
        {
            {
                Lokad.Enforce.Argument(() => endpoints);
                Lokad.Enforce.Argument(() => verifyConnectionTo);
                Lokad.Enforce.Argument(() => timer);
                Lokad.Enforce.Argument(() => now);
                Lokad.Enforce.Argument(() => configuration);
            }

            m_VerifyConnectionTo = verifyConnectionTo;
            m_Now = now;
            m_KeepAliveCustomDataBuilder   = keepAliveCustomDataBuilder;
            m_KeepAliveResponseDataHandler = keepAliveResponseDataHandler;

            m_MaximumNumberOfMissedKeepAliveSignals = configuration.HasValueFor(
                CommunicationConfigurationKeys.MaximumNumberOfMissedConnectionConfirmations)
                ? configuration.Value <int>(CommunicationConfigurationKeys.MaximumNumberOfMissedConnectionConfirmations)
                : CommunicationConstants.DefaultMaximumNumberOfMissedKeepAliveSignals;

            m_MaximumTimeBetweenConnectionConfirmations = configuration.HasValueFor(
                CommunicationConfigurationKeys.MaximumTimeInMillisecondsBetweenConnectionConfirmations)
                ? TimeSpan.FromMilliseconds(
                configuration.Value <int>(CommunicationConfigurationKeys.MaximumTimeInMillisecondsBetweenConnectionConfirmations))
                : TimeSpan.FromMilliseconds(CommunicationConstants.DefaultMaximumTimeInMillisecondsBetweenConnectionConfirmations);

            m_MessageSendTimeout = configuration.HasValueFor(CommunicationConfigurationKeys.WaitForResponseTimeoutInMilliSeconds)
                ? TimeSpan.FromMilliseconds(configuration.Value <int>(CommunicationConfigurationKeys.WaitForResponseTimeoutInMilliSeconds))
                : TimeSpan.FromMilliseconds(CommunicationConstants.DefaultWaitForResponseTimeoutInMilliSeconds);

            m_Endpoints = endpoints;
            m_Endpoints.OnEndpointConnected    += HandleOnEndpointConnected;
            m_Endpoints.OnEndpointDisconnected += HandleOnEndpointDisconnected;

            m_Timer            = timer;
            m_Timer.OnElapsed += HandleKeepAliveIntervalOnElapsed;
        }
Ejemplo n.º 2
0
        private static void RegisterConnectionVerificationFunctions(ContainerBuilder builder)
        {
            builder.Register(
                c =>
            {
                var layer = c.Resolve <IProtocolLayer>();
                VerifyEndpointConnectionStatus func = (id, timeout) => layer.VerifyConnectionIsActive(id, timeout);
                return(func);
            })
            .As <VerifyEndpointConnectionStatus>()
            .SingleInstance();

            builder.Register(
                c =>
            {
                var layer = c.Resolve <IProtocolLayer>();
                VerifyEndpointConnectionStatusWithCustomData func = layer.VerifyConnectionIsActive;
                return(func);
            })
            .As <VerifyEndpointConnectionStatusWithCustomData>()
            .SingleInstance();
        }
        public void HandleKeepAliveIntervalElapsedWithConnectionTimeout()
        {
            var info = new EndpointInformation(
                new EndpointId("a"),
                new DiscoveryInformation(new Uri("http://localhost/discovery/invalid")),
                new ProtocolInformation(
                    new Version(1, 0),
                    new Uri("http://localhost/protocol/invalid")));
            var endpoints = new Mock <IStoreInformationAboutEndpoints>();
            {
                endpoints.Setup(e => e.TryGetConnectionFor(It.IsAny <EndpointId>(), out info))
                .Returns(true);
            }

            var wasInvoked = false;
            VerifyEndpointConnectionStatusWithCustomData func =
                (id, timeout, data) =>
            {
                wasInvoked = true;
                Assert.AreEqual(info.Id, id);
                var source = new CancellationTokenSource();
                source.Cancel();
                return(Task <object> .Factory.StartNew(
                           () => null,
                           source.Token,
                           TaskCreationOptions.None,
                           new CurrentThreadTaskScheduler()));
            };

            var timer = new Mock <ITimer>();

            var configuration = new Mock <IConfiguration>();
            {
                configuration.Setup(
                    c => c.HasValueFor(It.Is <ConfigurationKey>(k => k.Equals(CommunicationConfigurationKeys.KeepAliveIntervalInMilliseconds))))
                .Returns(true);
                configuration.Setup(
                    c => c.Value <int>(It.Is <ConfigurationKey>(k => k.Equals(CommunicationConfigurationKeys.KeepAliveIntervalInMilliseconds))))
                .Returns(1);
            }

            DateTimeOffset        time = DateTimeOffset.Now;
            Func <DateTimeOffset> now  = () => time;

            var monitor = new ConnectionMonitor(
                endpoints.Object,
                func,
                timer.Object,
                now,
                configuration.Object);

            // New connection
            var connection = new Mock <IConfirmConnections>();

            monitor.Register(connection.Object);

            // New endpoint
            endpoints.Raise(e => e.OnEndpointConnected += null, new EndpointEventArgs(info.Id));
            time = time + TimeSpan.FromMinutes(2);

            timer.Raise(t => t.OnElapsed += null, EventArgs.Empty);

            Assert.IsTrue(wasInvoked);
            wasInvoked = false;

            timer.Raise(t => t.OnElapsed += null, EventArgs.Empty);

            Assert.IsTrue(wasInvoked);
        }
        public void HandleKeepAliveIntervalElapsedWithAllConnectionsConfirmed()
        {
            var info = new EndpointInformation(
                new EndpointId("a"),
                new DiscoveryInformation(new Uri("http://localhost/discovery/invalid")),
                new ProtocolInformation(
                    new Version(1, 0),
                    new Uri("http://localhost/protocol/invalid")));
            var endpoints = new Mock <IStoreInformationAboutEndpoints>();
            {
                endpoints.Setup(e => e.TryGetConnectionFor(It.IsAny <EndpointId>(), out info))
                .Returns(true);
            }

            var localId = new EndpointId("b");
            VerifyEndpointConnectionStatusWithCustomData func =
                (id, timeout, data) =>
            {
                Assert.AreEqual(info.Id, id);
                return(Task <object> .Factory.StartNew(
                           () => null,
                           new CancellationToken(),
                           TaskCreationOptions.None,
                           new CurrentThreadTaskScheduler()));
            };

            var layer = new Mock <IProtocolLayer>();
            {
                layer.Setup(l => l.Id)
                .Returns(localId);
                layer.Setup(l => l.SendMessageAndWaitForResponse(
                                It.IsAny <EndpointId>(),
                                It.IsAny <ICommunicationMessage>(),
                                It.IsAny <int>(),
                                It.IsAny <TimeSpan>()))
                .Verifiable();
            }

            var timer = new Mock <ITimer>();

            var configuration = new Mock <IConfiguration>();
            {
                configuration.Setup(
                    c => c.HasValueFor(It.Is <ConfigurationKey>(k => k.Equals(CommunicationConfigurationKeys.KeepAliveIntervalInMilliseconds))))
                .Returns(true);
                configuration.Setup(
                    c => c.Value <int>(It.Is <ConfigurationKey>(k => k.Equals(CommunicationConfigurationKeys.KeepAliveIntervalInMilliseconds))))
                .Returns(1);
            }

            DateTimeOffset        time = DateTimeOffset.Now;
            Func <DateTimeOffset> now  = () => time;

            var monitor = new ConnectionMonitor(
                endpoints.Object,
                func,
                timer.Object,
                now,
                configuration.Object);

            // New connection
            var connection = new Mock <IConfirmConnections>();

            monitor.Register(connection.Object);

            // New endpoint
            endpoints.Raise(e => e.OnEndpointConnected += null, new EndpointEventArgs(info.Id));
            timer.Raise(t => t.OnElapsed += null, EventArgs.Empty);

            layer.Verify(
                l => l.SendMessageAndWaitForResponse(
                    It.IsAny <EndpointId>(),
                    It.IsAny <ICommunicationMessage>(),
                    It.IsAny <int>(),
                    It.IsAny <TimeSpan>()),
                Times.Never());
        }