public async Task <string> GetFile(byte[] fileHash)
        {
            var requestMessage = new GetFileMessage(fileHash);

            var subDir = new DirectoryInfo(Path.Combine(TempStorageDirectory, Hasher.GetDirectoryNameFromHash(fileHash)));

            if (!subDir.Exists)
            {
                subDir.Create();
            }
            var fileName = Hasher.GetFileNameFromHash(fileHash);
            var filePath = Path.Combine(subDir.FullName, fileName);

            FilesInProgress.Add(fileHash, File.OpenWrite(filePath));

            await Communicator.SendMessage(requestMessage);

            // wait for transfer
            var    gotVerificationMessage = false;
            string resultsPath            = null;

            while (!gotVerificationMessage)
            {
                if (VerificationMessages.ContainsKey(fileHash))
                {
                    var verifyMessage = VerificationMessages[fileHash] as FileStoredVerificationMessage;
                    resultsPath = (verifyMessage?.Success ?? false) ? verifyMessage.FilePath : null;
                    VerificationMessages.Remove(fileHash);
                    gotVerificationMessage = true;
                }

                await Task.Delay(1);
            }

            return(resultsPath);
        }
        protected void ProcessMessage(object sender, MessageReceivedArgs e)
        {
            switch (e.Message)
            {
            case FileStartMessage message:
                if (!FilesInProgress.ContainsKey(message.Payload))
                {
                    var fileHash = message.Payload;
                    var subDir   = new DirectoryInfo(Path.Combine(TempStorageDirectory, Hasher.GetDirectoryNameFromHash(fileHash)));
                    if (!subDir.Exists)
                    {
                        subDir.Create();
                    }
                    var fileName = Hasher.GetFileNameFromHash(fileHash);
                    var filePath = Path.Combine(subDir.FullName, fileName);
                    FilesInProgress.Add(message.Payload, File.OpenWrite(filePath));
                }
                break;

            case FileChunckMessage message:
                if (FilesInProgress.ContainsKey(message.FileHash))
                {
                    var stream = FilesInProgress[message.FileHash];
                    stream.Write(message.FileData, 0, message.FileData.Length);
                    var receipt = new FileChunkReceivedMessage(message.FileHash, message.DataChecksum);
                    Communicator.SendMessage(((INetworkClient)sender).ClientName, receipt);
                }
                break;

            case FileEndMessage message:
                if (FilesInProgress.ContainsKey(message.Payload))
                {
                    var stream = FilesInProgress[message.Payload];
                    stream.Flush();

                    var fileHash = message.Payload;
                    var subDir   = Hasher.GetDirectoryNameFromHash(fileHash);
                    var fileName = Hasher.GetFileNameFromHash(fileHash);
                    var filePath = Path.Combine(TempStorageDirectory, subDir, fileName);
                    stream.Dispose();
                    ReadFile(((INetworkClient)sender).ClientName, message.Payload, new FileInfo(filePath));
                    FilesInProgress.Remove(message.Payload);
                }
                break;

            case AbandonFileTransferMessage message:
                if (FilesInProgress.ContainsKey(message.Payload))
                {
                    var stream = FilesInProgress[message.Payload];
                    stream.Dispose();
                    FilesInProgress.Remove(message.Payload);
                }
                break;

            case FileChunkReceivedMessage message:
                FileTransferResponse[message.FileHash] = true;
                break;

            case FileStoredVerificationMessage message:
                VerificationMessages.Add(message.FileHash, message);
                break;

            case GetFileMessage message:
                SendFile(((INetworkClient)sender).ClientName, message.Payload);
                break;
            }
        }