public async Task <ActionResult> InsertUpdateUserAddress(UserAddressModel userAddress)
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri(ConfigurationManager.AppSettings["BaseUrl"]);
                client.DefaultRequestHeaders.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                var json                = JsonConvert.SerializeObject(userAddress.UserAddressObject);
                var content             = new StringContent(json, Encoding.UTF8, "application/json");
                HttpResponseMessage Res = await client.PostAsync("api/DoctorAPI/InsertUpdateUserAddress", content);

                UserAddressResponse result = new UserAddressResponse();
                if (Res.IsSuccessStatusCode)
                {
                    result.IsSuccess = true;
                    result.Message   = Res.Content.ReadAsStringAsync().Result;
                }
                else
                {
                    result.IsSuccess = false;
                    result.Message   = Res.Content.ReadAsStringAsync().Result;
                }
                return(View("UserAddressResponse", result));
            }
        }
示例#2
0
        public void Handles_ServerGetPeerAddress(string username, IPAddress ip, int port)
        {
            UserAddressResponse result = null;

            var(handler, mocks) = GetFixture();

            mocks.Waiter.Setup(m => m.Complete(It.IsAny <WaitKey>(), It.IsAny <UserAddressResponse>()))
            .Callback <WaitKey, UserAddressResponse>((key, response) => result = response);

            var ipBytes = ip.GetAddressBytes();

            Array.Reverse(ipBytes);

            var message = new MessageBuilder()
                          .WriteCode(MessageCode.Server.GetPeerAddress)
                          .WriteString(username)
                          .WriteBytes(ipBytes)
                          .WriteInteger(port)
                          .Build();

            handler.HandleMessage(null, message);

            Assert.Equal(username, result.Username);
            Assert.Equal(ip, result.IPAddress);
            Assert.Equal(port, result.Port);
        }
示例#3
0
        public UserAddressResponse GetUserAddressList(int userId, int?addressId)
        {
            try
            {
                Log.Info("Started call to GetUserAddressList");
                Log.Info("parameter values" + JsonConvert.SerializeObject(new { userId = userId, addressId = addressId }));
                Command.CommandText = "SP_GET_ADDRESS_LIST";
                Command.CommandType = CommandType.StoredProcedure;
                Command.Parameters.Clear();

                Command.Parameters.AddWithValue("@USER_ID", userId);
                if (addressId.HasValue)
                {
                    Command.Parameters.AddWithValue("@ADDRESS_ID", addressId);
                }
                Connection.Open();

                SqlDataAdapter dataAdapter = new SqlDataAdapter(Command);
                DataSet        ds          = new DataSet();
                dataAdapter.Fill(ds);
                UserAddressResponse result = new UserAddressResponse();
                result.UserAddressList = new List <UserAddressDisplay>();
                foreach (DataRow drUserAddress in ds.Tables[0].Rows)
                {
                    result.UserAddressList.Add(new UserAddressDisplay
                    {
                        Id            = Convert.ToInt32(drUserAddress["Id"].ToString()),
                        UserId        = Convert.ToInt32(drUserAddress["UserId"].ToString()),
                        AddressTypeId = Convert.ToInt32(drUserAddress["AddressTypeId"].ToString()),
                        AddressType   = drUserAddress["AddressType"] != DBNull.Value ? drUserAddress["AddressType"].ToString() : null,
                        CountryId     = Convert.ToInt32(drUserAddress["CountryId"].ToString()),
                        Address1      = drUserAddress["Address1"] != DBNull.Value ? drUserAddress["Address1"].ToString() : null,
                        Address2      = drUserAddress["Address2"] != DBNull.Value ? drUserAddress["Address2"].ToString() : null,
                        ZipCode       = drUserAddress["ZipCode"] != DBNull.Value ? drUserAddress["ZipCode"].ToString() : null,
                        City          = drUserAddress["City"] != DBNull.Value ? drUserAddress["City"].ToString() : null,
                        StateId       = drUserAddress["StateId"] != DBNull.Value ? drUserAddress["StateId"].ToString() : null,
                        StateName     = drUserAddress["StateName"] != DBNull.Value ? drUserAddress["StateName"].ToString() : null,
                        CountryName   = drUserAddress["CountryName"] != DBNull.Value ? drUserAddress["CountryName"].ToString() : null,
                        AddedBy       = drUserAddress["AddedBy"] != DBNull.Value ? Convert.ToInt32(drUserAddress["AddedBy"].ToString()) : (int?)null,
                        AddedDate     = drUserAddress["AddedDate"] != DBNull.Value ? DateTime.Parse(drUserAddress["AddedDate"].ToString()) : (DateTime?)null,
                        ModifiedBy    = drUserAddress["ModifiedBy"] != DBNull.Value ? Convert.ToInt32(drUserAddress["ModifiedBy"].ToString()) : (int?)null,
                        ModifiedDate  = drUserAddress["ModifiedDate"] != DBNull.Value ? DateTime.Parse(drUserAddress["ModifiedDate"].ToString()) : (DateTime?)null,
                    });
                }
                Log.Info("End call to GetUserAddressList result " + JsonConvert.SerializeObject(result));

                return(result);
            }
            catch (Exception ex)
            {
                throw;
            }
            finally
            {
                Connection.Close();
            }
        }
        public void Parse_Throws_MessageException_On_Code_Mismatch()
        {
            var msg = new MessageBuilder()
                      .WriteCode(MessageCode.Peer.BrowseRequest)
                      .Build();

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

            Assert.NotNull(ex);
            Assert.IsType <MessageException>(ex);
        }
        public void Parse_Throws_MessageReadException_On_Missing_Data()
        {
            var msg = new MessageBuilder()
                      .WriteCode(MessageCode.Server.GetPeerAddress)
                      .WriteString("foo")
                      .Build();

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

            Assert.NotNull(ex);
            Assert.IsType <MessageReadException>(ex);
        }
        public void Instantiates_With_The_Given_Data(string username, IPEndPoint endpoint)
        {
            UserAddressResponse response = null;

            var ex = Record.Exception(() => response = new UserAddressResponse(username, endpoint));

            Assert.Null(ex);

            Assert.Equal(username, response.Username);
            Assert.Equal(endpoint.Address, response.IPEndPoint.Address);
            Assert.Equal(endpoint.Port, response.IPEndPoint.Port);
        }
示例#7
0
        public UserAddressResponse InsertUpdateUserAddress(UserAddress userAddress, string operation)
        {
            try
            {
                Log.Info("Started call to InsertUpdateUserAddress");
                Log.Info("parameter values" + JsonConvert.SerializeObject(new { userAddress = userAddress, operation = operation }));
                Command.CommandText = "SP_ADDRESS_MANAGER";
                Command.CommandType = CommandType.StoredProcedure;
                Command.Parameters.Clear();

                Command.Parameters.AddWithValue("@USER_ADDRESS_XML", GetXMLFromObject(userAddress));
                if (!string.IsNullOrEmpty(operation))
                {
                    Command.Parameters.AddWithValue("@OPERATION", operation);
                }
                if (userAddress.AddedBy.HasValue)
                {
                    Command.Parameters.AddWithValue("@USER_ID", userAddress.AddedBy.Value);
                }
                else if (userAddress.ModifiedBy.HasValue)
                {
                    Command.Parameters.AddWithValue("@USER_ID", userAddress.ModifiedBy.Value);
                }
                Connection.Open();
                SqlDataReader reader = Command.ExecuteReader();

                UserAddressResponse result = new UserAddressResponse();
                if (reader.HasRows)
                {
                    while (reader.Read())
                    {
                        result = new UserAddressResponse
                        {
                            Message   = reader["ReturnMessage"] != DBNull.Value ? reader["ReturnMessage"].ToString() : null,
                            IsSuccess = Convert.ToBoolean(reader["Result"].ToString())
                        };
                    }
                }
                Log.Info("End call to InsertUpdateUserAddress");

                return(result);
            }
            catch (Exception ex)
            {
                throw;
            }
            finally
            {
                Connection.Close();
            }
        }
        public void Instantiates_With_The_Given_Data()
        {
            var un   = RandomGuid;
            var ip   = new IPAddress(Random.Next(1024));
            var port = Random.Next();

            UserAddressResponse response = null;

            var ex = Record.Exception(() => response = new UserAddressResponse(un, ip, port));

            Assert.Null(ex);

            Assert.Equal(un, response.Username);
            Assert.Equal(ip, response.IPAddress);
            Assert.Equal(port, response.Port);
        }
        public void Parse_Returns_Expected_Data(string username, IPEndPoint endpoint)
        {
            var ipBytes = endpoint.Address.GetAddressBytes();

            Array.Reverse(ipBytes);

            var msg = new MessageBuilder()
                      .WriteCode(MessageCode.Server.GetPeerAddress)
                      .WriteString(username)
                      .WriteBytes(ipBytes)
                      .WriteInteger(endpoint.Port)
                      .Build();

            var response = UserAddressResponse.FromByteArray(msg);

            Assert.Equal(username, response.Username);
            Assert.Equal(endpoint.Address, response.IPAddress);
            Assert.Equal(endpoint.Port, response.Port);
        }
        public void Parse_Returns_Expected_Data()
        {
            var un = RandomGuid;

            var ip      = new IPAddress(Random.Next(1024));
            var ipBytes = ip.GetAddressBytes();

            Array.Reverse(ipBytes);

            var port = Random.Next();

            var msg = new MessageBuilder()
                      .WriteCode(MessageCode.Server.GetPeerAddress)
                      .WriteString(un)
                      .WriteBytes(ipBytes)
                      .WriteInteger(port)
                      .Build();

            var response = UserAddressResponse.FromByteArray(msg);

            Assert.Equal(un, response.Username);
            Assert.Equal(ip, response.IPAddress);
            Assert.Equal(port, response.Port);
        }
示例#11
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 code = new MessageReader <MessageCode.Server>(message).ReadCode();

            if (code != MessageCode.Server.SearchRequest)
            {
                Diagnostic.Debug($"Server message received: {code}");
            }

            try
            {
                switch (code)
                {
                case MessageCode.Server.ParentMinSpeed:
                case MessageCode.Server.ParentSpeedRatio:
                case MessageCode.Server.WishlistInterval:
                case MessageCode.Server.CheckPrivileges:
                    SoulseekClient.Waiter.Complete(new WaitKey(code), IntegerResponse.FromByteArray <MessageCode.Server>(message));
                    break;

                case MessageCode.Server.NewPassword:
                    var confirmedPassword = NewPassword.FromByteArray(message).Password;
                    SoulseekClient.Waiter.Complete(new WaitKey(code), confirmedPassword);
                    break;

                case MessageCode.Server.GlobalAdminMessage:
                    var msg = GlobalMessageNotification.FromByteArray(message);
                    GlobalMessageReceived?.Invoke(this, new GlobalMessageReceivedEventArgs(msg));
                    break;

                case MessageCode.Server.Ping:
                    SoulseekClient.Waiter.Complete(new WaitKey(code));
                    break;

                case MessageCode.Server.Login:
                    SoulseekClient.Waiter.Complete(new WaitKey(code), LoginResponse.FromByteArray(message));
                    break;

                case MessageCode.Server.RoomList:
                    var roomList = RoomListResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code), roomList);
                    RoomListReceived?.Invoke(this, new RoomListReceivedEventArgs(roomList));
                    break;

                case MessageCode.Server.PrivilegedUsers:
                    var privilegedUserList = PrivilegedUserListNotification.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code), privilegedUserList);
                    PrivilegedUserListReceived?.Invoke(this, new PrivilegedUserListReceivedEventArgs(privilegedUserList));
                    break;

                case MessageCode.Server.AddPrivilegedUser:
                    PrivilegeNotificationReceived?.Invoke(this, new PrivilegeNotificationReceivedEventArgs(PrivilegedUserNotification.FromByteArray(message)));
                    break;

                case MessageCode.Server.NotifyPrivileges:
                    var pn = PrivilegeNotification.FromByteArray(message);
                    PrivilegeNotificationReceived?.Invoke(this, new PrivilegeNotificationReceivedEventArgs(pn.Username, pn.Id));

                    if (SoulseekClient.Options.AutoAcknowledgePrivilegeNotifications)
                    {
                        await SoulseekClient.AcknowledgePrivilegeNotificationAsync(pn.Id, CancellationToken.None).ConfigureAwait(false);
                    }

                    break;

                case MessageCode.Server.UserPrivileges:
                    var privilegeResponse = UserPrivilegeResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, privilegeResponse.Username), privilegeResponse.IsPrivileged);
                    break;

                case MessageCode.Server.NetInfo:
                    var netInfo = NetInfoNotification.FromByteArray(message);

                    try
                    {
                        var parents = netInfo.Parents.Select(parent => (parent.Username, new IPEndPoint(parent.IPAddress, parent.Port)));
                        await SoulseekClient.DistributedConnectionManager.AddParentConnectionAsync(parents).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        Diagnostic.Debug($"Error handling NetInfo message: {ex.Message}");
                    }

                    break;

                case MessageCode.Server.ConnectToPeer:
                    ConnectToPeerResponse connectToPeerResponse = default;

                    try
                    {
                        connectToPeerResponse = ConnectToPeerResponse.FromByteArray(message);

                        if (connectToPeerResponse.Type == Constants.ConnectionType.Transfer)
                        {
                            Diagnostic.Debug($"Received transfer ConnectToPeer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint}) for remote token {connectToPeerResponse.Token}");

                            // ensure that we are expecting at least one file from this user before we connect. the response
                            // doesn't contain any other identifying information about the file.
                            if (!SoulseekClient.Downloads.IsEmpty && SoulseekClient.Downloads.Values.Any(d => d.Username == connectToPeerResponse.Username))
                            {
                                var(connection, remoteToken) = await SoulseekClient.PeerConnectionManager.GetTransferConnectionAsync(connectToPeerResponse).ConfigureAwait(false);

                                var download = SoulseekClient.Downloads.Values.FirstOrDefault(v => v.RemoteToken == remoteToken && v.Username == connectToPeerResponse.Username);

                                if (download != default(TransferInternal))
                                {
                                    Diagnostic.Debug($"Solicited inbound transfer connection to {download.Username} ({connection.IPEndPoint}) for token {download.Token} (remote: {download.RemoteToken}) established. (id: {connection.Id})");
                                    SoulseekClient.Waiter.Complete(new WaitKey(Constants.WaitKey.IndirectTransfer, download.Username, download.Filename, download.RemoteToken), connection);
                                }
                                else
                                {
                                    Diagnostic.Debug($"Transfer ConnectToPeer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint}) for remote token {connectToPeerResponse.Token} does not match any waiting downloads, discarding.");
                                    connection.Disconnect($"Unknown transfer");
                                }
                            }
                            else
                            {
                                throw new SoulseekClientException($"Unexpected transfer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint}); Ignored");
                            }
                        }
                        else if (connectToPeerResponse.Type == Constants.ConnectionType.Peer)
                        {
                            Diagnostic.Debug($"Received message ConnectToPeer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint})");
                            await SoulseekClient.PeerConnectionManager.GetOrAddMessageConnectionAsync(connectToPeerResponse).ConfigureAwait(false);
                        }
                        else if (connectToPeerResponse.Type == Constants.ConnectionType.Distributed)
                        {
                            Diagnostic.Debug($"Received distributed ConnectToPeer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint})");
                            await SoulseekClient.DistributedConnectionManager.AddChildConnectionAsync(connectToPeerResponse).ConfigureAwait(false);
                        }
                        else
                        {
                            throw new MessageException($"Unknown Connect To Peer connection type '{connectToPeerResponse.Type}'");
                        }
                    }
                    catch (Exception ex)
                    {
                        Diagnostic.Debug($"Error handling ConnectToPeer response from {connectToPeerResponse?.Username} ({connectToPeerResponse?.IPEndPoint}): {ex.Message}");
                    }

                    break;

                case MessageCode.Server.AddUser:
                    var addUserResponse = AddUserResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, addUserResponse.Username), addUserResponse);
                    break;

                case MessageCode.Server.GetStatus:
                    var statsResponse = UserStatusResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, statsResponse.Username), statsResponse);
                    UserStatusChanged?.Invoke(this, new UserStatusChangedEventArgs(statsResponse));
                    break;

                case MessageCode.Server.PrivateMessage:
                    var pm = PrivateMessageNotification.FromByteArray(message);
                    PrivateMessageReceived?.Invoke(this, new PrivateMessageReceivedEventArgs(pm));

                    if (SoulseekClient.Options.AutoAcknowledgePrivateMessages)
                    {
                        await SoulseekClient.AcknowledgePrivateMessageAsync(pm.Id, CancellationToken.None).ConfigureAwait(false);
                    }

                    break;

                case MessageCode.Server.GetPeerAddress:
                    var peerAddressResponse = UserAddressResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, peerAddressResponse.Username), peerAddressResponse);
                    break;

                case MessageCode.Server.JoinRoom:
                    var roomData = RoomJoinResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, roomData.Name), roomData);
                    break;

                case MessageCode.Server.LeaveRoom:
                    var leaveRoomResponse = RoomLeaveResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, leaveRoomResponse.RoomName));
                    break;

                case MessageCode.Server.SayInChatRoom:
                    var roomMessage = RoomMessageNotification.FromByteArray(message);
                    RoomMessageReceived?.Invoke(this, new RoomMessageReceivedEventArgs(roomMessage));
                    break;

                case MessageCode.Server.UserJoinedRoom:
                    var joinNotification = RoomJoinedNotification.FromByteArray(message);
                    RoomJoined?.Invoke(this, new RoomJoinedEventArgs(joinNotification));
                    break;

                case MessageCode.Server.UserLeftRoom:
                    var leftNotification = RoomLeftNotification.FromByteArray(message);
                    RoomLeft?.Invoke(this, new RoomLeftEventArgs(leftNotification));
                    break;

                case MessageCode.Server.KickedFromServer:
                    KickedFromServer?.Invoke(this, EventArgs.Empty);
                    break;

                case MessageCode.Server.FileSearch:
                    var searchRequest = ServerSearchRequest.FromByteArray(message);

                    // sometimes (most of the time?) a room search will result in a request to ourselves (assuming we are
                    // joined to it)
                    if (searchRequest.Username == SoulseekClient.Username)
                    {
                        break;
                    }

                    SearchResponse searchResponse;

                    if (SoulseekClient.Options.SearchResponseResolver == default)
                    {
                        break;
                    }

                    try
                    {
                        searchResponse = await SoulseekClient.Options.SearchResponseResolver(searchRequest.Username, searchRequest.Token, SearchQuery.FromText(searchRequest.Query)).ConfigureAwait(false);

                        if (searchResponse != null && searchResponse.FileCount + searchResponse.LockedFileCount > 0)
                        {
                            var endpoint = await SoulseekClient.GetUserEndPointAsync(searchRequest.Username).ConfigureAwait(false);

                            var peerConnection = await SoulseekClient.PeerConnectionManager.GetOrAddMessageConnectionAsync(searchRequest.Username, endpoint, CancellationToken.None).ConfigureAwait(false);

                            await peerConnection.WriteAsync(searchResponse.ToByteArray()).ConfigureAwait(false);
                        }
                    }
                    catch (Exception ex)
                    {
                        Diagnostic.Warning($"Error resolving search response for query '{searchRequest.Query}' requested by {searchRequest.Username} with token {searchRequest.Token}: {ex.Message}", ex);
                    }

                    break;

                // if we fail to connect to a distributed parent in a timely manner, the server will begin to send us distributed search requests directly.
                // forward these to the distributed message handler.
                case MessageCode.Server.SearchRequest:
                    SoulseekClient.DistributedMessageHandler.HandleMessageRead(SoulseekClient.ServerConnection, message);
                    break;

                default:
                    Diagnostic.Debug($"Unhandled server message: {code}; {message.Length} bytes");
                    break;
                }
            }
            catch (Exception ex)
            {
                Diagnostic.Warning($"Error handling server message: {code}; {ex.Message}", ex);
            }
        }
示例#12
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 code = new MessageReader <MessageCode.Server>(message).ReadCode();

            if (code != MessageCode.Server.EmbeddedMessage)
            {
                Diagnostic.Debug($"Server message received: {code}");
            }

            try
            {
                switch (code)
                {
                case MessageCode.Server.ParentMinSpeed:
                case MessageCode.Server.ParentSpeedRatio:
                case MessageCode.Server.WishlistInterval:
                case MessageCode.Server.CheckPrivileges:
                    SoulseekClient.Waiter.Complete(new WaitKey(code), IntegerResponse.FromByteArray <MessageCode.Server>(message));
                    break;

                case MessageCode.Server.PrivateRoomAdded:
                    PrivateRoomMembershipAdded?.Invoke(this, StringResponse.FromByteArray <MessageCode.Server>(message));
                    break;

                case MessageCode.Server.PrivateRoomRemoved:
                    var privateRoomRemoved = StringResponse.FromByteArray <MessageCode.Server>(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, privateRoomRemoved));
                    PrivateRoomMembershipRemoved?.Invoke(this, privateRoomRemoved);
                    break;

                case MessageCode.Server.PrivateRoomOperatorAdded:
                    PrivateRoomModerationAdded?.Invoke(this, StringResponse.FromByteArray <MessageCode.Server>(message));
                    break;

                case MessageCode.Server.PrivateRoomOperatorRemoved:
                    var privateRoomOperatorRemoved = StringResponse.FromByteArray <MessageCode.Server>(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, privateRoomOperatorRemoved));
                    PrivateRoomModerationRemoved?.Invoke(this, privateRoomOperatorRemoved);
                    break;

                case MessageCode.Server.NewPassword:
                    var confirmedPassword = NewPassword.FromByteArray(message).Password;
                    SoulseekClient.Waiter.Complete(new WaitKey(code), confirmedPassword);
                    break;

                case MessageCode.Server.PrivateRoomToggle:
                    var acceptInvitations = PrivateRoomToggle.FromByteArray(message).AcceptInvitations;
                    SoulseekClient.Waiter.Complete(new WaitKey(code), acceptInvitations);
                    break;

                case MessageCode.Server.GlobalAdminMessage:
                    var msg = GlobalMessageNotification.FromByteArray(message);
                    GlobalMessageReceived?.Invoke(this, msg);
                    break;

                case MessageCode.Server.Ping:
                    SoulseekClient.Waiter.Complete(new WaitKey(code));
                    break;

                case MessageCode.Server.Login:
                    SoulseekClient.Waiter.Complete(new WaitKey(code), LoginResponse.FromByteArray(message));
                    break;

                case MessageCode.Server.RoomList:
                    var roomList = RoomListResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code), roomList);
                    RoomListReceived?.Invoke(this, roomList);
                    break;

                case MessageCode.Server.PrivateRoomOwned:
                    var moderatedRoomInfo = PrivateRoomOwnedListNotification.FromByteArray(message);
                    PrivateRoomModeratedUserListReceived?.Invoke(this, moderatedRoomInfo);
                    break;

                case MessageCode.Server.PrivateRoomUsers:
                    var roomInfo = PrivateRoomUserListNotification.FromByteArray(message);
                    PrivateRoomUserListReceived?.Invoke(this, roomInfo);
                    break;

                case MessageCode.Server.PrivilegedUsers:
                    var privilegedUserList = PrivilegedUserListNotification.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code), privilegedUserList);
                    PrivilegedUserListReceived?.Invoke(this, privilegedUserList);
                    break;

                case MessageCode.Server.AddPrivilegedUser:
                    PrivilegeNotificationReceived?.Invoke(this, new PrivilegeNotificationReceivedEventArgs(PrivilegedUserNotification.FromByteArray(message)));
                    break;

                case MessageCode.Server.NotifyPrivileges:
                    var pn = PrivilegeNotification.FromByteArray(message);
                    PrivilegeNotificationReceived?.Invoke(this, new PrivilegeNotificationReceivedEventArgs(pn.Username, pn.Id));

                    if (SoulseekClient.Options.AutoAcknowledgePrivilegeNotifications)
                    {
                        await SoulseekClient.AcknowledgePrivilegeNotificationAsync(pn.Id, CancellationToken.None).ConfigureAwait(false);
                    }

                    break;

                case MessageCode.Server.UserPrivileges:
                    var privilegeResponse = UserPrivilegeResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, privilegeResponse.Username), privilegeResponse.IsPrivileged);
                    break;

                case MessageCode.Server.NetInfo:
                    var netInfo = NetInfoNotification.FromByteArray(message);

                    try
                    {
                        var parents = netInfo.Parents.Select(parent => (parent.Username, new IPEndPoint(parent.IPAddress, parent.Port)));
                        await SoulseekClient.DistributedConnectionManager.AddParentConnectionAsync(parents).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        Diagnostic.Debug($"Error handling NetInfo message: {ex.Message}");
                    }

                    break;

                case MessageCode.Server.CannotConnect:
                    var cannotConnect = CannotConnect.FromByteArray(message);
                    Diagnostic.Debug($"Received CannotConnect message for token {cannotConnect.Token}{(!string.IsNullOrEmpty(cannotConnect.Username) ? $" from user {cannotConnect.Username}" : string.Empty)}");

                    SoulseekClient.SearchResponder.TryDiscard(cannotConnect.Token);

                    if (!string.IsNullOrEmpty(cannotConnect.Username))
                    {
                        UserCannotConnect?.Invoke(this, new UserCannotConnectEventArgs(cannotConnect));
                    }

                    break;

                case MessageCode.Server.CannotJoinRoom:
                    var cannotJoinRoom = CannotJoinRoom.FromByteArray(message);
                    SoulseekClient.Waiter.Throw(
                        new WaitKey(MessageCode.Server.JoinRoom, cannotJoinRoom.RoomName),
                        new RoomJoinForbiddenException($"The server rejected the request to join room {cannotJoinRoom.RoomName}"));

                    break;

                case MessageCode.Server.ConnectToPeer:
                    var connectToPeerResponse = ConnectToPeerResponse.FromByteArray(message);

                    try
                    {
                        if (connectToPeerResponse.Type == Constants.ConnectionType.Transfer)
                        {
                            Diagnostic.Debug($"Received transfer ConnectToPeer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint}) for remote token {connectToPeerResponse.Token}");

                            // ensure that we are expecting at least one file from this user before we connect. the response
                            // doesn't contain any other identifying information about the file.
                            if (!SoulseekClient.Downloads.IsEmpty && SoulseekClient.Downloads.Values.Any(d => d.Username == connectToPeerResponse.Username))
                            {
                                var(connection, remoteToken) = await SoulseekClient.PeerConnectionManager.GetTransferConnectionAsync(connectToPeerResponse).ConfigureAwait(false);

                                var download = SoulseekClient.Downloads.Values.FirstOrDefault(v => v.RemoteToken == remoteToken && v.Username == connectToPeerResponse.Username);

                                if (download != default(TransferInternal))
                                {
                                    Diagnostic.Debug($"Solicited inbound transfer connection to {download.Username} ({connection.IPEndPoint}) for token {download.Token} (remote: {download.RemoteToken}) established. (id: {connection.Id})");
                                    SoulseekClient.Waiter.Complete(new WaitKey(Constants.WaitKey.IndirectTransfer, download.Username, download.Filename, download.RemoteToken), connection);
                                }
                                else
                                {
                                    Diagnostic.Debug($"Transfer ConnectToPeer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint}) for remote token {connectToPeerResponse.Token} does not match any waiting downloads, discarding.");
                                    connection.Disconnect("Unknown transfer");
                                }
                            }
                            else
                            {
                                throw new SoulseekClientException($"Unexpected transfer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint}); Ignored");
                            }
                        }
                        else if (connectToPeerResponse.Type == Constants.ConnectionType.Peer)
                        {
                            Diagnostic.Debug($"Received message ConnectToPeer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint})");
                            await SoulseekClient.PeerConnectionManager.GetOrAddMessageConnectionAsync(connectToPeerResponse).ConfigureAwait(false);
                        }
                        else if (connectToPeerResponse.Type == Constants.ConnectionType.Distributed)
                        {
                            Diagnostic.Debug($"Received distributed ConnectToPeer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint})");
                            await SoulseekClient.DistributedConnectionManager.GetOrAddChildConnectionAsync(connectToPeerResponse).ConfigureAwait(false);
                        }
                        else
                        {
                            throw new MessageException($"Unknown Connect To Peer connection type '{connectToPeerResponse.Type}'");
                        }
                    }
                    catch (Exception ex)
                    {
                        Diagnostic.Debug($"Error handling ConnectToPeer response from {connectToPeerResponse.Username} ({connectToPeerResponse.IPEndPoint}): {ex.Message}");
                    }

                    break;

                case MessageCode.Server.AddUser:
                    var addUserResponse = AddUserResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, addUserResponse.Username), addUserResponse);
                    break;

                case MessageCode.Server.GetStatus:
                    var statsResponse = UserStatusResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, statsResponse.Username), statsResponse);
                    UserStatusChanged?.Invoke(this, new UserStatusChangedEventArgs(statsResponse));
                    break;

                case MessageCode.Server.PrivateMessage:
                    var pm = PrivateMessageNotification.FromByteArray(message);
                    PrivateMessageReceived?.Invoke(this, new PrivateMessageReceivedEventArgs(pm));

                    if (SoulseekClient.Options.AutoAcknowledgePrivateMessages)
                    {
                        await SoulseekClient.AcknowledgePrivateMessageAsync(pm.Id, CancellationToken.None).ConfigureAwait(false);
                    }

                    break;

                case MessageCode.Server.GetPeerAddress:
                    var peerAddressResponse = UserAddressResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, peerAddressResponse.Username), peerAddressResponse);
                    break;

                case MessageCode.Server.JoinRoom:
                    var roomData = JoinRoomResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, roomData.Name), roomData);
                    break;

                case MessageCode.Server.LeaveRoom:
                    var leaveRoomResponse = LeaveRoomResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, leaveRoomResponse.RoomName));
                    break;

                case MessageCode.Server.SayInChatRoom:
                    var roomMessage = RoomMessageNotification.FromByteArray(message);
                    RoomMessageReceived?.Invoke(this, new RoomMessageReceivedEventArgs(roomMessage));
                    break;

                case MessageCode.Server.PublicChat:
                    var publicChatMessage = PublicChatMessageNotification.FromByteArray(message);
                    PublicChatMessageReceived?.Invoke(this, new PublicChatMessageReceivedEventArgs(publicChatMessage));
                    break;

                case MessageCode.Server.UserJoinedRoom:
                    var joinNotification = UserJoinedRoomNotification.FromByteArray(message);
                    RoomJoined?.Invoke(this, new RoomJoinedEventArgs(joinNotification));
                    break;

                case MessageCode.Server.UserLeftRoom:
                    var leftNotification = UserLeftRoomNotification.FromByteArray(message);
                    RoomLeft?.Invoke(this, new RoomLeftEventArgs(leftNotification));
                    break;

                case MessageCode.Server.RoomTickers:
                    var roomTickers = RoomTickerListNotification.FromByteArray(message);
                    RoomTickerListReceived?.Invoke(this, new RoomTickerListReceivedEventArgs(roomTickers));
                    break;

                case MessageCode.Server.RoomTickerAdd:
                    var roomTickerAdded = RoomTickerAddedNotification.FromByteArray(message);
                    RoomTickerAdded?.Invoke(this, new RoomTickerAddedEventArgs(roomTickerAdded.RoomName, roomTickerAdded.Ticker));
                    break;

                case MessageCode.Server.RoomTickerRemove:
                    var roomTickerRemoved = RoomTickerRemovedNotification.FromByteArray(message);
                    RoomTickerRemoved?.Invoke(this, new RoomTickerRemovedEventArgs(roomTickerRemoved.RoomName, roomTickerRemoved.Username));
                    break;

                case MessageCode.Server.PrivateRoomAddUser:
                    var privateRoomAddUserResponse = PrivateRoomAddUser.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, privateRoomAddUserResponse.RoomName, privateRoomAddUserResponse.Username));
                    break;

                case MessageCode.Server.PrivateRoomRemoveUser:
                    var privateRoomRemoveUserResponse = PrivateRoomRemoveUser.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, privateRoomRemoveUserResponse.RoomName, privateRoomRemoveUserResponse.Username));
                    break;

                case MessageCode.Server.PrivateRoomAddOperator:
                    var privateRoomAddOperatorResponse = PrivateRoomAddOperator.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, privateRoomAddOperatorResponse.RoomName, privateRoomAddOperatorResponse.Username));
                    break;

                case MessageCode.Server.PrivateRoomRemoveOperator:
                    var privateRoomRemoveOperatorResponse = PrivateRoomRemoveOperator.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, privateRoomRemoveOperatorResponse.RoomName, privateRoomRemoveOperatorResponse.Username));
                    break;

                case MessageCode.Server.KickedFromServer:
                    KickedFromServer?.Invoke(this, EventArgs.Empty);
                    break;

                case MessageCode.Server.FileSearch:
                    var searchRequest = ServerSearchRequest.FromByteArray(message);

                    // sometimes (most of the time?) a room search will result in a request to ourselves (assuming we are
                    // joined to it)
                    if (searchRequest.Username == SoulseekClient.Username)
                    {
                        break;
                    }

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

                    break;

                case MessageCode.Server.EmbeddedMessage:
                    SoulseekClient.DistributedMessageHandler.HandleEmbeddedMessage(message);
                    break;

                default:
                    Diagnostic.Debug($"Unhandled server message: {code}; {message.Length} bytes");
                    break;
                }
            }
            catch (Exception ex)
            {
                Diagnostic.Warning($"Error handling server message: {code}; {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 HandleMessage(object sender, byte[] message)
        {
            var code = new MessageReader <MessageCode.Server>(message).ReadCode();

            Diagnostic.Debug($"Server message received: {code}");

            try
            {
                switch (code)
                {
                case MessageCode.Server.ParentMinSpeed:
                case MessageCode.Server.ParentSpeedRatio:
                case MessageCode.Server.WishlistInterval:
                    SoulseekClient.Waiter.Complete(new WaitKey(code), IntegerResponse.FromByteArray <MessageCode.Server>(message));
                    break;

                case MessageCode.Server.Login:
                    SoulseekClient.Waiter.Complete(new WaitKey(code), LoginResponse.FromByteArray(message));
                    break;

                case MessageCode.Server.RoomList:
                    SoulseekClient.Waiter.Complete(new WaitKey(code), RoomList.FromByteArray(message));
                    break;

                case MessageCode.Server.PrivilegedUsers:
                    SoulseekClient.Waiter.Complete(new WaitKey(code), PrivilegedUserList.FromByteArray(message));
                    break;

                case MessageCode.Server.NetInfo:
                    var netInfo = NetInfo.FromByteArray(message);

                    try
                    {
                        await SoulseekClient.DistributedConnectionManager.AddParentConnectionAsync(netInfo.Parents).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        Diagnostic.Debug($"Error handling NetInfo message: {ex.Message}");
                    }

                    break;

                case MessageCode.Server.ConnectToPeer:
                    ConnectToPeerResponse connectToPeerResponse = default;

                    try
                    {
                        connectToPeerResponse = ConnectToPeerResponse.FromByteArray(message);

                        if (connectToPeerResponse.Type == Constants.ConnectionType.Transfer)
                        {
                            // ensure that we are expecting at least one file from this user before we connect. the response
                            // doesn't contain any other identifying information about the file.
                            if (!SoulseekClient.Downloads.IsEmpty && SoulseekClient.Downloads.Values.Any(d => d.Username == connectToPeerResponse.Username))
                            {
                                var(connection, remoteToken) = await SoulseekClient.PeerConnectionManager.GetTransferConnectionAsync(connectToPeerResponse).ConfigureAwait(false);

                                var download = SoulseekClient.Downloads.Values.FirstOrDefault(v => v.RemoteToken == remoteToken && v.Username == connectToPeerResponse.Username);

                                if (download != default(Transfer))
                                {
                                    SoulseekClient.Waiter.Complete(new WaitKey(Constants.WaitKey.IndirectTransfer, download.Username, download.Filename, download.RemoteToken), connection);
                                }
                            }
                            else
                            {
                                throw new SoulseekClientException($"Unexpected transfer request from {connectToPeerResponse.Username} ({connectToPeerResponse.IPAddress}:{connectToPeerResponse.Port}); Ignored");
                            }
                        }
                        else if (connectToPeerResponse.Type == Constants.ConnectionType.Peer)
                        {
                            await SoulseekClient.PeerConnectionManager.GetOrAddMessageConnectionAsync(connectToPeerResponse).ConfigureAwait(false);
                        }
                        else if (connectToPeerResponse.Type == Constants.ConnectionType.Distributed)
                        {
                            await SoulseekClient.DistributedConnectionManager.AddChildConnectionAsync(connectToPeerResponse).ConfigureAwait(false);
                        }
                        else
                        {
                            throw new MessageException($"Unknown Connect To Peer connection type '{connectToPeerResponse.Type}'");
                        }
                    }
                    catch (Exception ex)
                    {
                        Diagnostic.Debug($"Error handling ConnectToPeer response from {connectToPeerResponse?.Username} ({connectToPeerResponse?.IPAddress}:{connectToPeerResponse.Port}): {ex.Message}");
                    }

                    break;

                case MessageCode.Server.AddUser:
                    var addUserResponse = AddUserResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, addUserResponse.Username), addUserResponse);
                    break;

                case MessageCode.Server.GetStatus:
                    var statsResponse = UserStatusResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, statsResponse.Username), statsResponse);
                    UserStatusChanged?.Invoke(this, new UserStatusChangedEventArgs(statsResponse));
                    break;

                case MessageCode.Server.PrivateMessage:
                    var pm = PrivateMessage.FromByteArray(message);
                    PrivateMessageReceived?.Invoke(this, pm);

                    if (SoulseekClient.Options.AutoAcknowledgePrivateMessages)
                    {
                        await SoulseekClient.AcknowledgePrivateMessageAsync(pm.Id, CancellationToken.None).ConfigureAwait(false);
                    }

                    break;

                case MessageCode.Server.GetPeerAddress:
                    var peerAddressResponse = UserAddressResponse.FromByteArray(message);
                    SoulseekClient.Waiter.Complete(new WaitKey(code, peerAddressResponse.Username), peerAddressResponse);
                    break;

                default:
                    Diagnostic.Debug($"Unhandled server message: {code}; {message.Length} bytes");
                    break;
                }
            }
            catch (Exception ex)
            {
                Diagnostic.Warning($"Error handling server message: {code}; {ex.Message}", ex);
            }
        }