public override FileTransferResponsed Handle(ContextRequest request, FileWriteHandleContext context)
        {
            FileTransferResponsed responsed = new FileTransferResponsed(request.FileRequest);
            var r = request.FileRequest;

            if (r.IsSendingOver)//在文件写入完成时,检查文件MD5
            {
                if (request.ProgressDic.ContainsKey(r.FileMd5))
                {
                    request.ProgressDic[r.FileMd5].StateMsg = "校验中";
                    //request.ProgressDic.Remove(r.FileMd5);
                }
#if DEBUG
                Console.WriteLine("Normal file send finished,prepare to check fileMD5");
#endif
                context.State = new StateFileExist();//检查文件长度是否相等或超过。PS:可能存在陷入无限死循环的隐患,调试时注意
                return(context.Request(request));
            }

            try
            {
                using (var fs = File.OpenWrite(request.WorkingPath))
                {
                    //在文件未传输完成时,持续写入文件
                    using (BinaryWriter bs = new BinaryWriter(fs))
                    {
                        //Console.WriteLine($"seekoffset{r.SeekOffset},index={r.BlockIndex},length={r.BlockData.Length}");
                        bs.Seek((int)r.SeekOffset, SeekOrigin.Begin);
                        bs.Write(r.BlockData);
                        responsed.RemoteStreamPosition = fs.Position;
                    }
                }
                var progress = request.ProgressDic[r.FileMd5];
                progress.MaxValue      = r.BlockCount;
                progress.ProgressValue = r.BlockIndex;
                progress.Title         = r.FileName;
                progress.StateMsg      = "传输中";

                try
                {
                    request?.ReceiveProgressHandler?.OnRecieving(r.FileMd5);
                    //PubSubEvents.Singleton.Publish(new FileReceiveProgressChangedEvent() { ProgressMsg = request.ProgressDic[r.FileMd5] });
                }
                catch
                {
                    // ignored
                }
            }
            catch (Exception e)
            {
#if DEBUG
                Console.WriteLine(e);
#endif
                responsed.IsError = true;
                responsed.ErrMsg  = e.Message;
            }
            return(responsed);
        }
        public override FileTransferResponsed Handle(ContextRequest request, FileWriteHandleContext context)
        {
            var r = request.FileRequest;

            if (!request.ProgressDic.ContainsKey(r.FileMd5))
            {
                var progress = new ProgressMessage();
                request.ProgressDic.Add(r.FileMd5, progress);

                try
                {
                    request?.ReceiveProgressHandler?.OnReceiveStart(r.FileMd5, progress);
                }
                catch
                {
                    // ignored
                }
            }

            //若文件存在,则进入文件存在状态
            if (File.Exists(request.WorkingPath))
            {
                context.State = new StateFileExist();
                return(context.Request(request));
            }

            FileTransferResponsed responsed = new FileTransferResponsed(request.FileRequest);

            try
            {
                //创建文件并写入第一块数据
                using (var fs = new FileStream(request.WorkingPath, FileMode.Create, FileAccess.Write))
                {
                    var data = request.FileRequest.BlockData;
                    fs.Write(data, 0, data.Length);
                    responsed.RemoteStreamPosition = fs.Position;
                }
                //TODO : 将Block的信息存起来,最好把每个Block的MD5值存起来,方便使用本地对比,而不是连接远程对比。或从远程下载BLock信息,再在本地读取,PS:内存也可。
            }
            catch (Exception e)
            {
#if DEBUG
                Console.WriteLine(e);
#endif
                responsed.IsError = true;
                responsed.ErrMsg  = e.Message;
            }
            context.State = new StateFileNormalTransfer();
            return(responsed);
        }
        public override FileTransferResponsed Handle(ContextRequest request, FileWriteHandleContext context)
        {
            var r = request.FileRequest;

            //Console.WriteLine("StateFileLengthEqual");
            var fs = request.WorkingStream;
            //bug : filestream appeared that has been closed

            string md5      = fs.CanRead ? Md5.GetMd5WithFileStream(fs, fs.Position) : Md5.GetMd5WithFilePath(request.WorkingPath);
            var    progress = request.ProgressDic[r.FileMd5];
            FileTransferResponsed responsed = new FileTransferResponsed(request.FileRequest)
            {
                IsSendingOver      = true,
                FileMd5CheckResult = md5 == request.FileRequest.FileMd5
                                     //文件长度相等,则视为已传输完毕
            };

            if (responsed.FileMd5CheckResult)
            {
                fs.Close();
                var path = FileNameTools.GetDownloadedFullPath(request.WorkingPath);
                File.Move(request.WorkingPath, path);//modify filename

                progress.ProgressValue = progress.MaxValue;
                progress.StateMsg      = "校验成功!";
                try
                {
                    request?.ReceiveProgressHandler?.OnReceiveEnd(r.FileMd5, true);
                    //PubSubEvents.Singleton.Publish(new FileReceiveProgressCompleteEvent() { IsChecked = true,FileName = r.FileName });
                }
                catch
                {
                    // ignored
                }
            }
            else
            {
                request?.ReceiveProgressHandler?.OnReceiveEnd(r.FileMd5, false);
                progress.StateMsg = "校验失败!正在重新检查,请耐心等待。";
                //PubSubEvents.Singleton.GetEvent<FileReceiveProgressCompleteEvent>().Publish(new FileReceiveProgressCompleteEvent() { IsChecked = false, FileName = r.FileName });

                context.State = new StateFileNormalTransfer();//等待单个Block文件写入
            }
            return(responsed);
        }
        /// <summary>
        /// 检查是否处于断点续传状态
        /// </summary>
        /// <param name="responsed"></param>
        /// <param name="request"></param>
        /// <param name="info"></param>
        /// <param name="fsPosition"></param>
        /// <param name="positionOffset"></param>
        /// <param name="sendBlockSize"></param>
        private void OfflineReSendCheck(FileTransferResponsed responsed, FileTransferRequest request, FileBlockInfo info, long fsPosition, ref long positionOffset, ref int sendBlockSize)
        {
            if (responsed.RemoteStreamPosition == fsPosition)
            {
                request.BlockIndex++;
            }
            else
            {
                int  rBlockIndex = 0;
                long rPosition   = 0;
                ClacBlockIndex(info, responsed.RemoteStreamPosition, out rBlockIndex, out rPosition);
                request.BlockIndex = rBlockIndex;
                positionOffset     = rPosition;
            }

            if (info.BlockSize > info.FileLength - positionOffset)
            {
                sendBlockSize = (int)(info.FileLength - positionOffset);
            }
        }
Example #5
0
        public override FileTransferResponsed Handle(ContextRequest request, FileWriteHandleContext context)
        {
            long fsLength;
            FileTransferResponsed responsed;

            using (request.WorkingStream = File.Open(request.WorkingPath, FileMode.Open, FileAccess.ReadWrite))
            {
                fsLength = request.WorkingStream.Length;
                if (fsLength > request.FileRequest.FileSize)
                {
                    context.State = new StateFileLengthOutRange();
                    responsed     = context.Request(request);
                }
                else if (fsLength == request.FileRequest.FileSize)
                {
                    context.State = new StateFileLengthEqual();
                    responsed     = context.Request(request);
                }
                else//文件实际长度既不大于也不等于远程端文件长度时
                {
                    context.State = new StateFileNormalTransfer();//若检查全部通过,则下一个状态是普通传输文件状态

                    if (fsLength >= request.FileRequest.EachBlockSize)//返回文件在倒数第2个Block时的offset,让远程端从该处发送对应Block数据,然后进入普通文件传输状态
                    {
                        var  fRequest = request.FileRequest;
                        long position = ((fsLength / fRequest.EachBlockSize) - 1) * fRequest.EachBlockSize;

                        responsed = new FileTransferResponsed(request.FileRequest);
                        responsed.RemoteStreamPosition = position;
                    }
                    else//若文件长度小于区块长度,则直接按普通方式写入文件,此时远程SeekOffset应为0
                    {
                        request.WorkingStream.Close();//防止正常写入文件时触发文件被占用异常
                        responsed = context.Request(request);
                    }
                }
            }
            return(responsed);//保证FileStream被Using释放后才return
        }
 /// <summary>
 /// 根据反馈,重发文件
 /// </summary>
 /// <param name="path"></param>
 /// <param name="fileBlockInfo"></param>
 /// <param name="request"></param>
 /// <param name="checkResponsed"></param>
 private bool ReSendFile(string path, FileBlockInfo fileBlockInfo, FileTransferRequest request, FileTransferResponsed checkResponsed)
 {
     return(ReSendFile(path, _fileStreamDic[path], fileBlockInfo, request, checkResponsed));
 }
        /// <summary>
        /// 根据反馈结果,重发文件
        /// </summary>
        /// <param name="path"></param>
        /// <param name="fs"></param>
        /// <param name="fileBlockInfo"></param>
        /// <param name="request"></param>
        /// <param name="checkResponsed"></param>
        public bool ReSendFile(string path, FileStream fs, FileBlockInfo fileBlockInfo, FileTransferRequest request, FileTransferResponsed checkResponsed)
        {
            int resendCountOut = 0;

            while (!checkResponsed.FileMd5CheckResult && resendCountOut < 3)//最多重发三次
            {
#if DEBUG
                Console.WriteLine("ReSending File, count " + resendCountOut);
#endif
                //MD5检查失败重发
                var blockMsgList = ClacFileEachBlockMd5(fileBlockInfo, fs);

                if (blockMsgList.Count != fileBlockInfo.BlockCount)
                {
                    throw new Exception("校准MD5时,Block数量计算错误!");
                }
                int size = request.EachBlockSize;
                request.IsSendingOver = false;
                for (int i = 0; i < blockMsgList.Count; i++)
                {
                    var blockCheck = _sendAdapter.UpdateFileBlockMessage(blockMsgList[i]);
                    if (blockCheck.IsError)
                    {
                        if (i == blockMsgList.Count - 1)
                        {
                            size = request.LastBlockSize;
                        }
                        request.BlockIndex = i;
                        request.SeekOffset = i * fileBlockInfo.BlockSize;
                        request.BlockData  = ReadFileBytes(path, request.SeekOffset, size);
                        _sendAdapter.UpdateFileData(request);
                    }
                }
                request.IsSendingOver = true;
                checkResponsed        = _sendAdapter.UpdateFileData(request);
                resendCountOut++;
            }
            return(checkResponsed.FileMd5CheckResult);
        }
 public void HandleResponsed(FileTransferResponsed responsed)
 {
     //throw new NotImplementedException();
 }