Ejemplo n.º 1
0
        /// <summary>
        ///     Handles incoming messages from distributed children.
        /// </summary>
        /// <param name="sender">The child <see cref="IMessageConnection"/> from which the message originated.</param>
        /// <param name="message">The message.</param>
        public async void HandleChildMessageRead(object sender, byte[] message)
        {
            var connection = (IMessageConnection)sender;
            var code       = new MessageReader <MessageCode.Distributed>(message).ReadCode();

            Diagnostic.Debug($"Distributed child message received: {code} from {connection.Username} ({connection.IPEndPoint}) (id: {connection.Id})");

            try
            {
                switch (code)
                {
                case MessageCode.Distributed.ChildDepth:
                    break;

                case MessageCode.Distributed.Ping:
                    var pingResponse = new DistributedPingResponse(SoulseekClient.GetNextToken());
                    await connection.WriteAsync(pingResponse).ConfigureAwait(false);

                    break;

                default:
                    Diagnostic.Debug($"Unhandled distributed child message: {code} from {connection.Username} ({connection.IPEndPoint}); {message.Length} bytes");
                    break;
                }
            }
            catch (Exception ex)
            {
                Diagnostic.Warning($"Error handling distributed child message: {code} from {connection.Username} ({connection.IPEndPoint}); {ex.Message}", ex);
            }
        }
        public void FromByteArray_Does_Not_Throw_If_Message_Is_Missing_Token()
        {
            var msg = new MessageBuilder()
                      .WriteCode(MessageCode.Distributed.Ping)
                      .Build();

            var response = DistributedPingResponse.FromByteArray(msg);

            Assert.Equal(0, response.Token);
        }
Ejemplo n.º 3
0
        public void FromByteArray_Returns_Expected_Data(int token)
        {
            var msg = new MessageBuilder()
                      .WriteCode(MessageCode.Distributed.Ping)
                      .WriteInteger(token)
                      .Build();

            var response = DistributedPingResponse.FromByteArray(msg);

            Assert.Equal(token, response.Token);
        }
Ejemplo n.º 4
0
        public void FromByteArray_Throws_MessageException_On_Code_Mismatch()
        {
            var msg = new MessageBuilder()
                      .WriteCode(MessageCode.Distributed.BranchLevel)
                      .WriteInteger(1)
                      .Build();

            var ex = Record.Exception(() => DistributedPingResponse.FromByteArray(msg));

            Assert.NotNull(ex);
            Assert.IsType <MessageException>(ex);
        }
Ejemplo n.º 5
0
        public void ToByteArray_Constructs_The_Correct_Message(int token)
        {
            var msg = new DistributedPingResponse(token).ToByteArray();

            var reader = new MessageReader <MessageCode.Distributed>(msg);
            var code   = reader.ReadCode();

            Assert.Equal(MessageCode.Distributed.Ping, code);
            Assert.Equal(4 + 1 + 4, msg.Length);

            Assert.Equal(token, reader.ReadInteger());
        }
Ejemplo n.º 6
0
        /// <summary>
        ///     Handles incoming messages.
        /// </summary>
        /// <param name="sender">The <see cref="IMessageConnection"/> instance from which the message originated.</param>
        /// <param name="message">The message.</param>
        public async void HandleMessageRead(object sender, byte[] message)
        {
            var connection = (IMessageConnection)sender;
            var code       = new MessageReader <MessageCode.Distributed>(message).ReadCode();

            if (code != MessageCode.Distributed.SearchRequest && code != MessageCode.Distributed.EmbeddedMessage)
            {
                Diagnostic.Debug($"Distributed message received: {code} from {connection.Username} ({connection.IPEndPoint}) (id: {connection.Id})");
            }
            else if (SoulseekClient.Options.DeduplicateSearchRequests)
            {
                var current = Convert.ToBase64String(message);

                if (DeduplicationHash == current)
                {
                    return;
                }

                DeduplicationHash = current;
            }

            try
            {
                switch (code)
                {
                // if we are connected to a branch root, we will receive EmbeddedMessage/93.
                case MessageCode.Distributed.EmbeddedMessage:
                    var embeddedMessage = EmbeddedMessage.FromByteArray(message);

                    switch (embeddedMessage.DistributedCode)
                    {
                    // convert this message to a normal DistributedSearchRequest before forwarding.  this functionality is based
                    // on the observation that branch roots send embedded messages to children, while parents that are not a branch root
                    // send a plain SearchRequest/3.
                    case MessageCode.Distributed.SearchRequest:
                        var embeddedSearchRequest = DistributedSearchRequest.FromByteArray(embeddedMessage.DistributedMessage);

                        _ = SoulseekClient.DistributedConnectionManager.BroadcastMessageAsync(embeddedMessage.DistributedMessage).ConfigureAwait(false);

                        await SoulseekClient.SearchResponder.TryRespondAsync(embeddedSearchRequest.Username, embeddedSearchRequest.Token, embeddedSearchRequest.Query).ConfigureAwait(false);

                        break;

                    default:
                        Diagnostic.Debug($"Unhandled embedded message: {code} from {connection.Username} ({connection.IPEndPoint}); {message.Length} bytes");
                        break;
                    }

                    break;

                // if we are connected to anyone other than a branch root, we will receive SearchRequest/3.
                case MessageCode.Distributed.SearchRequest:
                    var searchRequest = DistributedSearchRequest.FromByteArray(message);

                    _ = SoulseekClient.DistributedConnectionManager.BroadcastMessageAsync(message).ConfigureAwait(false);

                    await SoulseekClient.SearchResponder.TryRespondAsync(searchRequest.Username, searchRequest.Token, searchRequest.Query).ConfigureAwait(false);

                    break;

                case MessageCode.Distributed.Ping:
                    var pingResponse = DistributedPingResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(MessageCode.Distributed.Ping, connection.Username), pingResponse);

                    break;

                case MessageCode.Distributed.BranchLevel:
                    var branchLevel = DistributedBranchLevel.FromByteArray(message);

                    if ((connection.Username, connection.IPEndPoint) == SoulseekClient.DistributedConnectionManager.Parent)
                    {
                        SoulseekClient.DistributedConnectionManager.SetParentBranchLevel(branchLevel.Level);
                    }

                    break;

                case MessageCode.Distributed.BranchRoot:
                    var branchRoot = DistributedBranchRoot.FromByteArray(message);

                    if ((connection.Username, connection.IPEndPoint) == SoulseekClient.DistributedConnectionManager.Parent)
                    {
                        SoulseekClient.DistributedConnectionManager.SetParentBranchRoot(branchRoot.Username);
                    }

                    break;

                case MessageCode.Distributed.ChildDepth:
                    var childDepth = DistributedChildDepth.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(Constants.WaitKey.ChildDepthMessage, connection.Key), childDepth.Depth);
                    break;

                default:
                    Diagnostic.Debug($"Unhandled distributed message: {code} from {connection.Username} ({connection.IPEndPoint}); {message.Length} bytes");
                    break;
                }
            }
            catch (Exception ex)
            {
                Diagnostic.Warning($"Error handling distributed message: {code} from {connection.Username} ({connection.IPEndPoint}); {ex.Message}", ex);
            }
        }
        /// <summary>
        ///     Handles incoming messages.
        /// </summary>
        /// <param name="sender">The <see cref="IMessageConnection"/> instance from which the message originated.</param>
        /// <param name="message">The message.</param>
        public async void HandleMessageRead(object sender, byte[] message)
        {
            var connection = (IMessageConnection)sender;
            var code       = new MessageReader <MessageCode.Distributed>(message).ReadCode();

            if (code != MessageCode.Distributed.SearchRequest && code != MessageCode.Distributed.ServerSearchRequest)
            {
                Diagnostic.Debug($"Distributed message received: {code} from {connection.Username} ({connection.IPEndPoint}) (id: {connection.Id})");
            }
            else if (SoulseekClient.Options.DeduplicateSearchRequests)
            {
                var current = Convert.ToBase64String(message);

                if (DeduplicationHash == current)
                {
                    return;
                }

                DeduplicationHash = current;
            }

            try
            {
                switch (code)
                {
                // if we are connected to a branch root, we get search requests with code DistributedServerSearchRequest.
                // convert this message to a normal DistributedSearchRequest before forwarding. not sure if this is correct,
                // but it would match the observed behavior. these messages may also be forwarded from the server message
                // handler if we haven't connected to a distributed parent in a timely manner.
                case MessageCode.Distributed.ServerSearchRequest:
                    var serverSearchRequest = DistributedServerSearchRequest.FromByteArray(message);

                    var forwardedSearchRequest = new DistributedSearchRequest(serverSearchRequest.Username, serverSearchRequest.Token, serverSearchRequest.Query);
                    _ = SoulseekClient.DistributedConnectionManager.BroadcastMessageAsync(forwardedSearchRequest.ToByteArray()).ConfigureAwait(false);

                    await TrySendSearchResults(serverSearchRequest.Username, serverSearchRequest.Token, serverSearchRequest.Query).ConfigureAwait(false);

                    break;

                // if we are connected to anyone other than a branch root, we should get search requests with code
                // SearchRequest. forward these requests as is.
                case MessageCode.Distributed.SearchRequest:
                    var searchRequest = DistributedSearchRequest.FromByteArray(message);

                    _ = SoulseekClient.DistributedConnectionManager.BroadcastMessageAsync(searchRequest.ToByteArray()).ConfigureAwait(false);

                    await TrySendSearchResults(searchRequest.Username, searchRequest.Token, searchRequest.Query).ConfigureAwait(false);

                    break;

                case MessageCode.Distributed.Ping:
                    var pingResponse = DistributedPingResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(MessageCode.Distributed.Ping, connection.Username), pingResponse);

                    break;

                case MessageCode.Distributed.BranchLevel:
                    var branchLevel = DistributedBranchLevel.FromByteArray(message);

                    if ((connection.Username, connection.IPEndPoint) == SoulseekClient.DistributedConnectionManager.Parent)
                    {
                        SoulseekClient.DistributedConnectionManager.SetBranchLevel(branchLevel.Level);
                    }

                    break;

                case MessageCode.Distributed.BranchRoot:
                    var branchRoot = DistributedBranchRoot.FromByteArray(message);

                    if ((connection.Username, connection.IPEndPoint) == SoulseekClient.DistributedConnectionManager.Parent)
                    {
                        SoulseekClient.DistributedConnectionManager.SetBranchRoot(branchRoot.Username);
                    }

                    break;

                case MessageCode.Distributed.ChildDepth:
                    var childDepth = DistributedChildDepth.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(Constants.WaitKey.ChildDepthMessage, connection.Key), childDepth.Depth);
                    break;

                default:
                    Diagnostic.Debug($"Unhandled distributed message: {code} from {connection.Username} ({connection.IPEndPoint}); {message.Length} bytes");
                    break;
                }
            }
            catch (Exception ex)
            {
                Diagnostic.Warning($"Error handling distributed message: {code} from {connection.Username} ({connection.IPEndPoint}); {ex.Message}", ex);
            }
        }
Ejemplo n.º 8
0
        public void Instantiates_With_The_Given_Data(int token)
        {
            var r = new DistributedPingResponse(token);

            Assert.Equal(token, r.Token);
        }