public void Handle(FileChunkResponse message) { DownloadInfo downloadInfo; lock (this.downloadInfos) { if (!this.downloadInfos.TryGetValue(message.DownloadId, out downloadInfo)) // Unknown, ignore return; string chunkFile = Path.Combine(downloadInfo.TempFolder, string.Format("chunk_{0}.bin", message.ChunkStart)); Directory.CreateDirectory(Path.GetDirectoryName(chunkFile)); File.WriteAllBytes(chunkFile, message.Chunk); downloadInfo.ReceivedChunks++; downloadInfo.LastReceive = DateTime.Now; // Request next chunk if (downloadInfo.RequestedChunks < downloadInfo.Chunks) { this.log.Trace("Requesting chunk {0} of file {1}", downloadInfo.RequestedChunks, downloadInfo.FileName); SendMessage(new FileChunkRequest { DownloadId = message.DownloadId, FileName = downloadInfo.FileName, Type = downloadInfo.FileType, ChunkSize = ChunkSize, ChunkStart = downloadInfo.RequestedChunks * ChunkSize }); downloadInfo.RequestedChunks++; } else { if (downloadInfo.ReceivedChunks >= downloadInfo.Chunks) { // Check if we have everything long chunkStart = 0; long fileSize = 0; string assembleFile = Path.Combine(Path.GetDirectoryName(downloadInfo.TempFolder), downloadInfo.FileName); try { using (var fsOutput = File.Create(assembleFile)) { while (fileSize != downloadInfo.FileSize) { chunkFile = Path.Combine(downloadInfo.TempFolder, string.Format("chunk_{0}.bin", chunkStart)); long expectedChunkSize = Math.Min(downloadInfo.FileSize - fileSize, ChunkSize); if (!File.Exists(chunkFile) || new FileInfo(chunkFile).Length != expectedChunkSize) { this.log.Trace("Re-requesting chunk {0} of file {1}", chunkStart / ChunkSize, downloadInfo.FileName); // Re-request SendMessage(new FileChunkRequest { DownloadId = message.DownloadId, FileName = downloadInfo.FileName, Type = downloadInfo.FileType, ChunkSize = ChunkSize, ChunkStart = chunkStart }); // Not done yet return; } var fi = new FileInfo(chunkFile); chunkStart += fi.Length; fileSize += fi.Length; using (var fsInput = File.OpenRead(chunkFile)) fsInput.CopyTo(fsOutput); } fsOutput.Flush(); } // Delete all chunks downloadInfo.Cleanup(); // Check signature byte[] sign = CalculateSignatureSha1(assembleFile); if (!sign.SequenceEqual(downloadInfo.SignatureSha1)) { // Invalid signature, request the file again downloadInfo.Restart(); SendMessage(new FileRequest { DownloadId = downloadInfo.Id, Type = downloadInfo.FileType, FileName = downloadInfo.FileName }); return; } // Match, move to final directory File.Move(assembleFile, downloadInfo.FinalFilePath); assembleFile = null; this.downloadInfos.Remove(downloadInfo.Id); if (downloadInfo.TriggerMessage != null) { // Invoke var method = typeof(MonoExpanderClient).GetMethods() .Where(x => x.Name == "Handle" && x.GetParameters().Any(p => p.ParameterType == downloadInfo.TriggerMessage.GetType())) .ToList(); method.SingleOrDefault()?.Invoke(this, new object[] { downloadInfo.TriggerMessage }); } } finally { // Delete the temporary assemble file if (!string.IsNullOrEmpty(assembleFile)) File.Delete(assembleFile); } } } } }