mirror of
https://github.com/RRQM/TouchSocket.git
synced 2025-12-20 10:26:43 +08:00
替换RRQMSocket.FileTransfer代码
This commit is contained in:
@@ -1,134 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件工具类
|
||||
/// </summary>
|
||||
public static class FileBaseTool
|
||||
{
|
||||
#region Methods
|
||||
|
||||
internal static void SaveProgressBlockCollection(RRQMStream stream, ProgressBlockCollection blocks)
|
||||
{
|
||||
if (stream.RRQMFileStream != null && stream.RRQMFileStream.CanWrite)
|
||||
{
|
||||
stream.RRQMFileStream.Position = 0;
|
||||
byte[] dataBuffer = SerializeConvert.RRQMBinarySerialize(PBCollectionTemp.GetFromProgressBlockCollection(blocks), true);
|
||||
stream.RRQMFileStream.Write(dataBuffer, 0, dataBuffer.Length);
|
||||
stream.RRQMFileStream.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool WriteFile(RRQMStream stream, out string mes, long streamPosition, byte[] buffer, int offset, int length)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (stream != null && stream.TempFileStream.CanWrite)
|
||||
{
|
||||
stream.TempFileStream.Position = streamPosition;
|
||||
stream.TempFileStream.Write(buffer, offset, length);
|
||||
stream.TempFileStream.Flush();
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
mes = "流不可写";
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mes = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static int blockCount = 100;
|
||||
|
||||
/// <summary>
|
||||
/// 分块数量
|
||||
/// </summary>
|
||||
public static int BlockCount
|
||||
{
|
||||
get { return blockCount; }
|
||||
set
|
||||
{
|
||||
if (value < 10)
|
||||
{
|
||||
value = 10;
|
||||
}
|
||||
blockCount = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal static ProgressBlockCollection GetProgressBlockCollection(UrlFileInfo urlFileInfo, bool breakpointResume)
|
||||
{
|
||||
ProgressBlockCollection blocks = new ProgressBlockCollection();
|
||||
blocks.UrlFileInfo = urlFileInfo;
|
||||
long position = 0;
|
||||
if (breakpointResume && urlFileInfo.FileLength >= blockCount)
|
||||
{
|
||||
long blockLength = (long)(urlFileInfo.FileLength / (blockCount * 1.0));
|
||||
|
||||
for (int i = 0; i < blockCount; i++)
|
||||
{
|
||||
FileProgressBlock block = new FileProgressBlock();
|
||||
block.Index = i;
|
||||
block.FileHash = urlFileInfo.FileHash;
|
||||
block.Finished = false;
|
||||
block.StreamPosition = position;
|
||||
block.UnitLength = i != (blockCount - 1) ? blockLength : urlFileInfo.FileLength - i * blockLength;
|
||||
blocks.Add(block);
|
||||
position += blockLength;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FileProgressBlock block = new FileProgressBlock();
|
||||
block.Index = 0;
|
||||
block.FileHash = urlFileInfo.FileHash;
|
||||
block.Finished = false;
|
||||
block.StreamPosition = position;
|
||||
block.UnitLength = urlFileInfo.FileLength;
|
||||
blocks.Add(block);
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
internal static bool ReadFileBytes(string path, long beginPosition, ByteBlock byteBlock, int offset, int length)
|
||||
{
|
||||
FileStream fileStream = TransferFileStreamDic.GetFileStream(path);
|
||||
|
||||
fileStream.Position = beginPosition;
|
||||
|
||||
if (byteBlock.Buffer.Length < length + offset)
|
||||
{
|
||||
byteBlock.SetBuffer(new byte[length + offset]);
|
||||
}
|
||||
|
||||
int r = fileStream.Read(byteBlock.Buffer, offset, length);
|
||||
if (r == length)
|
||||
{
|
||||
byteBlock.Position = offset + length;
|
||||
byteBlock.SetLength(offset + length);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
@@ -25,11 +25,16 @@ namespace RRQMSocket.FileTransfer
|
||||
/// <summary>
|
||||
/// 文件流位置
|
||||
/// </summary>
|
||||
public long StreamPosition { get; internal set; }
|
||||
public long Position { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件哈希值
|
||||
/// 文件块长度
|
||||
/// </summary>
|
||||
public string FileHash { get; internal set; }
|
||||
public long UnitLength { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 请求状态
|
||||
/// </summary>
|
||||
public RequestStatus RequestStatus { get; internal set; }
|
||||
}
|
||||
}
|
||||
80
RRQMSocket.FileTransfer/Common/FileHashGenerator.cs
Normal file
80
RRQMSocket.FileTransfer/Common/FileHashGenerator.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.IO;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件Hash校验
|
||||
/// </summary>
|
||||
public static class FileHashGenerator
|
||||
{
|
||||
private static FileHashType fileCheckType;
|
||||
|
||||
/// <summary>
|
||||
/// 文件
|
||||
/// </summary>
|
||||
public static FileHashType FileCheckType
|
||||
{
|
||||
get { return fileCheckType; }
|
||||
set { fileCheckType = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件Hash
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetFileHash(string path)
|
||||
{
|
||||
using (FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read))
|
||||
{
|
||||
return GetFileHash(fileStream);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件Hash
|
||||
/// </summary>
|
||||
/// <param name="fileStream"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetFileHash(FileStream fileStream)
|
||||
{
|
||||
HashAlgorithm hash;
|
||||
switch (fileCheckType)
|
||||
{
|
||||
case FileHashType.MD5:
|
||||
hash = MD5.Create();
|
||||
break;
|
||||
|
||||
case FileHashType.SHA1:
|
||||
hash = SHA1.Create();
|
||||
break;
|
||||
|
||||
case FileHashType.SHA256:
|
||||
hash = SHA256.Create();
|
||||
break;
|
||||
|
||||
case FileHashType.SHA512:
|
||||
hash = SHA512.Create();
|
||||
break;
|
||||
|
||||
default:
|
||||
hash = null;
|
||||
break;
|
||||
}
|
||||
return FileControler.GetStreamHash(fileStream, hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件信息基类
|
||||
/// </summary>
|
||||
public class FileInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件大小
|
||||
/// </summary>
|
||||
public long FileLength { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// </summary>
|
||||
public string FilePath { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件哈希值
|
||||
/// </summary>
|
||||
public string FileHash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件标志
|
||||
/// </summary>
|
||||
public string Flag { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 复制
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
public void Copy(FileInfo fileInfo)
|
||||
{
|
||||
this.FileHash = fileInfo.FileHash;
|
||||
this.FileLength = fileInfo.FileLength;
|
||||
this.FileName = fileInfo.FileName;
|
||||
this.FilePath = fileInfo.FilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
250
RRQMSocket.FileTransfer/Common/FileStreamPool.cs
Normal file
250
RRQMSocket.FileTransfer/Common/FileStreamPool.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.Exceptions;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件流池
|
||||
/// </summary>
|
||||
public static class FileStreamPool
|
||||
{
|
||||
internal static ConcurrentDictionary<string, RRQMStream> pathStream = new ConcurrentDictionary<string, RRQMStream>();
|
||||
private readonly static object locker = new object();
|
||||
private static ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();
|
||||
|
||||
internal static bool CheckAllFileBlockFinished(string path)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (!pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (stream.StreamType == StreamOperationType.Read)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
foreach (var block in stream.Blocks)
|
||||
{
|
||||
if (block.RequestStatus != RequestStatus.Finished)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DisposeReadStream(string path)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
if (Interlocked.Decrement(ref stream.reference) == 0)
|
||||
{
|
||||
if (pathStream.TryRemove(path, out stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static void DisposeWriteStream(string path, bool finished)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
if (Interlocked.Decrement(ref stream.reference) == 0)
|
||||
{
|
||||
if (pathStream.TryRemove(path, out stream))
|
||||
{
|
||||
if (finished)
|
||||
{
|
||||
stream.FinishStream();
|
||||
}
|
||||
else
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool GetFreeFileBlock(string path, out FileBlock fileBlock, out string mes)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (!pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
mes = "没有此路径的写入信息";
|
||||
fileBlock = null;
|
||||
return false;
|
||||
}
|
||||
if (stream.StreamType == StreamOperationType.Read)
|
||||
{
|
||||
mes = "该路径的流为只读";
|
||||
fileBlock = null;
|
||||
return false;
|
||||
}
|
||||
foreach (var block in stream.Blocks)
|
||||
{
|
||||
if (block.RequestStatus == RequestStatus.Hovering)
|
||||
{
|
||||
block.RequestStatus = RequestStatus.InProgress;
|
||||
fileBlock = block;
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
fileBlock = null;
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool LoadReadStream(ref UrlFileInfo urlFileInfo, out string mes)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (pathStream.TryGetValue(urlFileInfo.FilePath, out stream))
|
||||
{
|
||||
Interlocked.Increment(ref stream.reference);
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (RRQMStream.CreateReadStream(out stream, ref urlFileInfo, out mes))
|
||||
{
|
||||
Interlocked.Increment(ref stream.reference);
|
||||
pathStream.TryAdd(urlFileInfo.FilePath, stream);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool LoadWriteStream(ref ProgressBlockCollection blocks, bool onlySearch, out string mes)
|
||||
{
|
||||
RRQMStream stream;
|
||||
string rrqmPath = blocks.UrlFileInfo.SaveFullPath + ".rrqm";
|
||||
if (!pathStream.TryGetValue(rrqmPath, out stream))
|
||||
{
|
||||
if (RRQMStream.CreateWriteStream(out stream, ref blocks, out mes))
|
||||
{
|
||||
Interlocked.Increment(ref stream.reference);
|
||||
mes = null;
|
||||
return pathStream.TryAdd(rrqmPath, stream);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (onlySearch)
|
||||
{
|
||||
blocks = stream.Blocks;
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
mes = "该文件流正在被其他客户端拥有";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool ReadFile(string path, out string mes, long beginPosition, ByteBlock byteBlock, int offset, int length)
|
||||
{
|
||||
lockSlim.EnterReadLock();
|
||||
try
|
||||
{
|
||||
if (pathStream.TryGetValue(path, out RRQMStream stream))
|
||||
{
|
||||
stream.FileStream.Position = beginPosition;
|
||||
|
||||
if (byteBlock.Buffer.Length < length + offset)
|
||||
{
|
||||
byteBlock.SetBuffer(new byte[length + offset]);
|
||||
}
|
||||
|
||||
int r = stream.FileStream.Read(byteBlock.Buffer, offset, length);
|
||||
if (r == length)
|
||||
{
|
||||
byteBlock.Position = offset + length;
|
||||
byteBlock.SetLength(offset + length);
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
mes = "没有找到该路径下的流文件";
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mes = ex.Message;
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
lockSlim.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SaveProgressBlockCollection(string path)
|
||||
{
|
||||
RRQMStream stream;
|
||||
if (pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
stream.SaveProgressBlockCollection();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new RRQMException("没有找到该路径下的流文件");
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool WriteFile(string path, out string mes, out RRQMStream stream, long streamPosition, byte[] buffer, int offset, int length)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pathStream.TryGetValue(path, out stream))
|
||||
{
|
||||
stream.FileStream.Position = streamPosition;
|
||||
stream.FileStream.Write(buffer, offset, length);
|
||||
stream.FileStream.Flush();
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
mes = "未找到该路径下的流";
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mes = ex.Message;
|
||||
stream = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Exceptions;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件传输错误码映射
|
||||
/// </summary>
|
||||
public class FileTransferErrorExceptionMapping : ErrorExceptionMapping
|
||||
{
|
||||
private static FileTransferErrorExceptionMapping _instance = new FileTransferErrorExceptionMapping();
|
||||
|
||||
/// <summary>
|
||||
/// 默认实例
|
||||
/// </summary>
|
||||
public static FileTransferErrorExceptionMapping Default { get => _instance; }
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ namespace RRQMSocket.FileTransfer
|
||||
/// <summary>
|
||||
/// 块集合
|
||||
/// </summary>
|
||||
public List<FileProgressBlock> Blocks { get; internal set; }
|
||||
public List<FileBlock> Blocks { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 从文件块转换
|
||||
@@ -41,7 +41,7 @@ namespace RRQMSocket.FileTransfer
|
||||
}
|
||||
PBCollectionTemp collectionTemp = new PBCollectionTemp();
|
||||
collectionTemp.UrlFileInfo = progressBlocks.UrlFileInfo;
|
||||
collectionTemp.Blocks = new List<FileProgressBlock>();
|
||||
collectionTemp.Blocks = new List<FileBlock>();
|
||||
collectionTemp.Blocks.AddRange(progressBlocks);
|
||||
return collectionTemp;
|
||||
}
|
||||
|
||||
@@ -18,13 +18,31 @@ namespace RRQMSocket.FileTransfer
|
||||
/// <summary>
|
||||
/// 文件进度块集合
|
||||
/// </summary>
|
||||
public class ProgressBlockCollection : ReadOnlyList<FileProgressBlock>
|
||||
public class ProgressBlockCollection : ReadOnlyList<FileBlock>
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件信息
|
||||
/// </summary>
|
||||
public UrlFileInfo UrlFileInfo { get; internal set; }
|
||||
|
||||
private static int blockLength = 1024 * 1024 * 10;
|
||||
|
||||
/// <summary>
|
||||
/// 分块长度,min=1024*1024*5
|
||||
/// </summary>
|
||||
public static int BlockLength
|
||||
{
|
||||
get { return blockLength; }
|
||||
set
|
||||
{
|
||||
if (value < 1024 * 1024 * 5)
|
||||
{
|
||||
value = 1024 * 1024 * 5;
|
||||
}
|
||||
blockLength = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存
|
||||
/// </summary>
|
||||
@@ -63,5 +81,26 @@ namespace RRQMSocket.FileTransfer
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
internal static ProgressBlockCollection CreateProgressBlockCollection(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
ProgressBlockCollection blocks = new ProgressBlockCollection();
|
||||
blocks.UrlFileInfo = urlFileInfo;
|
||||
long position = 0;
|
||||
long surLength = urlFileInfo.FileLength;
|
||||
int index = 0;
|
||||
while (surLength > 0)
|
||||
{
|
||||
FileBlock block = new FileBlock();
|
||||
block.Index = index++;
|
||||
block.RequestStatus = RequestStatus.Hovering;
|
||||
block.Position = position;
|
||||
block.UnitLength = surLength > blockLength ? blockLength : surLength;
|
||||
blocks.Add(block);
|
||||
position += block.UnitLength;
|
||||
surLength -= block.UnitLength;
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,115 +11,147 @@
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.Serialization;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
internal class RRQMStream : IDisposable
|
||||
internal class RRQMStream
|
||||
{
|
||||
internal static ConcurrentDictionary<string, RRQMStream> pathAndStream = new ConcurrentDictionary<string, RRQMStream>();
|
||||
|
||||
internal static RRQMStream GetRRQMStream(ref ProgressBlockCollection blocks, bool restart, bool breakpoint)
|
||||
{
|
||||
string rrqmPath = blocks.UrlFileInfo.FilePath + ".rrqm";
|
||||
string tempPath = blocks.UrlFileInfo.FilePath + ".temp";
|
||||
|
||||
if (pathAndStream.TryRemove(blocks.UrlFileInfo.FilePath, out RRQMStream rrqmStream))
|
||||
{
|
||||
rrqmStream.Dispose();
|
||||
}
|
||||
RRQMStream stream = new RRQMStream();
|
||||
pathAndStream.TryAdd(blocks.UrlFileInfo.FilePath, stream);
|
||||
stream.fileInfo = blocks.UrlFileInfo;
|
||||
|
||||
if (File.Exists(rrqmPath) && File.Exists(tempPath) && !restart && breakpoint)
|
||||
{
|
||||
PBCollectionTemp readBlocks = SerializeConvert.RRQMBinaryDeserialize<PBCollectionTemp>(File.ReadAllBytes(rrqmPath));
|
||||
if (readBlocks.UrlFileInfo != null && blocks.UrlFileInfo != null)
|
||||
{
|
||||
if (readBlocks.UrlFileInfo.FileHash != null && blocks.UrlFileInfo.FileHash != null && readBlocks.UrlFileInfo.FileHash == blocks.UrlFileInfo.FileHash)
|
||||
{
|
||||
stream.tempFileStream = new FileStream(tempPath, FileMode.Open, FileAccess.ReadWrite);
|
||||
stream.rrqmFileStream = new FileStream(rrqmPath, FileMode.Open, FileAccess.ReadWrite);
|
||||
stream.blocks = blocks = readBlocks.ToPBCollection();
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (File.Exists(rrqmPath))
|
||||
{
|
||||
File.Delete(rrqmPath);
|
||||
}
|
||||
if (File.Exists(tempPath))
|
||||
{
|
||||
File.Delete(tempPath);
|
||||
}
|
||||
if (breakpoint)
|
||||
{
|
||||
byte[] dataBuffer = SerializeConvert.RRQMBinarySerialize(PBCollectionTemp.GetFromProgressBlockCollection(blocks), true);
|
||||
stream.rrqmFileStream = new FileStream(rrqmPath, FileMode.Create, FileAccess.ReadWrite);
|
||||
stream.rrqmFileStream.Write(dataBuffer, 0, dataBuffer.Length);
|
||||
stream.rrqmFileStream.Flush();
|
||||
}
|
||||
|
||||
stream.tempFileStream = new FileStream(tempPath, FileMode.Create, FileAccess.ReadWrite);
|
||||
return stream;
|
||||
}
|
||||
|
||||
internal static void FileFinished(RRQMStream stream)
|
||||
{
|
||||
stream.Dispose();
|
||||
string path = stream.fileInfo.FilePath;
|
||||
if (File.Exists(path + ".rrqm"))
|
||||
{
|
||||
File.Delete(path + ".rrqm");
|
||||
}
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
if (File.Exists(path + ".temp"))
|
||||
{
|
||||
File.Move(path + ".temp", path);
|
||||
}
|
||||
}
|
||||
internal int reference;
|
||||
|
||||
private ProgressBlockCollection blocks;
|
||||
|
||||
internal FileInfo fileInfo;
|
||||
private FileStream fileStream;
|
||||
private string rrqmPath;
|
||||
private StreamOperationType streamType;
|
||||
|
||||
private FileStream rrqmFileStream;
|
||||
private UrlFileInfo urlFileInfo;
|
||||
|
||||
public FileStream RRQMFileStream
|
||||
private RRQMStream()
|
||||
{
|
||||
get { return rrqmFileStream; }
|
||||
}
|
||||
|
||||
private FileStream tempFileStream;
|
||||
public ProgressBlockCollection Blocks { get { return blocks; } }
|
||||
|
||||
public FileStream TempFileStream
|
||||
public FileStream FileStream
|
||||
{
|
||||
get { return tempFileStream; }
|
||||
get { return fileStream; }
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
public StreamOperationType StreamType
|
||||
{
|
||||
get { return streamType; }
|
||||
}
|
||||
|
||||
public UrlFileInfo UrlFileInfo { get => urlFileInfo; }
|
||||
|
||||
internal static bool CreateReadStream(out RRQMStream stream, ref UrlFileInfo urlFileInfo, out string mes)
|
||||
{
|
||||
stream = new RRQMStream();
|
||||
try
|
||||
{
|
||||
stream.streamType = StreamOperationType.Read;
|
||||
stream.fileStream = File.OpenRead(urlFileInfo.FilePath);
|
||||
urlFileInfo.FileLength = stream.fileStream.Length;
|
||||
stream.urlFileInfo = urlFileInfo;
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
stream.Dispose();
|
||||
stream = null;
|
||||
mes = ex.Message;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool CreateWriteStream(out RRQMStream stream, ref ProgressBlockCollection blocks, out string mes)
|
||||
{
|
||||
stream = new RRQMStream();
|
||||
stream.rrqmPath = blocks.UrlFileInfo.SaveFullPath + ".rrqm";
|
||||
stream.urlFileInfo = blocks.UrlFileInfo;
|
||||
stream.streamType = StreamOperationType.Write;
|
||||
try
|
||||
{
|
||||
if (blocks.UrlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume) && File.Exists(stream.rrqmPath))
|
||||
{
|
||||
stream.fileStream = new FileStream(stream.rrqmPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
|
||||
int blocksLength = (int)(stream.fileStream.Length - blocks.UrlFileInfo.FileLength);
|
||||
if (blocksLength > 0)
|
||||
{
|
||||
stream.fileStream.Position = blocks.UrlFileInfo.FileLength;
|
||||
byte[] buffer = new byte[blocksLength];
|
||||
stream.fileStream.Read(buffer, 0, buffer.Length);
|
||||
try
|
||||
{
|
||||
PBCollectionTemp readBlocks = SerializeConvert.RRQMBinaryDeserialize<PBCollectionTemp>(buffer);
|
||||
if (readBlocks.UrlFileInfo != null && blocks.UrlFileInfo != null && readBlocks.UrlFileInfo.FileHash != null)
|
||||
{
|
||||
if (readBlocks.UrlFileInfo.FileHash == blocks.UrlFileInfo.FileHash)
|
||||
{
|
||||
stream.blocks = blocks = readBlocks.ToPBCollection();
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
stream.fileStream.Dispose();
|
||||
}
|
||||
stream.blocks = blocks;
|
||||
if (File.Exists(stream.rrqmPath))
|
||||
{
|
||||
File.Delete(stream.rrqmPath);
|
||||
}
|
||||
stream.fileStream = new FileStream(stream.rrqmPath, FileMode.Create, FileAccess.ReadWrite);
|
||||
stream.SaveProgressBlockCollection();
|
||||
mes = null;
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
mes = ex.Message;
|
||||
stream.Dispose();
|
||||
stream = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
internal bool FinishStream()
|
||||
{
|
||||
this.fileStream.SetLength(this.urlFileInfo.FileLength);
|
||||
this.fileStream.Flush();
|
||||
UrlFileInfo info = this.urlFileInfo;
|
||||
this.Dispose();
|
||||
if (File.Exists(info.SaveFullPath))
|
||||
{
|
||||
File.Delete(info.SaveFullPath);
|
||||
}
|
||||
File.Move(info.SaveFullPath + ".rrqm", info.SaveFullPath);
|
||||
return true;
|
||||
}
|
||||
|
||||
internal void Dispose()
|
||||
{
|
||||
string path = this.fileInfo.FilePath;
|
||||
pathAndStream.TryRemove(path, out _);
|
||||
this.blocks = null;
|
||||
if (this.rrqmFileStream != null)
|
||||
this.urlFileInfo = null;
|
||||
if (this.fileStream != null)
|
||||
{
|
||||
this.rrqmFileStream.Dispose();
|
||||
this.rrqmFileStream = null;
|
||||
}
|
||||
if (this.tempFileStream != null)
|
||||
{
|
||||
this.tempFileStream.Dispose();
|
||||
this.tempFileStream = null;
|
||||
this.fileStream.Dispose();
|
||||
this.fileStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
internal void SaveProgressBlockCollection()
|
||||
{
|
||||
byte[] dataBuffer = SerializeConvert.RRQMBinarySerialize(PBCollectionTemp.GetFromProgressBlockCollection(blocks), true);
|
||||
this.fileStream.Position = this.urlFileInfo.FileLength;
|
||||
this.fileStream.WriteAsync(dataBuffer, 0, dataBuffer.Length);
|
||||
this.fileStream.Flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,71 +9,86 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.IO;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/*
|
||||
若汝棋茗
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// 传输文件Hash暂存字典
|
||||
/// </summary>
|
||||
public static class TransferFileHashDictionary
|
||||
{
|
||||
private static ConcurrentDictionary<string, FileInfo> filePathAndInfo = new ConcurrentDictionary<string, FileInfo>();
|
||||
private static ConcurrentDictionary<string, UrlFileInfo> fileHashAndInfo = new ConcurrentDictionary<string, UrlFileInfo>();
|
||||
private static ConcurrentDictionary<string, UrlFileInfo> filePathAndInfo = new ConcurrentDictionary<string, UrlFileInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// 字典存储文件Hash的最大数量,默认为5000
|
||||
/// 字典存储文件Hash的最大数量,默认为10000
|
||||
/// </summary>
|
||||
public static int MaxCount { get; set; } = 5000;
|
||||
public static int MaxCount { get; set; } = 10000;
|
||||
|
||||
/// <summary>
|
||||
/// 添加文件信息
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
public static void AddFile(string filePath)
|
||||
/// <param name="breakpointResume"></param>
|
||||
/// <returns></returns>
|
||||
public static UrlFileInfo AddFile(string filePath, bool breakpointResume = true)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
FileInfo fileInfo = new FileInfo();
|
||||
UrlFileInfo urlFileInfo = new UrlFileInfo();
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
fileInfo.FilePath = filePath;
|
||||
fileInfo.FileLength = stream.Length;
|
||||
fileInfo.FileName = Path.GetFileName(filePath);
|
||||
fileInfo.FileHash = FileControler.GetStreamHash(stream);
|
||||
urlFileInfo.FilePath = filePath;
|
||||
urlFileInfo.FileLength = stream.Length;
|
||||
urlFileInfo.FileName = Path.GetFileName(filePath);
|
||||
if (breakpointResume)
|
||||
{
|
||||
urlFileInfo.FileHash = FileHashGenerator.GetFileHash(stream);
|
||||
}
|
||||
}
|
||||
AddFile(fileInfo);
|
||||
AddFile(urlFileInfo);
|
||||
return urlFileInfo;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加文件信息
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
public static void AddFile(FileInfo fileInfo)
|
||||
/// <param name="urlFileInfo"></param>
|
||||
public static void AddFile(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
if (fileInfo == null)
|
||||
if (urlFileInfo == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
filePathAndInfo.AddOrUpdate(fileInfo.FilePath, fileInfo, (key, oldValue) =>
|
||||
filePathAndInfo.AddOrUpdate(urlFileInfo.FilePath, urlFileInfo, (key, oldValue) =>
|
||||
{
|
||||
return fileInfo;
|
||||
return urlFileInfo;
|
||||
});
|
||||
|
||||
if (!string.IsNullOrEmpty(urlFileInfo.FileHash))
|
||||
{
|
||||
fileHashAndInfo.AddOrUpdate(urlFileInfo.FileHash, urlFileInfo, (key, oldValue) =>
|
||||
{
|
||||
return urlFileInfo;
|
||||
});
|
||||
}
|
||||
|
||||
if (filePathAndInfo.Count > MaxCount)
|
||||
{
|
||||
foreach (var item in filePathAndInfo.Keys)
|
||||
{
|
||||
FileInfo info;
|
||||
if (filePathAndInfo.TryRemove(item, out info))
|
||||
if (filePathAndInfo.TryRemove(item, out _))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fileHashAndInfo.Count > MaxCount)
|
||||
{
|
||||
foreach (var item in fileHashAndInfo.Keys)
|
||||
{
|
||||
if (fileHashAndInfo.TryRemove(item, out _))
|
||||
{
|
||||
break;
|
||||
}
|
||||
@@ -93,6 +108,84 @@ namespace RRQMSocket.FileTransfer
|
||||
filePathAndInfo.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件信息
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="urlFileInfo"></param>
|
||||
/// <param name="breakpointResume"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetFileInfo(string filePath, out UrlFileInfo urlFileInfo, bool breakpointResume)
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (filePathAndInfo.ContainsKey(filePath))
|
||||
{
|
||||
urlFileInfo = filePathAndInfo[filePath];
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
if (urlFileInfo.FileLength == stream.Length)
|
||||
{
|
||||
if (breakpointResume && urlFileInfo.FileHash == null)
|
||||
{
|
||||
urlFileInfo.FileHash = FileHashGenerator.GetFileHash(stream);
|
||||
AddFile(urlFileInfo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过FileHash获取文件信息
|
||||
/// </summary>
|
||||
/// <param name="fileHash"></param>
|
||||
/// <param name="urlFileInfo"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetFileInfoFromHash(string fileHash, out UrlFileInfo urlFileInfo)
|
||||
{
|
||||
if (fileHashAndInfo == null)
|
||||
{
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrEmpty(fileHash))
|
||||
{
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fileHashAndInfo.TryGetValue(fileHash, out urlFileInfo))
|
||||
{
|
||||
if (urlFileInfo.FileHash == fileHash)
|
||||
{
|
||||
if (File.Exists(urlFileInfo.FilePath))
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(urlFileInfo.FilePath))
|
||||
{
|
||||
if (urlFileInfo.FileLength == stream.Length)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
urlFileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除
|
||||
/// </summary>
|
||||
@@ -106,84 +199,5 @@ namespace RRQMSocket.FileTransfer
|
||||
}
|
||||
return filePathAndInfo.TryRemove(filePath, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件信息
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="breakpointResume"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetFileInfo(string filePath, out FileInfo fileInfo, bool breakpointResume)
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (filePathAndInfo.ContainsKey(filePath))
|
||||
{
|
||||
fileInfo = filePathAndInfo[filePath];
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
if (fileInfo.FileLength == stream.Length)
|
||||
{
|
||||
if (breakpointResume && fileInfo.FileHash == null)
|
||||
{
|
||||
fileInfo.FileHash = FileControler.GetStreamHash(stream);
|
||||
AddFile(fileInfo);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 通过FileHash获取文件信息
|
||||
/// </summary>
|
||||
/// <param name="fileHash"></param>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <returns></returns>
|
||||
public static bool GetFileInfoFromHash(string fileHash, out FileInfo fileInfo)
|
||||
{
|
||||
if (filePathAndInfo == null)
|
||||
{
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
if (fileHash == null)
|
||||
{
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var item in filePathAndInfo.Values)
|
||||
{
|
||||
if (item.FileHash == fileHash)
|
||||
{
|
||||
if (File.Exists(item.FilePath))
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(item.FilePath))
|
||||
{
|
||||
if (item.FileLength == stream.Length)
|
||||
{
|
||||
fileInfo = item;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fileInfo = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// 此代码版权(除特别声明或在RRQMCore.XREF命名空间的代码)归作者本人若汝棋茗所有
|
||||
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权
|
||||
// CSDN博客:https://blog.csdn.net/qq_40374647
|
||||
// 哔哩哔哩视频:https://space.bilibili.com/94253567
|
||||
// Gitee源代码仓库:https://gitee.com/RRQM_Home
|
||||
// Github源代码仓库:https://github.com/RRQM
|
||||
// 交流QQ群:234762506
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
internal class TransferSetting
|
||||
{
|
||||
internal bool breakpointResume;
|
||||
internal int bufferLength;
|
||||
|
||||
internal void Serialize(ByteBlock byteBlock)
|
||||
{
|
||||
byteBlock.Write(Convert.ToByte(breakpointResume));
|
||||
byteBlock.Write(BitConverter.GetBytes(bufferLength));
|
||||
}
|
||||
|
||||
internal static TransferSetting Deserialize(byte[] buffer, int offset)
|
||||
{
|
||||
TransferSetting transferSetting = new TransferSetting();
|
||||
transferSetting.breakpointResume = BitConverter.ToBoolean(buffer, offset);
|
||||
transferSetting.bufferLength = BitConverter.ToInt32(buffer, offset + 1);
|
||||
return transferSetting;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using RRQMCore.IO;
|
||||
using System.IO;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
@@ -18,19 +17,83 @@ namespace RRQMSocket.FileTransfer
|
||||
/// <summary>
|
||||
/// 文件信息类
|
||||
/// </summary>
|
||||
public class UrlFileInfo : FileInfo
|
||||
public class UrlFileInfo
|
||||
{
|
||||
private string saveFullPath = string.Empty;
|
||||
|
||||
private int timeout = 30 * 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 文件哈希值
|
||||
/// </summary>
|
||||
public string FileHash { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件大小
|
||||
/// </summary>
|
||||
public long FileLength { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件名
|
||||
/// </summary>
|
||||
public string FileName { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件路径
|
||||
/// </summary>
|
||||
public string FilePath { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 传输标识
|
||||
/// </summary>
|
||||
public TransferFlags Flags { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 携带消息
|
||||
/// </summary>
|
||||
public string Message { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 存放目录
|
||||
/// </summary>
|
||||
public string SaveFullPath
|
||||
{
|
||||
get { return saveFullPath; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
value = string.Empty;
|
||||
}
|
||||
saveFullPath = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 超时时间,默认30*1000 ms
|
||||
/// </summary>
|
||||
public int Timeout
|
||||
{
|
||||
get { return timeout; }
|
||||
set { timeout = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求传输类型
|
||||
/// </summary>
|
||||
public TransferType TransferType { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 生成下载请求必要信息
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="restart"></param>
|
||||
/// <param name="flags"></param>
|
||||
/// <returns></returns>
|
||||
public static UrlFileInfo CreatDownload(string path, bool restart = false)
|
||||
public static UrlFileInfo CreateDownload(string path, TransferFlags flags)
|
||||
{
|
||||
UrlFileInfo fileInfo = new UrlFileInfo();
|
||||
fileInfo.FilePath = path;
|
||||
fileInfo.Restart = restart;
|
||||
fileInfo.Flags = flags;
|
||||
fileInfo.FileName = Path.GetFileName(path);
|
||||
fileInfo.TransferType = TransferType.Download;
|
||||
return fileInfo;
|
||||
@@ -40,20 +103,19 @@ namespace RRQMSocket.FileTransfer
|
||||
/// 生成上传请求必要信息
|
||||
/// </summary>
|
||||
/// <param name="path"></param>
|
||||
/// <param name="breakpointResume"></param>
|
||||
/// <param name="restart"></param>
|
||||
/// <param name="flags"></param>
|
||||
/// <returns></returns>
|
||||
public static UrlFileInfo CreatUpload(string path, bool breakpointResume, bool restart = false)
|
||||
public static UrlFileInfo CreateUpload(string path, TransferFlags flags)
|
||||
{
|
||||
UrlFileInfo fileInfo = new UrlFileInfo();
|
||||
fileInfo.TransferType = TransferType.Upload;
|
||||
using (FileStream stream = File.OpenRead(path))
|
||||
{
|
||||
fileInfo.Restart = restart;
|
||||
fileInfo.Flags = flags;
|
||||
fileInfo.FilePath = path;
|
||||
if (breakpointResume)
|
||||
if (flags.HasFlag(TransferFlags.BreakpointResume) || flags.HasFlag(TransferFlags.QuickTransfer))
|
||||
{
|
||||
fileInfo.FileHash = FileControler.GetStreamHash(stream);
|
||||
fileInfo.FileHash = FileHashGenerator.GetFileHash(stream);
|
||||
}
|
||||
fileInfo.FileLength = stream.Length;
|
||||
fileInfo.FileName = Path.GetFileName(path);
|
||||
@@ -63,57 +125,42 @@ namespace RRQMSocket.FileTransfer
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重新开始
|
||||
/// 复制
|
||||
/// </summary>
|
||||
public bool Restart { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 超时时间,默认30秒
|
||||
/// </summary>
|
||||
public int Timeout { get; set; } = 30;
|
||||
|
||||
/// <summary>
|
||||
/// 请求传输类型
|
||||
/// </summary>
|
||||
public TransferType TransferType { get; set; }
|
||||
|
||||
private string saveFolder = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 存放目录
|
||||
/// </summary>
|
||||
public string SaveFolder
|
||||
/// <param name="urlFileInfo"></param>
|
||||
public void CopyFrom(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
get { return saveFolder; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
value = string.Empty;
|
||||
}
|
||||
saveFolder = value;
|
||||
}
|
||||
this.FileHash = urlFileInfo.FileHash;
|
||||
this.FileLength = urlFileInfo.FileLength;
|
||||
this.FileName = urlFileInfo.FileName;
|
||||
this.FilePath = urlFileInfo.FilePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 比较
|
||||
/// 判断参数是否相同
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <param name="urlFileInfo"></param>
|
||||
/// <returns></returns>
|
||||
public bool Equals(UrlFileInfo fileInfo)
|
||||
public bool Equals(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
if (this.FileHash == fileInfo.FileHash)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (this.FilePath == fileInfo.FilePath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
if (urlFileInfo.FileHash != this.FileHash)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (urlFileInfo.FileLength != this.FileLength)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (urlFileInfo.FileName != this.FileName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (urlFileInfo.FilePath != this.FilePath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,14 @@ namespace RRQMSocket.FileTransfer
|
||||
/// </summary>
|
||||
public class FileClientConfig : TokenClientConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public FileClientConfig()
|
||||
{
|
||||
this.BufferLength = 64 * 1024;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 默认接收文件的存放目录
|
||||
/// </summary>
|
||||
@@ -41,22 +49,37 @@ namespace RRQMSocket.FileTransfer
|
||||
DependencyProperty.Register("ReceiveDirectory", typeof(string), typeof(FileClientConfig), string.Empty);
|
||||
|
||||
/// <summary>
|
||||
/// 单次请求超时时间 min=5,max=60 单位:秒
|
||||
/// 单次请求超时时间 min=5000,max=60*1000 ms
|
||||
/// </summary>
|
||||
public int Timeout
|
||||
{
|
||||
get { return (int)GetValue(TimeoutProperty); }
|
||||
set
|
||||
{
|
||||
value = value < 5 ? 5 : (value > 60 ? 60 : value);
|
||||
SetValue(TimeoutProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单次请求超时时间 min=5,max=60 单位:秒, 所需类型<see cref="int"/>
|
||||
/// 单次请求超时时间 min=5000,max=60*1000 ms, 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TimeoutProperty =
|
||||
DependencyProperty.Register("Timeout", typeof(int), typeof(FileClientConfig), 5);
|
||||
DependencyProperty.Register("Timeout", typeof(int), typeof(FileClientConfig), 10*1000);
|
||||
|
||||
/// <summary>
|
||||
/// 数据包尺寸
|
||||
/// </summary>
|
||||
public int PacketSize
|
||||
{
|
||||
get { return (int)GetValue(PacketSizeProperty); }
|
||||
set { SetValue(PacketSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 数据包尺寸, 所需类型<see cref="int"/>
|
||||
/// </summary>
|
||||
[RRQMCore.Range]
|
||||
public static readonly DependencyProperty PacketSizeProperty =
|
||||
DependencyProperty.Register("PacketSize", typeof(int), typeof(FileClientConfig), 1024 * 1024);
|
||||
}
|
||||
}
|
||||
@@ -19,20 +19,13 @@ namespace RRQMSocket.FileTransfer
|
||||
public class FileServiceConfig : TokenServiceConfig
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否支持断点续传
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
public bool BreakpointResume
|
||||
public FileServiceConfig()
|
||||
{
|
||||
get { return (bool)GetValue(BreakpointResumeProperty); }
|
||||
set { SetValue(BreakpointResumeProperty, value); }
|
||||
this.BufferLength = 64 * 1024;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持断点续传, 所需类型<see cref="bool"/>
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty BreakpointResumeProperty =
|
||||
DependencyProperty.Register("BreakpointResume", typeof(bool), typeof(FileServiceConfig), false);
|
||||
|
||||
/// <summary>
|
||||
/// 最大下载速度
|
||||
/// </summary>
|
||||
|
||||
@@ -12,23 +12,28 @@
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输文件
|
||||
/// 文件Hash检验类型
|
||||
/// </summary>
|
||||
public class TransferFileArgs
|
||||
public enum FileHashType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 已接收的流位置
|
||||
/// MD5
|
||||
/// </summary>
|
||||
public long StreamPosition { get; set; }
|
||||
MD5,
|
||||
|
||||
/// <summary>
|
||||
/// 接收的文件信息(不要手动更改里面任何内容)
|
||||
/// SHA1
|
||||
/// </summary>
|
||||
public FileInfo FileInfo { get; set; }
|
||||
SHA1,
|
||||
|
||||
/// <summary>
|
||||
/// 传输文件进度
|
||||
/// SHA256
|
||||
/// </summary>
|
||||
public float TransferProgressValue { get; set; }
|
||||
SHA256,
|
||||
|
||||
/// <summary>
|
||||
/// SHA512
|
||||
/// </summary>
|
||||
SHA512
|
||||
}
|
||||
}
|
||||
@@ -9,22 +9,26 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件进度块
|
||||
/// 请求状态
|
||||
/// </summary>
|
||||
public class FileProgressBlock : FileBlock
|
||||
public enum RequestStatus : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件块长度
|
||||
/// 未开始
|
||||
/// </summary>
|
||||
public long UnitLength { get; internal set; }
|
||||
Hovering,
|
||||
|
||||
/// <summary>
|
||||
/// 正在进行
|
||||
/// </summary>
|
||||
InProgress,
|
||||
|
||||
/// <summary>
|
||||
/// 完成
|
||||
/// </summary>
|
||||
public bool Finished { get; internal set; }
|
||||
Finished
|
||||
}
|
||||
}
|
||||
@@ -9,17 +9,21 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件路径事件类
|
||||
/// 流操作类型
|
||||
/// </summary>
|
||||
public class FilePathEventArgs : TransferFileMessageArgs
|
||||
public enum StreamOperationType : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取或设置目标文件的最终路径,包含文件名及文件扩展名
|
||||
/// 读
|
||||
/// </summary>
|
||||
public string TargetPath { get; set; }
|
||||
Read,
|
||||
|
||||
/// <summary>
|
||||
/// 写
|
||||
/// </summary>
|
||||
Write
|
||||
}
|
||||
}
|
||||
@@ -9,30 +9,29 @@
|
||||
// 感谢您的下载和使用
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
internal static class TransferFileStreamDic
|
||||
/// <summary>
|
||||
/// 传输标识
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum TransferFlags
|
||||
{
|
||||
private static ConcurrentDictionary<string, FileStream> readOrWriteStreamDic = new ConcurrentDictionary<string, FileStream>();
|
||||
/// <summary>
|
||||
/// 无任何标识
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
internal static FileStream GetFileStream(string path)
|
||||
{
|
||||
return readOrWriteStreamDic.GetOrAdd(path, (v) =>
|
||||
{
|
||||
return File.OpenRead(path);
|
||||
});
|
||||
}
|
||||
/// <summary>
|
||||
/// 断点续传
|
||||
/// </summary>
|
||||
BreakpointResume = 1,
|
||||
|
||||
internal static void DisposeFileStream(string path)
|
||||
{
|
||||
FileStream stream;
|
||||
if (readOrWriteStreamDic.TryRemove(path, out stream))
|
||||
{
|
||||
stream.Dispose();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 快速传输
|
||||
/// </summary>
|
||||
QuickTransfer = 2
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,6 @@ namespace RRQMSocket.FileTransfer
|
||||
/// <summary>
|
||||
/// 文件信息
|
||||
/// </summary>
|
||||
public FileInfo FileInfo { get; internal set; }
|
||||
public UrlFileInfo UrlFileInfo { get; internal set; }
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace RRQMSocket.FileTransfer
|
||||
/// <summary>
|
||||
/// 操作文件事件类
|
||||
/// </summary>
|
||||
public class FileOperationEventArgs : FilePathEventArgs
|
||||
public class FileOperationEventArgs : TransferFileMessageArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否允许操作
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace RRQMSocket.FileTransfer
|
||||
public class TransferFileMessageArgs : FileEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 错误信息
|
||||
/// 信息
|
||||
/// </summary>
|
||||
public string Message { get; internal set; }
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace RRQMSocket.FileTransfer
|
||||
/// <summary>
|
||||
/// 获取当前传输文件信息
|
||||
/// </summary>
|
||||
FileInfo TransferFileInfo { get; }
|
||||
UrlFileInfo TransferFileInfo { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输进度
|
||||
@@ -36,10 +36,5 @@ namespace RRQMSocket.FileTransfer
|
||||
/// 获取当前传输状态
|
||||
/// </summary>
|
||||
TransferStatus TransferStatus { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输文件包
|
||||
/// </summary>
|
||||
ProgressBlockCollection FileBlocks { get; }
|
||||
}
|
||||
}
|
||||
@@ -65,6 +65,10 @@ Demo:https://gitee.com/RRQM_OS/RRQMBox</Description>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RRQMSocket.RPC\RRQMSocket.RPC.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="RRQMCore">
|
||||
<HintPath>..\..\RRQMCore\RRQMCore\bin\Debug\net45\RRQMCore.dll</HintPath>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,20 +21,10 @@ namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
#region 属性
|
||||
|
||||
private bool breakpointResume;
|
||||
|
||||
private long maxDownloadSpeed;
|
||||
|
||||
private long maxUploadSpeed;
|
||||
|
||||
/// <summary>
|
||||
/// 是否支持断点续传
|
||||
/// </summary>
|
||||
public bool BreakpointResume
|
||||
{
|
||||
get { return breakpointResume; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取下载速度
|
||||
/// </summary>
|
||||
@@ -105,13 +95,12 @@ namespace RRQMSocket.FileTransfer
|
||||
/// <summary>
|
||||
/// 载入配置
|
||||
/// </summary>
|
||||
/// <param name="serverConfig"></param>
|
||||
protected override void LoadConfig(ServiceConfig serverConfig)
|
||||
/// <param name="serviceConfig"></param>
|
||||
protected override void LoadConfig(ServiceConfig serviceConfig)
|
||||
{
|
||||
base.LoadConfig(serverConfig);
|
||||
this.breakpointResume = (bool)serverConfig.GetValue(FileServiceConfig.BreakpointResumeProperty);
|
||||
this.maxDownloadSpeed = (long)serverConfig.GetValue(FileServiceConfig.MaxDownloadSpeedProperty);
|
||||
this.maxUploadSpeed = (long)serverConfig.GetValue(FileServiceConfig.MaxUploadSpeedProperty);
|
||||
base.LoadConfig(serviceConfig);
|
||||
this.maxDownloadSpeed = (long)serviceConfig.GetValue(FileServiceConfig.MaxDownloadSpeedProperty);
|
||||
this.maxUploadSpeed = (long)serviceConfig.GetValue(FileServiceConfig.MaxUploadSpeedProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -122,8 +111,6 @@ namespace RRQMSocket.FileTransfer
|
||||
protected override void OnCreateSocketCliect(FileSocketClient socketClient, CreateOption creatOption)
|
||||
{
|
||||
base.OnCreateSocketCliect(socketClient, creatOption);
|
||||
|
||||
socketClient.breakpointResume = this.BreakpointResume;
|
||||
socketClient.MaxDownloadSpeed = this.MaxDownloadSpeed;
|
||||
socketClient.MaxUploadSpeed = this.MaxUploadSpeed;
|
||||
if (creatOption.NewCreate)
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
using RRQMCore.ByteManager;
|
||||
using RRQMCore.IO;
|
||||
using RRQMCore.Log;
|
||||
using RRQMCore.Serialization;
|
||||
using RRQMSocket.RPC.RRQMRPC;
|
||||
@@ -18,6 +17,7 @@ using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace RRQMSocket.FileTransfer
|
||||
@@ -27,6 +27,40 @@ namespace RRQMSocket.FileTransfer
|
||||
/// </summary>
|
||||
public class FileSocketClient : RPCSocketClient, IFileService, IFileClient
|
||||
{
|
||||
/// <summary>
|
||||
/// 传输文件之前
|
||||
/// </summary>
|
||||
internal RRQMFileOperationEventHandler BeforeFileTransfer;
|
||||
|
||||
/// <summary>
|
||||
/// 当文件传输完成时
|
||||
/// </summary>
|
||||
internal RRQMTransferFileMessageEventHandler FinishedFileTransfer;
|
||||
|
||||
private long dataTransferLength;
|
||||
|
||||
private long maxDownloadSpeed = 1024 * 1024;
|
||||
|
||||
private long maxUploadSpeed = 1024 * 1024;
|
||||
|
||||
private long position;
|
||||
|
||||
private float progress;
|
||||
|
||||
private string rrqmPath;
|
||||
|
||||
private long speed;
|
||||
|
||||
private Stopwatch stopwatch = new Stopwatch();
|
||||
|
||||
private long tempLength;
|
||||
|
||||
private long timeTick;
|
||||
|
||||
private TransferStatus transferStatus;
|
||||
|
||||
private UrlFileInfo transferUrlFileInfo;
|
||||
|
||||
static FileSocketClient()
|
||||
{
|
||||
AddUsedProtocol(110, "同步设置");
|
||||
@@ -39,19 +73,13 @@ namespace RRQMSocket.FileTransfer
|
||||
AddUsedProtocol(117, "上传分块");
|
||||
AddUsedProtocol(118, "停止上传");
|
||||
AddUsedProtocol(119, "确认上传完成");
|
||||
AddUsedProtocol(120, "智能包调节");
|
||||
for (short i = 121; i < 200; i++)
|
||||
{
|
||||
AddUsedProtocol(i, "保留协议");
|
||||
}
|
||||
}
|
||||
|
||||
#region 属性
|
||||
|
||||
private long maxDownloadSpeed = 1024 * 1024;
|
||||
|
||||
private long maxUploadSpeed = 1024 * 1024;
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输文件包
|
||||
/// </summary>
|
||||
public ProgressBlockCollection FileBlocks { get { return fileBlocks == null ? null : fileBlocks; } }
|
||||
|
||||
/// <summary>
|
||||
/// 每秒最大下载速度(Byte),不可小于1024
|
||||
/// </summary>
|
||||
@@ -64,8 +92,7 @@ namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
value = 1024;
|
||||
}
|
||||
maxDownloadSpeed = value;
|
||||
MaxSpeedChanged(maxDownloadSpeed);
|
||||
this.maxDownloadSpeed = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,15 +108,14 @@ namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
value = 1024;
|
||||
}
|
||||
maxUploadSpeed = value;
|
||||
MaxSpeedChanged(maxUploadSpeed);
|
||||
this.maxUploadSpeed = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输文件信息
|
||||
/// </summary>
|
||||
public FileInfo TransferFileInfo { get { return fileBlocks == null ? null : fileBlocks.UrlFileInfo; } }
|
||||
public UrlFileInfo TransferFileInfo { get => this.transferUrlFileInfo; }
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前传输进度
|
||||
@@ -98,18 +124,11 @@ namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
get
|
||||
{
|
||||
if (fileBlocks == null)
|
||||
if (transferUrlFileInfo == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (fileBlocks.UrlFileInfo != null)
|
||||
{
|
||||
this.progress = fileBlocks.UrlFileInfo.FileLength > 0 ? (float)position / fileBlocks.UrlFileInfo.FileLength : 0;//计算下载完成进度
|
||||
}
|
||||
else
|
||||
{
|
||||
this.progress = 0;
|
||||
}
|
||||
this.progress = transferUrlFileInfo.FileLength > 0 ? (float)position / transferUrlFileInfo.FileLength : 0;//计算下载完成进度
|
||||
return progress <= 1 ? progress : 1;
|
||||
}
|
||||
}
|
||||
@@ -130,39 +149,10 @@ namespace RRQMSocket.FileTransfer
|
||||
/// <summary>
|
||||
/// 获取当前传输状态
|
||||
/// </summary>
|
||||
public TransferStatus TransferStatus { get; private set; }
|
||||
|
||||
#endregion 属性
|
||||
|
||||
#region 字段
|
||||
|
||||
internal bool breakpointResume;
|
||||
private bool bufferLengthChanged;
|
||||
private long dataTransferLength;
|
||||
private ProgressBlockCollection fileBlocks;
|
||||
private long position;
|
||||
private float progress;
|
||||
private long speed;
|
||||
private Stopwatch stopwatch = new Stopwatch();
|
||||
private long tempLength;
|
||||
private long timeTick;
|
||||
private RRQMStream uploadFileStream;
|
||||
|
||||
#endregion 字段
|
||||
|
||||
#region 事件
|
||||
|
||||
/// <summary>
|
||||
/// 传输文件之前
|
||||
/// </summary>
|
||||
internal RRQMFileOperationEventHandler BeforeFileTransfer;
|
||||
|
||||
/// <summary>
|
||||
/// 当文件传输完成时
|
||||
/// </summary>
|
||||
internal RRQMTransferFileMessageEventHandler FinishedFileTransfer;
|
||||
|
||||
#endregion 事件
|
||||
public TransferStatus TransferStatus
|
||||
{
|
||||
get { return transferStatus; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放资源
|
||||
@@ -170,6 +160,7 @@ namespace RRQMSocket.FileTransfer
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
this.ResetVariable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -178,8 +169,16 @@ namespace RRQMSocket.FileTransfer
|
||||
public override void Recreate()
|
||||
{
|
||||
base.Recreate();
|
||||
this.maxDownloadSpeed = 1024 * 1024;
|
||||
this.maxUploadSpeed = 1024 * 1024;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件辅助类处理其他协议
|
||||
/// </summary>
|
||||
/// <param name="procotol"></param>
|
||||
/// <param name="byteBlock"></param>
|
||||
protected virtual void FileSocketClientHandleDefaultData(short? procotol, ByteBlock byteBlock)
|
||||
{
|
||||
this.OnHandleDefaultData(procotol, byteBlock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -195,181 +194,113 @@ namespace RRQMSocket.FileTransfer
|
||||
{
|
||||
case 110:
|
||||
{
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
if (this.TransferStatus == TransferStatus.Download)
|
||||
{
|
||||
this.MaxSpeedChanged(this.maxDownloadSpeed);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.MaxSpeedChanged(this.maxUploadSpeed);
|
||||
}
|
||||
TransferSetting transferSetting = new TransferSetting();
|
||||
transferSetting.breakpointResume = this.breakpointResume;
|
||||
transferSetting.bufferLength = this.BufferLength;
|
||||
transferSetting.Serialize(returnByteBlock);
|
||||
this.bufferLengthChanged = false;
|
||||
this.InternalSend(111, returnByteBlock);
|
||||
//this.P110_SynchronizeTransferSetting();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 112:
|
||||
{
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
UrlFileInfo fileInfo = SerializeConvert.RRQMBinaryDeserialize<UrlFileInfo>(buffer, 2);
|
||||
RequestDownload(returnByteBlock, fileInfo);
|
||||
this.InternalSend(111, returnByteBlock);
|
||||
P112_RequestDownload(fileInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 113:
|
||||
{
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
DownloadBlockData(returnByteBlock, buffer);
|
||||
this.InternalSend(111, returnByteBlock.Buffer, 0, (int)returnByteBlock.Length, true);
|
||||
P113_DownloadBlockData(byteBlock);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 114:
|
||||
{
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
this.fileBlocks = null;
|
||||
this.TransferStatus = TransferStatus.None;
|
||||
returnByteBlock.Write(1);
|
||||
this.InternalSend(111, returnByteBlock);
|
||||
P114_StopDownload();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 115:
|
||||
{
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
DownloadFinished(returnByteBlock);
|
||||
this.InternalSend(111, returnByteBlock);
|
||||
P115_DownloadFinished();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 116:
|
||||
{
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
bool restart = BitConverter.ToBoolean(byteBlock.Buffer, 2);
|
||||
PBCollectionTemp blocks = SerializeConvert.RRQMBinaryDeserialize<PBCollectionTemp>(byteBlock.Buffer, 3);
|
||||
RequestUpload(returnByteBlock, blocks, restart);
|
||||
this.InternalSend(111, returnByteBlock);
|
||||
UrlFileInfo urlFileInfo = SerializeConvert.RRQMBinaryDeserialize<UrlFileInfo>(buffer, 2);
|
||||
P116_RequestUpload(urlFileInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 117:
|
||||
{
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
UploadBlockData(returnByteBlock, byteBlock);
|
||||
this.InternalSend(111, returnByteBlock);
|
||||
P117_UploadBlockData(buffer);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 118:
|
||||
{
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
StopUpload(returnByteBlock);
|
||||
this.InternalSend(111, returnByteBlock);
|
||||
P118_StopUpload();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 119:
|
||||
{
|
||||
ByteBlock returnByteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
UploadFinished(returnByteBlock);
|
||||
this.InternalSend(111, returnByteBlock);
|
||||
P119_UploadFinished();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Debug(LogType.Error, this, ex.Message, ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
returnByteBlock.Dispose();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -380,24 +311,6 @@ namespace RRQMSocket.FileTransfer
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件辅助类处理其他协议
|
||||
/// </summary>
|
||||
/// <param name="procotol"></param>
|
||||
/// <param name="byteBlock"></param>
|
||||
protected virtual void FileSocketClientHandleDefaultData(short? procotol, ByteBlock byteBlock)
|
||||
{
|
||||
this.OnHandleDefaultData(procotol, byteBlock);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当BufferLength改变值的时候
|
||||
/// </summary>
|
||||
protected override void OnBufferLengthChanged()
|
||||
{
|
||||
bufferLengthChanged = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 继承
|
||||
/// </summary>
|
||||
@@ -414,7 +327,7 @@ namespace RRQMSocket.FileTransfer
|
||||
else
|
||||
{
|
||||
//在这一秒中
|
||||
switch (this.TransferStatus)
|
||||
switch (this.transferStatus)
|
||||
{
|
||||
case TransferStatus.Upload:
|
||||
if (this.dataTransferLength > this.maxUploadSpeed)
|
||||
@@ -448,188 +361,222 @@ namespace RRQMSocket.FileTransfer
|
||||
return DateTime.Now.Ticks / 10000000;
|
||||
}
|
||||
|
||||
private void MaxSpeedChanged(long speed)
|
||||
private FileOperationEventArgs OnBeforeFileTransfer(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
if (speed < 1024 * 1024 * 50)
|
||||
FileOperationEventArgs args = new FileOperationEventArgs();
|
||||
args.UrlFileInfo = urlFileInfo;
|
||||
args.TransferType = urlFileInfo.TransferType;
|
||||
args.IsPermitOperation = true;
|
||||
if (urlFileInfo.TransferType == TransferType.Download)
|
||||
{
|
||||
this.SetBufferLength(1024 * 10);
|
||||
//下载
|
||||
urlFileInfo.FilePath = Path.GetFullPath(urlFileInfo.FilePath);
|
||||
}
|
||||
else if (speed < 1024 * 1024 * 100)
|
||||
|
||||
try
|
||||
{
|
||||
this.SetBufferLength(1024 * 64);
|
||||
this.BeforeFileTransfer?.Invoke(this, args);//触发 接收文件事件
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
this.Logger.Debug(LogType.Error, this, $"在事件{nameof(BeforeFileTransfer)}中发生异常", ex);
|
||||
}
|
||||
|
||||
if (urlFileInfo.TransferType == TransferType.Upload)
|
||||
{
|
||||
urlFileInfo.SaveFullPath = Path.GetFullPath(string.IsNullOrEmpty(urlFileInfo.SaveFullPath) ? urlFileInfo.FileName : urlFileInfo.SaveFullPath);
|
||||
this.rrqmPath = urlFileInfo.SaveFullPath + ".rrqm";
|
||||
}
|
||||
this.transferUrlFileInfo = urlFileInfo;
|
||||
return args;
|
||||
}
|
||||
|
||||
private void OnFinishedFileTransfer(TransferType transferType)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(this.transferUrlFileInfo.FileHash))
|
||||
{
|
||||
TransferFileHashDictionary.AddFile(this.transferUrlFileInfo);
|
||||
}
|
||||
TransferFileMessageArgs args = new TransferFileMessageArgs();
|
||||
args.UrlFileInfo = this.transferUrlFileInfo;
|
||||
args.TransferType = transferType;
|
||||
|
||||
if (transferType == TransferType.Download)
|
||||
{
|
||||
FileStreamPool.DisposeReadStream(this.transferUrlFileInfo.FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.SetBufferLength(1024 * 512);
|
||||
}
|
||||
}
|
||||
|
||||
#region 协议函数
|
||||
|
||||
private void DownloadBlockData(ByteBlock byteBlock, byte[] buffer)
|
||||
{
|
||||
if (this.TransferStatus != TransferStatus.Download)
|
||||
{
|
||||
byteBlock.Buffer[6] = 0;
|
||||
return;
|
||||
FileStreamPool.DisposeWriteStream(this.rrqmPath, true);
|
||||
this.rrqmPath = null;
|
||||
}
|
||||
this.transferStatus = TransferStatus.None;
|
||||
this.transferUrlFileInfo = null;
|
||||
try
|
||||
{
|
||||
long position = BitConverter.ToInt64(buffer, 2);
|
||||
long requestLength = BitConverter.ToInt64(buffer, 10);
|
||||
if (FileBaseTool.ReadFileBytes(fileBlocks.UrlFileInfo.FilePath, position, byteBlock, 7, (int)requestLength))
|
||||
{
|
||||
Speed.downloadSpeed += requestLength;
|
||||
this.position = position + requestLength;
|
||||
this.tempLength += requestLength;
|
||||
this.dataTransferLength += requestLength;
|
||||
if (this.bufferLengthChanged)
|
||||
{
|
||||
byteBlock.Buffer[6] = 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Buffer[6] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Buffer[6] = 2;
|
||||
}
|
||||
this.FinishedFileTransfer?.Invoke(this, args);
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
byteBlock.Buffer[6] = 2;
|
||||
this.Logger.Debug(LogType.Error, this, $"在事件{nameof(FinishedFileTransfer)}中发生异常", ex);
|
||||
}
|
||||
this.ResetVariable();
|
||||
}
|
||||
|
||||
private void DownloadFinished(ByteBlock byteBlock)
|
||||
private void P112_RequestDownload(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
TransferFileStreamDic.DisposeFileStream(this.fileBlocks.UrlFileInfo.FilePath);
|
||||
byteBlock.Write(1);
|
||||
FilePathEventArgs args = new FilePathEventArgs();
|
||||
args.FileInfo = this.fileBlocks.UrlFileInfo;
|
||||
this.TransferStatus = TransferStatus.None;
|
||||
args.TransferType = TransferType.Download;
|
||||
args.TargetPath = args.FileInfo.FilePath;
|
||||
this.FinishedFileTransfer?.Invoke(this, args);
|
||||
this.fileBlocks = null;
|
||||
}
|
||||
|
||||
private void RequestDownload(ByteBlock byteBlock, UrlFileInfo urlFileInfo)
|
||||
{
|
||||
FileOperationEventArgs args = new FileOperationEventArgs();
|
||||
args.FileInfo = urlFileInfo;
|
||||
args.IsPermitOperation = true;
|
||||
args.TargetPath = args.FileInfo.FilePath;
|
||||
args.TransferType = TransferType.Download;
|
||||
this.BeforeFileTransfer?.Invoke(this, args);
|
||||
|
||||
string filePath = args.TargetPath;
|
||||
FileOperationEventArgs args = OnBeforeFileTransfer(urlFileInfo);
|
||||
FileWaitResult waitResult = new FileWaitResult();
|
||||
if (!args.IsPermitOperation)
|
||||
{
|
||||
waitResult.Message = string.IsNullOrEmpty(args.Message) ? "服务器拒绝下载" : args.Message;
|
||||
waitResult.Status = 2;
|
||||
this.TransferStatus = TransferStatus.None;
|
||||
this.transferStatus = TransferStatus.None;
|
||||
}
|
||||
else if (!File.Exists(urlFileInfo.FilePath))
|
||||
{
|
||||
waitResult.Message = string.Format("文件不存在", filePath);
|
||||
waitResult.Message = $"路径{urlFileInfo.FilePath}文件不存在";
|
||||
waitResult.Status = 2;
|
||||
this.TransferStatus = TransferStatus.None;
|
||||
this.transferStatus = TransferStatus.None;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.TransferStatus = TransferStatus.Download;
|
||||
waitResult.Message = null;
|
||||
waitResult.Status = 1;
|
||||
FileInfo fileInfo;
|
||||
UrlFileInfo fileInfo;
|
||||
|
||||
if (!TransferFileHashDictionary.GetFileInfo(filePath, out fileInfo, breakpointResume))
|
||||
if (!TransferFileHashDictionary.GetFileInfo(urlFileInfo.FilePath, out fileInfo, urlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume)))
|
||||
{
|
||||
fileInfo = new FileInfo();
|
||||
using (FileStream stream = File.OpenRead(filePath))
|
||||
{
|
||||
fileInfo.FilePath = filePath;
|
||||
fileInfo.FileLength = stream.Length;
|
||||
fileInfo.FileName = Path.GetFileName(filePath);
|
||||
if (this.breakpointResume)
|
||||
{
|
||||
fileInfo.FileHash = FileControler.GetStreamHash(stream);
|
||||
}
|
||||
TransferFileHashDictionary.AddFile(fileInfo);
|
||||
}
|
||||
fileInfo = TransferFileHashDictionary.AddFile(urlFileInfo.FilePath, urlFileInfo.Flags.HasFlag(TransferFlags.BreakpointResume));
|
||||
}
|
||||
urlFileInfo.CopyFrom(fileInfo);
|
||||
if (FileStreamPool.LoadReadStream(ref urlFileInfo, out string mes))
|
||||
{
|
||||
this.transferStatus = TransferStatus.Download;
|
||||
waitResult.Message = null;
|
||||
waitResult.Status = 1;
|
||||
this.transferUrlFileInfo = urlFileInfo;
|
||||
waitResult.PBCollectionTemp = new PBCollectionTemp();
|
||||
waitResult.PBCollectionTemp.UrlFileInfo = urlFileInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
waitResult.Message = mes;
|
||||
waitResult.Status = 2;
|
||||
}
|
||||
urlFileInfo.Copy(fileInfo);
|
||||
fileBlocks = FileBaseTool.GetProgressBlockCollection(urlFileInfo, this.breakpointResume);
|
||||
waitResult.PBCollectionTemp = PBCollectionTemp.GetFromProgressBlockCollection(fileBlocks);
|
||||
}
|
||||
|
||||
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(waitResult, true));
|
||||
this.SendDefaultObject(waitResult);
|
||||
}
|
||||
|
||||
private void RequestUpload(ByteBlock byteBlock, PBCollectionTemp requestBlocks, bool restart)
|
||||
private void P113_DownloadBlockData(ByteBlock receivedByteBlock)
|
||||
{
|
||||
FileWaitResult waitResult = new FileWaitResult();
|
||||
FileOperationEventArgs args = new FileOperationEventArgs();
|
||||
args.FileInfo = requestBlocks.UrlFileInfo;
|
||||
args.TargetPath = Path.Combine(requestBlocks.UrlFileInfo.SaveFolder, requestBlocks.UrlFileInfo.FileName);
|
||||
args.IsPermitOperation = true;
|
||||
this.BeforeFileTransfer?.Invoke(this, args);//触发 接收文件事件
|
||||
requestBlocks.UrlFileInfo.FilePath = args.TargetPath;
|
||||
receivedByteBlock.Pos = 2;
|
||||
|
||||
long position = receivedByteBlock.ReadInt64();
|
||||
int requestLength = receivedByteBlock.ReadInt32();
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(requestLength + 7);
|
||||
if (this.transferStatus != TransferStatus.Download)
|
||||
{
|
||||
byteBlock.Buffer[6] = 0;
|
||||
}
|
||||
|
||||
string mes;
|
||||
if (FileStreamPool.ReadFile(transferUrlFileInfo.FilePath, out mes, position, byteBlock, 7, requestLength))
|
||||
{
|
||||
Speed.downloadSpeed += requestLength;
|
||||
this.position = position + requestLength;
|
||||
this.tempLength += requestLength;
|
||||
this.dataTransferLength += requestLength;
|
||||
byteBlock.Buffer[6] = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Position = 6;
|
||||
byteBlock.Write((byte)2);
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(string.IsNullOrEmpty(mes) ? "未知错误" : mes));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (this.Online)
|
||||
{
|
||||
this.InternalSend(111, byteBlock.Buffer, 0, byteBlock.Len, true);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void P114_StopDownload()
|
||||
{
|
||||
this.transferUrlFileInfo = null;
|
||||
this.transferStatus = TransferStatus.None;
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
}
|
||||
|
||||
private void P115_DownloadFinished()
|
||||
{
|
||||
if (this.transferStatus == TransferStatus.None)
|
||||
{
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
return;
|
||||
}
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
OnFinishedFileTransfer(TransferType.Download);
|
||||
}
|
||||
|
||||
private void P116_RequestUpload(UrlFileInfo urlFileInfo)
|
||||
{
|
||||
FileOperationEventArgs args = OnBeforeFileTransfer(urlFileInfo);
|
||||
|
||||
FileWaitResult waitResult = new FileWaitResult();
|
||||
if (!args.IsPermitOperation)
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = string.IsNullOrEmpty(args.Message) ? "服务器拒绝上传" : args.Message;
|
||||
}
|
||||
else if (FileControler.FileIsOpen(requestBlocks.UrlFileInfo.FilePath))
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = "该文件已被打开,或许正在由其他客户端上传";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.TransferStatus = TransferStatus.Upload;
|
||||
|
||||
restart = this.breakpointResume ? restart : true;
|
||||
if (!restart)
|
||||
this.transferStatus = TransferStatus.Upload;
|
||||
this.transferUrlFileInfo = urlFileInfo;
|
||||
if (urlFileInfo.Flags.HasFlag(TransferFlags.QuickTransfer) && TransferFileHashDictionary.GetFileInfoFromHash(urlFileInfo.FileHash, out UrlFileInfo oldUrlFileInfo))
|
||||
{
|
||||
FileInfo fileInfo;
|
||||
if (TransferFileHashDictionary.GetFileInfoFromHash(requestBlocks.UrlFileInfo.FileHash, out fileInfo))
|
||||
try
|
||||
{
|
||||
try
|
||||
if (urlFileInfo.FilePath != oldUrlFileInfo.FilePath)
|
||||
{
|
||||
if (fileInfo.FilePath != requestBlocks.UrlFileInfo.FilePath)
|
||||
{
|
||||
File.Copy(fileInfo.FilePath, requestBlocks.UrlFileInfo.FilePath);
|
||||
}
|
||||
this.fileBlocks = FileBaseTool.GetProgressBlockCollection(requestBlocks.UrlFileInfo, this.breakpointResume);
|
||||
foreach (var item in this.fileBlocks)
|
||||
{
|
||||
item.Finished = true;
|
||||
}
|
||||
waitResult.Status = 3;
|
||||
waitResult.Message = null;
|
||||
File.Copy(oldUrlFileInfo.FilePath, urlFileInfo.FilePath, true);
|
||||
}
|
||||
|
||||
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(waitResult, true));
|
||||
return;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
waitResult.Status = 3;
|
||||
waitResult.Message = null;
|
||||
this.SendDefaultObject(waitResult);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = ex.Message;
|
||||
this.Logger.Debug(LogType.Error, this, "在处理快速上传时发生异常。", ex);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ProgressBlockCollection blocks = requestBlocks.ToPBCollection();
|
||||
uploadFileStream = RRQMStream.GetRRQMStream(ref blocks, restart, this.breakpointResume);
|
||||
blocks.UrlFileInfo.FilePath = requestBlocks.UrlFileInfo.FilePath;
|
||||
this.fileBlocks = blocks;
|
||||
waitResult.Status = 1;
|
||||
waitResult.Message = null;
|
||||
waitResult.PBCollectionTemp = PBCollectionTemp.GetFromProgressBlockCollection(blocks);
|
||||
ProgressBlockCollection blocks = ProgressBlockCollection.CreateProgressBlockCollection(urlFileInfo);
|
||||
|
||||
if (FileStreamPool.LoadWriteStream(ref blocks, false, out string mes))
|
||||
{
|
||||
waitResult.Status = 1;
|
||||
waitResult.Message = null;
|
||||
waitResult.PBCollectionTemp = PBCollectionTemp.GetFromProgressBlockCollection(blocks);
|
||||
}
|
||||
else
|
||||
{
|
||||
waitResult.Status = 2;
|
||||
waitResult.Message = mes;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -639,83 +586,107 @@ namespace RRQMSocket.FileTransfer
|
||||
}
|
||||
}
|
||||
|
||||
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(waitResult, true));
|
||||
this.SendDefaultObject(waitResult);
|
||||
}
|
||||
|
||||
private void StopUpload(ByteBlock byteBlock)
|
||||
private void P117_UploadBlockData(byte[] buffer)
|
||||
{
|
||||
FileBaseTool.SaveProgressBlockCollection(this.uploadFileStream, this.fileBlocks);
|
||||
this.uploadFileStream.Dispose();
|
||||
this.uploadFileStream = null;
|
||||
byteBlock.Write(1);
|
||||
}
|
||||
|
||||
private void UploadBlockData(ByteBlock byteBlock, ByteBlock receivedbyteBlock)
|
||||
{
|
||||
if (this.TransferStatus != TransferStatus.Upload)
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
try
|
||||
{
|
||||
byteBlock.Write(4);
|
||||
return;
|
||||
}
|
||||
byte status = receivedbyteBlock.Buffer[2];
|
||||
int index = BitConverter.ToInt32(receivedbyteBlock.Buffer, 3);
|
||||
long position = BitConverter.ToInt64(receivedbyteBlock.Buffer, 7);
|
||||
long submitLength = BitConverter.ToInt64(receivedbyteBlock.Buffer, 15);
|
||||
|
||||
string mes;
|
||||
if (FileBaseTool.WriteFile(this.uploadFileStream, out mes, position, receivedbyteBlock.Buffer, 23, (int)submitLength))
|
||||
{
|
||||
this.position = position + submitLength;
|
||||
this.tempLength += submitLength;
|
||||
this.dataTransferLength += submitLength;
|
||||
Speed.uploadSpeed += submitLength;
|
||||
|
||||
if (this.bufferLengthChanged)
|
||||
if (this.transferStatus != TransferStatus.Upload)
|
||||
{
|
||||
byteBlock.Write(3);
|
||||
byteBlock.Write((byte)4);
|
||||
}
|
||||
byte status = buffer[2];
|
||||
int index = BitConverter.ToInt32(buffer, 3);
|
||||
long position = BitConverter.ToInt64(buffer, 7);
|
||||
int submitLength = BitConverter.ToInt32(buffer, 15);
|
||||
|
||||
string mes;
|
||||
if (FileStreamPool.WriteFile(this.rrqmPath, out mes, out RRQMStream stream, position, buffer, 19, submitLength))
|
||||
{
|
||||
this.position = position + submitLength;
|
||||
this.tempLength += submitLength;
|
||||
this.dataTransferLength += submitLength;
|
||||
Speed.uploadSpeed += submitLength;
|
||||
byteBlock.Write((byte)1);
|
||||
if (status == 1)
|
||||
{
|
||||
FileBlock fileProgress = stream.Blocks.FirstOrDefault(a => a.Index == index);
|
||||
fileProgress.RequestStatus = RequestStatus.Finished;
|
||||
stream.SaveProgressBlockCollection();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byteBlock.Write(1);
|
||||
}
|
||||
|
||||
if (status == 1)
|
||||
{
|
||||
FileProgressBlock fileProgress = this.fileBlocks.FirstOrDefault(a => a.Index == index);
|
||||
fileProgress.Finished = true;
|
||||
FileBaseTool.SaveProgressBlockCollection(this.uploadFileStream, this.fileBlocks);
|
||||
byteBlock.Write((byte)2);
|
||||
byteBlock.Write(Encoding.UTF8.GetBytes(mes));
|
||||
Logger.Debug(LogType.Error, this, $"上传文件写入错误,信息:{mes}");
|
||||
}
|
||||
this.InternalSend(111, byteBlock);
|
||||
}
|
||||
else
|
||||
catch (Exception ex)
|
||||
{
|
||||
byteBlock.Write(2);
|
||||
Logger.Debug(LogType.Error, this, "上传文件写入错误:" + mes);
|
||||
Logger.Debug(LogType.Error, this, "上传文件错误", ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void UploadFinished(ByteBlock byteBlock)
|
||||
private void P118_StopUpload()
|
||||
{
|
||||
TransferFileHashDictionary.AddFile(this.TransferFileInfo);
|
||||
if (this.uploadFileStream != null)
|
||||
try
|
||||
{
|
||||
RRQMStream.FileFinished(this.uploadFileStream);
|
||||
this.uploadFileStream = null;
|
||||
FileStreamPool.SaveProgressBlockCollection(this.rrqmPath);
|
||||
FileStreamPool.DisposeWriteStream(this.rrqmPath, false);
|
||||
this.ResetVariable();
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
}
|
||||
if (this.fileBlocks != null)
|
||||
catch (Exception ex)
|
||||
{
|
||||
TransferFileHashDictionary.AddFile(this.fileBlocks.UrlFileInfo);
|
||||
FilePathEventArgs args = new FilePathEventArgs();
|
||||
args.FileInfo = this.fileBlocks.UrlFileInfo;
|
||||
args.TargetPath = args.FileInfo.FilePath;
|
||||
args.TransferType = TransferType.Upload;
|
||||
this.FinishedFileTransfer?.Invoke(this, args);
|
||||
|
||||
this.fileBlocks = null;
|
||||
this.Logger.Debug(LogType.Error, this, "客户端请求停止上传时发生异常", ex);
|
||||
}
|
||||
|
||||
byteBlock.Write(1);
|
||||
}
|
||||
|
||||
#endregion 协议函数
|
||||
private void P119_UploadFinished()
|
||||
{
|
||||
if (this.transferStatus == TransferStatus.None)
|
||||
{
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
return;
|
||||
}
|
||||
this.InternalSend(111, new byte[] { 1 }, 0, 1);
|
||||
OnFinishedFileTransfer(TransferType.Upload);
|
||||
}
|
||||
|
||||
private void ResetVariable()
|
||||
{
|
||||
this.transferStatus = TransferStatus.None;
|
||||
this.transferUrlFileInfo = null;
|
||||
this.progress = 0;
|
||||
this.speed = 0;
|
||||
if (!string.IsNullOrEmpty(this.rrqmPath))
|
||||
{
|
||||
FileStreamPool.DisposeWriteStream(this.rrqmPath, false);
|
||||
this.rrqmPath = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void SendDefaultObject(object obj)
|
||||
{
|
||||
ByteBlock byteBlock = this.BytePool.GetByteBlock(this.BufferLength);
|
||||
byteBlock.Write(SerializeConvert.RRQMBinarySerialize(obj, true));
|
||||
try
|
||||
{
|
||||
this.InternalSend(111, byteBlock);
|
||||
}
|
||||
finally
|
||||
{
|
||||
byteBlock.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user