You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1220 lines
54 KiB
1220 lines
54 KiB
|
3 months ago
|
//------------------------------------------------------------------------------
|
||
|
|
// 此代码版权(除特别声明或在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
|
||
|
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index
|
||
|
|
// 交流QQ群:234762506
|
||
|
|
// 感谢您的下载和使用
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
//------------------------------------------------------------------------------
|
||
|
|
using System;
|
||
|
|
using System.Collections.Concurrent;
|
||
|
|
using System.IO;
|
||
|
|
using System.Threading;
|
||
|
|
using System.Threading.Tasks;
|
||
|
|
using TouchSocket.Core;
|
||
|
|
using TouchSocket.Resources;
|
||
|
|
|
||
|
|
namespace TouchSocket.Rpc.TouchRpc
|
||
|
|
{
|
||
|
|
public partial class RpcActor
|
||
|
|
{
|
||
|
|
private readonly ConcurrentDictionary<int, object> m_eventArgs;
|
||
|
|
private string m_rootPath = string.Empty;
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public string RootPath
|
||
|
|
{
|
||
|
|
get => m_rootPath;
|
||
|
|
set
|
||
|
|
{
|
||
|
|
value ??= string.Empty;
|
||
|
|
m_rootPath = value;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#region Pull
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Result PullFile(FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
return this.PrivatePullFile(default, fileOperator);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Result PullFile(string targetId, FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
if (IsService)
|
||
|
|
{
|
||
|
|
if (this.TryFindRpcActor(targetId, out RpcActor rpcActor))
|
||
|
|
{
|
||
|
|
return rpcActor.PullFile(fileOperator);
|
||
|
|
}
|
||
|
|
return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription());
|
||
|
|
}
|
||
|
|
|
||
|
|
return this.PrivatePullFile(targetId, fileOperator);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Task<Result> PullFileAsync(string targetId, FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return PullFile(targetId, fileOperator);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Task<Result> PullFileAsync(FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return PullFile(fileOperator);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private Result PreviewPullFile(string targetId, FileOperator fileOperator, WaitFileInfoPackage waitFileInfoPackage)
|
||
|
|
{
|
||
|
|
TouchRpcFileInfo fileInfo = waitFileInfoPackage.FileInfo;
|
||
|
|
fileOperator.SavePath = FileController.GetFullPath(m_rootPath, fileOperator.SavePath);
|
||
|
|
TouchRpcFileStream stream;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
FileController.TryReadTempInfo(fileOperator.SavePath, fileOperator.Flags, ref fileInfo);
|
||
|
|
stream = TouchRpcFileStream.Create(fileOperator.SavePath, ref fileInfo, fileOperator.Flags.HasFlag(TransferFlags.BreakpointResume));
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message));
|
||
|
|
}
|
||
|
|
|
||
|
|
WaitTransferPackage waitTransfer = new WaitTransferPackage()
|
||
|
|
{
|
||
|
|
EventHashCode = waitFileInfoPackage.EventHashCode,
|
||
|
|
Path = fileInfo.FullName,
|
||
|
|
Position = fileInfo.Position,
|
||
|
|
SourceId = this.ID,
|
||
|
|
TargetId = targetId,
|
||
|
|
Route = targetId.HasValue()
|
||
|
|
};
|
||
|
|
|
||
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetWaitData(waitTransfer);
|
||
|
|
ByteBlock byteBlock = new ByteBlock();
|
||
|
|
Channel channel = default;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
if (targetId == null)
|
||
|
|
{
|
||
|
|
channel = CreateChannel();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
channel = CreateChannel(targetId);
|
||
|
|
}
|
||
|
|
waitTransfer.ChannelID = channel.ID;
|
||
|
|
waitTransfer.Package(byteBlock);
|
||
|
|
Send(TouchRpcUtility.P_501_BeginPullFile_Request, byteBlock);
|
||
|
|
|
||
|
|
if (fileOperator.Token.IsCancellationRequested)
|
||
|
|
{
|
||
|
|
waitData.SetCancellationToken(fileOperator.Token);
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (waitData.Wait(fileOperator.Timeout))
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
WaitTransferPackage waitTransferResult = (WaitTransferPackage)waitData.WaitResult;
|
||
|
|
switch (waitTransferResult.Status.ToStatus())
|
||
|
|
{
|
||
|
|
case TouchSocketStatus.Success:
|
||
|
|
{
|
||
|
|
fileOperator.SetFileCompletedLength(fileInfo.Position);
|
||
|
|
fileOperator.SetLength(fileInfo.Length);
|
||
|
|
channel.Timeout = fileOperator.Timeout;
|
||
|
|
while (channel.MoveNext())
|
||
|
|
{
|
||
|
|
if (fileOperator.Token.IsCancellationRequested)
|
||
|
|
{
|
||
|
|
channel.Cancel();
|
||
|
|
fileOperator.SetResult(new Result(ResultCode.Canceled));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
byte[] data = channel.GetCurrent();
|
||
|
|
if (data != null)
|
||
|
|
{
|
||
|
|
stream.Write(data, 0, data.Length);
|
||
|
|
fileInfo.Position = stream.FileWriter.Position;
|
||
|
|
fileOperator.AddFlow(data.Length);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (channel.Status == ChannelStatus.Completed)
|
||
|
|
{
|
||
|
|
stream.FinishStream();
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Success));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(channel.Status.ToResultCode()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case TouchSocketStatus.LoadStreamFail:
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Fail, TouchSocketStatus.LoadStreamFail.GetDescription(fileInfo.FullName)));
|
||
|
|
|
||
|
|
default:
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, waitTransferResult.Status.ToStatus().GetDescription(waitTransferResult.Message)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Overtime));
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Canceled:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Canceled));
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message));
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
WaitHandlePool.Destroy(waitData);
|
||
|
|
stream.SafeDispose();
|
||
|
|
byteBlock.Dispose();
|
||
|
|
channel.SafeDispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private Result PrivatePullFile(string targetId, FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
if (fileOperator is null)
|
||
|
|
{
|
||
|
|
return new Result(ResultCode.Error, TouchSocketStatus.ArgumentNull.GetDescription(nameof(fileOperator)));
|
||
|
|
}
|
||
|
|
|
||
|
|
WaitFileInfoPackage waitFileInfo = new WaitFileInfoPackage
|
||
|
|
{
|
||
|
|
SourceId = this.ID,
|
||
|
|
TargetId = targetId,
|
||
|
|
Route = targetId.HasValue(),
|
||
|
|
Metadata = fileOperator.Metadata,
|
||
|
|
SavePath = this.FileController.GetFullPath(this.m_rootPath, fileOperator.SavePath),
|
||
|
|
Flags = fileOperator.Flags,
|
||
|
|
ResourcePath = fileOperator.ResourcePath
|
||
|
|
};
|
||
|
|
|
||
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetWaitData(waitFileInfo);
|
||
|
|
|
||
|
|
ByteBlock byteBlock = new ByteBlock();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
waitFileInfo.Package(byteBlock);
|
||
|
|
Send(TouchRpcUtility.P_500_PullFile_Request, byteBlock);
|
||
|
|
|
||
|
|
if (fileOperator.Token.IsCancellationRequested)
|
||
|
|
{
|
||
|
|
waitData.SetCancellationToken(fileOperator.Token);
|
||
|
|
}
|
||
|
|
|
||
|
|
waitData.Wait(fileOperator.Timeout);
|
||
|
|
|
||
|
|
switch (waitData.Status)
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
WaitFileInfoPackage waitFileResult = (WaitFileInfoPackage)waitData.WaitResult;
|
||
|
|
switch (waitFileResult.Status.ToStatus())
|
||
|
|
{
|
||
|
|
case TouchSocketStatus.Success:
|
||
|
|
return PreviewPullFile(targetId, fileOperator, waitFileResult);
|
||
|
|
|
||
|
|
case TouchSocketStatus.FileNotExists:
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(waitFileResult.ResourcePath)));
|
||
|
|
|
||
|
|
case TouchSocketStatus.RemoteRefuse:
|
||
|
|
default:
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Fail, waitFileResult.Status.ToStatus().GetDescription(waitFileResult.Message)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(Result.Overtime);
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Canceled:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(Result.Canceled);
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(Result.UnknownFail);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ex));
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
WaitHandlePool.Destroy(waitData);
|
||
|
|
byteBlock.Dispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Pull
|
||
|
|
|
||
|
|
#region Push
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Result PushFile(FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
return PrivatePushFile(default, fileOperator);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Result PushFile(string targetId, FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
if (IsService)
|
||
|
|
{
|
||
|
|
if (this.TryFindRpcActor(targetId, out RpcActor rpcActor))
|
||
|
|
{
|
||
|
|
return rpcActor.PushFile(fileOperator);
|
||
|
|
}
|
||
|
|
return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription());
|
||
|
|
}
|
||
|
|
return this.PrivatePushFile(default, fileOperator);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Task<Result> PushFileAsync(string targetId, FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return PushFile(targetId, fileOperator);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Task<Result> PushFileAsync(FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
return EasyTask.Run(() =>
|
||
|
|
{
|
||
|
|
return PushFile(fileOperator);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private Result PreviewPushFile(FileOperator fileOperator, WaitTransferPackage waitTransfer)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
using FileStorageReader reader = FilePool.GetReader(waitTransfer.Path);
|
||
|
|
fileOperator.SetLength(reader.FileStorage.FileInfo.Length);
|
||
|
|
if (TrySubscribeChannel(waitTransfer.ChannelID, out Channel channel))
|
||
|
|
{
|
||
|
|
ByteBlock byteBlock = BytePool.Default.GetByteBlock(TouchRpcUtility.TransferPackage);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
long position = waitTransfer.Position;
|
||
|
|
reader.Position = position;
|
||
|
|
fileOperator.SetFileCompletedLength(waitTransfer.Position);
|
||
|
|
|
||
|
|
channel.Timeout = fileOperator.Timeout;
|
||
|
|
while (true)
|
||
|
|
{
|
||
|
|
if (fileOperator.Token.IsCancellationRequested)
|
||
|
|
{
|
||
|
|
channel.Cancel("主动取消");
|
||
|
|
fileOperator.SetResult(new Result(ResultCode.Canceled));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
int r = reader.Read(byteBlock.Buffer, 0, (int)Math.Min(TouchRpcUtility.TransferPackage, fileOperator.MaxSpeed / 10.0));
|
||
|
|
if (r == 0)
|
||
|
|
{
|
||
|
|
channel.Complete();
|
||
|
|
WaitPushFileAckPackage waitResult = null;
|
||
|
|
if (SpinWait.SpinUntil(() =>
|
||
|
|
{
|
||
|
|
if (m_eventArgs.TryRemove(waitTransfer.EventHashCode, out object obj))
|
||
|
|
{
|
||
|
|
waitResult = (WaitPushFileAckPackage)obj;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
return false;
|
||
|
|
}, fileOperator.Timeout))
|
||
|
|
{
|
||
|
|
if (waitResult.Status.ToStatus() == TouchSocketStatus.Success)
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Success));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, waitResult.Message));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Overtime, "等待最后状态确认超时。"));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
position += r;
|
||
|
|
if (channel.TryWrite(byteBlock.Buffer, 0, r))
|
||
|
|
{
|
||
|
|
fileOperator.AddFlow(r);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (channel.Status == ChannelStatus.Cancel && !string.IsNullOrEmpty(channel.LastOperationMes))
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Canceled, channel.LastOperationMes));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(channel.Status.ToResultCode()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message));
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
byteBlock.Dispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.SetChannelFail.GetDescription()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.LoadStreamFail.GetDescription(waitTransfer.Path, ex.Message)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private Result PrivatePushFile(string targetId, FileOperator fileOperator)
|
||
|
|
{
|
||
|
|
if (fileOperator is null)
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.ArgumentNull.GetDescription(nameof(fileOperator))));
|
||
|
|
}
|
||
|
|
|
||
|
|
string fullPath = FileController.GetFullPath(m_rootPath, fileOperator.ResourcePath);
|
||
|
|
|
||
|
|
if (!File.Exists(fullPath))
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(fullPath)));
|
||
|
|
}
|
||
|
|
|
||
|
|
TouchRpcFileInfo fileInfo = new TouchRpcFileInfo();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
FileController.GetFileInfo(fullPath, fileOperator.Flags.HasFlag(TransferFlags.MD5Verify), ref fileInfo);
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, ex.Message));
|
||
|
|
}
|
||
|
|
|
||
|
|
WaitFileInfoPackage waitFileInfoPackage = new WaitFileInfoPackage()
|
||
|
|
{
|
||
|
|
FileInfo = fileInfo,
|
||
|
|
Metadata = fileOperator.Metadata,
|
||
|
|
ResourcePath = this.FileController.GetFullPath(this.m_rootPath, fileOperator.ResourcePath),
|
||
|
|
SavePath = fileOperator.SavePath,
|
||
|
|
Flags = fileOperator.Flags,
|
||
|
|
TargetId = targetId,
|
||
|
|
SourceId = this.ID,
|
||
|
|
Route = targetId.HasValue()
|
||
|
|
};
|
||
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetWaitData(waitFileInfoPackage);
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
SendPackage(TouchRpcUtility.P_502_PushFile_Request, waitFileInfoPackage);
|
||
|
|
waitData.SetCancellationToken(fileOperator.Token);
|
||
|
|
|
||
|
|
waitData.Wait(fileOperator.Timeout);
|
||
|
|
|
||
|
|
switch (waitData.Status)
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
WaitTransferPackage waitResult = (WaitTransferPackage)waitData.WaitResult;
|
||
|
|
switch (waitResult.Status.ToStatus())
|
||
|
|
{
|
||
|
|
case TouchSocketStatus.Success:
|
||
|
|
return PreviewPushFile(fileOperator, waitResult);
|
||
|
|
|
||
|
|
case TouchSocketStatus.LoadStreamFail:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.LoadStreamFail.GetDescription(waitResult.Path, waitResult.Message)));
|
||
|
|
}
|
||
|
|
case TouchSocketStatus.ClientNotFind:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription(targetId)));
|
||
|
|
}
|
||
|
|
case TouchSocketStatus.DirectoryNotExists:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, TouchSocketStatus.DirectoryNotExists.GetDescription(waitResult.Path)));
|
||
|
|
}
|
||
|
|
case TouchSocketStatus.RemoteRefuse:
|
||
|
|
default:
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error, waitResult.Status.ToStatus().GetDescription(waitResult.Message)));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Overtime));
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Canceled:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Canceled));
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ResultCode.Error));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
return fileOperator.SetResult(new Result(ex));
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
WaitHandlePool.Destroy(waitData);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion Push
|
||
|
|
|
||
|
|
#region 小文件传输
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// 允许传输的小文件的最大长度。默认1024*1024字节。
|
||
|
|
/// <para>注意,当调整该值时,应该和对端保持一致。</para>
|
||
|
|
/// </summary>
|
||
|
|
public int MaxSmallFileLength { get; set; } = 1024 * 1024;
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public PullSmallFileResult PullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
if (IsService)
|
||
|
|
{
|
||
|
|
if (this.TryFindRpcActor(targetId, out RpcActor actor))
|
||
|
|
{
|
||
|
|
return actor.PullSmallFile(path, metadata, timeout, token);
|
||
|
|
}
|
||
|
|
return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription());
|
||
|
|
}
|
||
|
|
|
||
|
|
return PrivatePullSmallFile(targetId, path, metadata, timeout, token);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public PullSmallFileResult PullSmallFile(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
return PrivatePullSmallFile(default, path, metadata, timeout, token);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Task<PullSmallFileResult> PullSmallFileAsync(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
return Task.Run(() =>
|
||
|
|
{
|
||
|
|
return PullSmallFile(targetId, path, metadata, timeout, token);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Task<PullSmallFileResult> PullSmallFileAsync(string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
return Task.Run(() =>
|
||
|
|
{
|
||
|
|
return PullSmallFile(path, metadata, timeout, token);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Result PushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
if (IsService)
|
||
|
|
{
|
||
|
|
if (this.TryFindRpcActor(targetId, out RpcActor rpcActor))
|
||
|
|
{
|
||
|
|
return rpcActor.PushSmallFile(savePath, fileInfo, metadata, timeout, token);
|
||
|
|
}
|
||
|
|
return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription());
|
||
|
|
}
|
||
|
|
return PrivatePushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Result PushSmallFile(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
return PrivatePushSmallFile(default, savePath, fileInfo, metadata, timeout, token);
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Task<Result> PushSmallFileAsync(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
return Task.Run(() =>
|
||
|
|
{
|
||
|
|
return PushSmallFile(targetId, savePath, fileInfo, metadata, timeout, token);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <inheritdoc/>
|
||
|
|
public Task<Result> PushSmallFileAsync(string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
return Task.Run(() =>
|
||
|
|
{
|
||
|
|
return PushSmallFile(savePath, fileInfo, metadata, timeout, token);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private PullSmallFileResult PrivatePullSmallFile(string targetId, string path, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
WaitSmallFilePackage waitSmallFilePackage = new WaitSmallFilePackage()
|
||
|
|
{
|
||
|
|
Path = path,
|
||
|
|
SourceId = ID,
|
||
|
|
TargetId = targetId,
|
||
|
|
Route = targetId.HasValue(),
|
||
|
|
Metadata = metadata
|
||
|
|
};
|
||
|
|
|
||
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetWaitData(waitSmallFilePackage);
|
||
|
|
|
||
|
|
ByteBlock byteBlock = new ByteBlock();
|
||
|
|
try
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Package(byteBlock);
|
||
|
|
Send(TouchRpcUtility.P_517_PullSmallFile_Request, byteBlock);
|
||
|
|
waitData.SetCancellationToken(token);
|
||
|
|
|
||
|
|
waitData.Wait(timeout);
|
||
|
|
|
||
|
|
switch (waitData.Status)
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
WaitSmallFilePackage waitFile = (WaitSmallFilePackage)waitData.WaitResult;
|
||
|
|
switch (waitFile.Status.ToStatus())
|
||
|
|
{
|
||
|
|
case TouchSocketStatus.Success:
|
||
|
|
{
|
||
|
|
return new PullSmallFileResult(waitFile.Data);
|
||
|
|
}
|
||
|
|
case TouchSocketStatus.FileNotExists:
|
||
|
|
{
|
||
|
|
return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(waitFile.Path));
|
||
|
|
}
|
||
|
|
case TouchSocketStatus.RemoteRefuse:
|
||
|
|
case TouchSocketStatus.LengthErrorWhenRead:
|
||
|
|
case TouchSocketStatus.FileLengthTooLong:
|
||
|
|
case TouchSocketStatus.ClientNotFind:
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitFile.Message));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime:
|
||
|
|
{
|
||
|
|
return new PullSmallFileResult(ResultCode.Overtime);
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Canceled:
|
||
|
|
{
|
||
|
|
return new PullSmallFileResult(ResultCode.Canceled);
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
return new PullSmallFileResult(ResultCode.Error, TouchSocketStatus.UnknownError.GetDescription());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
WaitHandlePool.Destroy(waitData);
|
||
|
|
byteBlock.Dispose();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private Result PrivatePushSmallFile(string targetId, string savePath, FileInfo fileInfo, Metadata metadata = null, int timeout = 5000, CancellationToken token = default)
|
||
|
|
{
|
||
|
|
if (!File.Exists(fileInfo.FullName))
|
||
|
|
{
|
||
|
|
return new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(fileInfo.FullName));
|
||
|
|
}
|
||
|
|
if (fileInfo.Length > MaxSmallFileLength)
|
||
|
|
{
|
||
|
|
return new Result(ResultCode.Error, TouchSocketStatus.FileLengthTooLong.GetDescription());
|
||
|
|
}
|
||
|
|
WaitSmallFilePackage waitSmallFilePackage = new WaitSmallFilePackage()
|
||
|
|
{
|
||
|
|
Path = savePath,
|
||
|
|
SourceId = ID,
|
||
|
|
Metadata = metadata,
|
||
|
|
Route = targetId.HasValue(),
|
||
|
|
TargetId = targetId,
|
||
|
|
FileInfo = new RemoteFileInfo(fileInfo)
|
||
|
|
};
|
||
|
|
|
||
|
|
WaitData<IWaitResult> waitData = WaitHandlePool.GetWaitData(waitSmallFilePackage);
|
||
|
|
|
||
|
|
ByteBlock byteBlock = new ByteBlock();
|
||
|
|
byte[] buffer = BytePool.Default.GetByteCore((int)fileInfo.Length);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
int r = FileController.ReadAllBytes(fileInfo, buffer);
|
||
|
|
if (r <= 0)
|
||
|
|
{
|
||
|
|
return new Result(ResultCode.Error, TouchSocketStatus.LengthErrorWhenRead.GetDescription());
|
||
|
|
}
|
||
|
|
waitSmallFilePackage.Data = buffer;
|
||
|
|
waitSmallFilePackage.Len = r;
|
||
|
|
|
||
|
|
waitSmallFilePackage.Package(byteBlock);
|
||
|
|
Send(TouchRpcUtility.P_518_PushSmallFile_Request, byteBlock);
|
||
|
|
waitData.SetCancellationToken(token);
|
||
|
|
|
||
|
|
waitData.Wait(timeout);
|
||
|
|
|
||
|
|
switch (waitData.Status)
|
||
|
|
{
|
||
|
|
case WaitDataStatus.SetRunning:
|
||
|
|
{
|
||
|
|
WaitSmallFilePackage waitFile = (WaitSmallFilePackage)waitData.WaitResult;
|
||
|
|
switch (waitFile.Status.ToStatus())
|
||
|
|
{
|
||
|
|
case TouchSocketStatus.Success:
|
||
|
|
{
|
||
|
|
return Result.Success;
|
||
|
|
}
|
||
|
|
case TouchSocketStatus.RemoteRefuse:
|
||
|
|
{
|
||
|
|
return new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(waitFile.Message));
|
||
|
|
}
|
||
|
|
case TouchSocketStatus.ClientNotFind:
|
||
|
|
{
|
||
|
|
return new Result(ResultCode.Error, TouchSocketStatus.ClientNotFind.GetDescription());
|
||
|
|
}
|
||
|
|
default:
|
||
|
|
return new Result(ResultCode.Exception, waitFile.Message);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Overtime:
|
||
|
|
{
|
||
|
|
return Result.Overtime;
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Canceled:
|
||
|
|
{
|
||
|
|
return Result.Canceled;
|
||
|
|
}
|
||
|
|
case WaitDataStatus.Disposed:
|
||
|
|
default:
|
||
|
|
{
|
||
|
|
return Result.UnknownFail;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
WaitHandlePool.Destroy(waitData);
|
||
|
|
byteBlock.Dispose();
|
||
|
|
BytePool.Default.Recycle(buffer);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void RequestPullSmallFile(object o)
|
||
|
|
{
|
||
|
|
//2.不响应
|
||
|
|
//3.不允许
|
||
|
|
//4.不存在
|
||
|
|
//5.读取文件长度异常
|
||
|
|
|
||
|
|
byte[] buffer = BytePool.Default.GetByteCore(MaxSmallFileLength);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
WaitSmallFilePackage waitSmallFilePackage = (WaitSmallFilePackage)o;
|
||
|
|
Result resultThis = Result.Success;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
FileOperationEventArgs args = new FileOperationEventArgs(TransferType.SmallPull,
|
||
|
|
waitSmallFilePackage.Metadata, default)
|
||
|
|
{
|
||
|
|
ResourcePath = waitSmallFilePackage.Path
|
||
|
|
};
|
||
|
|
|
||
|
|
OnFileTransfering?.Invoke(this, args);
|
||
|
|
|
||
|
|
string fullPath = FileController.GetFullPath(RootPath, args.ResourcePath);
|
||
|
|
waitSmallFilePackage.Path = fullPath;
|
||
|
|
if (args.IsPermitOperation)
|
||
|
|
{
|
||
|
|
if (File.Exists(fullPath))
|
||
|
|
{
|
||
|
|
FileInfo fileInfo = new FileInfo(fullPath);
|
||
|
|
if (fileInfo.Length > MaxSmallFileLength)
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Status = TouchSocketStatus.FileLengthTooLong.ToValue();
|
||
|
|
resultThis = new Result(ResultCode.Error, TouchSocketStatus.FileLengthTooLong.GetDescription());
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
int r = FileController.ReadAllBytes(fileInfo, buffer);
|
||
|
|
if (r > 0)
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Data = buffer;
|
||
|
|
waitSmallFilePackage.Len = r;
|
||
|
|
waitSmallFilePackage.FileInfo = new RemoteFileInfo(fileInfo);
|
||
|
|
waitSmallFilePackage.Status = TouchSocketStatus.Success.ToValue();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Status = TouchSocketStatus.LengthErrorWhenRead.ToValue();
|
||
|
|
resultThis = new Result(ResultCode.Error, TouchSocketStatus.LengthErrorWhenRead.GetDescription());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Status = TouchSocketStatus.FileNotExists.ToValue();
|
||
|
|
resultThis = new Result(ResultCode.Error, TouchSocketStatus.FileNotExists.GetDescription(fullPath));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Status = TouchSocketStatus.RemoteRefuse.ToValue();
|
||
|
|
waitSmallFilePackage.Message = args.Message;
|
||
|
|
resultThis = new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(args.Message));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Status = TouchSocketStatus.Exception.ToValue();
|
||
|
|
waitSmallFilePackage.Message = ex.Message;
|
||
|
|
}
|
||
|
|
|
||
|
|
using (ByteBlock byteBlock = new ByteBlock())
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.SwitchId();
|
||
|
|
waitSmallFilePackage.Package(byteBlock);
|
||
|
|
Send(TouchRpcUtility.P_1517_PullSmallFile_Response, byteBlock);
|
||
|
|
}
|
||
|
|
|
||
|
|
FileTransferStatusEventArgs resultArgs = new FileTransferStatusEventArgs(
|
||
|
|
TransferType.SmallPull, waitSmallFilePackage.Metadata, waitSmallFilePackage.FileInfo, resultThis)
|
||
|
|
{
|
||
|
|
ResourcePath = waitSmallFilePackage.Path
|
||
|
|
};
|
||
|
|
OnFileTransfered?.Invoke(this, resultArgs);
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
BytePool.Default.Recycle(buffer);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void RequestPushSmallFile(object o)
|
||
|
|
{
|
||
|
|
//2.不响应
|
||
|
|
//3.不允许
|
||
|
|
|
||
|
|
try
|
||
|
|
{
|
||
|
|
WaitSmallFilePackage waitSmallFilePackage = (WaitSmallFilePackage)o;
|
||
|
|
Result resultThis = Result.Success;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
FileOperationEventArgs args = new FileOperationEventArgs(TransferType.SmallPush,
|
||
|
|
waitSmallFilePackage.Metadata, waitSmallFilePackage.FileInfo)
|
||
|
|
{
|
||
|
|
SavePath = waitSmallFilePackage.Path
|
||
|
|
};
|
||
|
|
|
||
|
|
OnFileTransfering?.Invoke(this, args);
|
||
|
|
|
||
|
|
string fullPath = FileController.GetFullPath(RootPath, args.SavePath);
|
||
|
|
waitSmallFilePackage.Path = fullPath;
|
||
|
|
if (args.IsPermitOperation)
|
||
|
|
{
|
||
|
|
FileInfo fileInfo = new FileInfo(fullPath);
|
||
|
|
FileController.WriteAllBytes(fileInfo, waitSmallFilePackage.Data, 0, waitSmallFilePackage.Data.Length);
|
||
|
|
waitSmallFilePackage.Status = TouchSocketStatus.Success.ToValue();
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Status = TouchSocketStatus.RemoteRefuse.ToValue();
|
||
|
|
waitSmallFilePackage.Message = args.Message;
|
||
|
|
resultThis = new Result(ResultCode.Error, TouchSocketStatus.RemoteRefuse.GetDescription(args.Message));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Status = TouchSocketStatus.Exception.ToValue();
|
||
|
|
waitSmallFilePackage.Message = ex.Message;
|
||
|
|
}
|
||
|
|
waitSmallFilePackage.FileInfo = default;
|
||
|
|
waitSmallFilePackage.Data = default;
|
||
|
|
waitSmallFilePackage.SwitchId();
|
||
|
|
using (ByteBlock byteBlock = new ByteBlock())
|
||
|
|
{
|
||
|
|
waitSmallFilePackage.Package(byteBlock);
|
||
|
|
Send(TouchRpcUtility.P_1518_PushSmallFile_Response, byteBlock);
|
||
|
|
}
|
||
|
|
|
||
|
|
FileTransferStatusEventArgs resultArgs = new FileTransferStatusEventArgs(
|
||
|
|
TransferType.SmallPush, waitSmallFilePackage.Metadata, waitSmallFilePackage.FileInfo, resultThis)
|
||
|
|
{
|
||
|
|
SavePath = waitSmallFilePackage.Path
|
||
|
|
};
|
||
|
|
OnFileTransfered?.Invoke(this, resultArgs);
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
#endregion 小文件传输
|
||
|
|
|
||
|
|
private void BeginPullFile(object o)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
WaitTransferPackage waitTransferPackage = (WaitTransferPackage)o;
|
||
|
|
FileTransferStatusEventArgs e;
|
||
|
|
if (m_eventArgs.TryRemove(waitTransferPackage.EventHashCode, out object obj) && obj is FileOperationEventArgs args)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
using (FileStorageReader reader = FilePool.GetReader(waitTransferPackage.Path))
|
||
|
|
{
|
||
|
|
if (TrySubscribeChannel(waitTransferPackage.ChannelID, out Channel channel))
|
||
|
|
{
|
||
|
|
ByteBlock byteBlock = BytePool.Default.GetByteBlock(TouchRpcUtility.TransferPackage);
|
||
|
|
FileOperator fileOperator = args.FileOperator;
|
||
|
|
fileOperator.SetLength(reader.FileStorage.FileInfo.Length);
|
||
|
|
try
|
||
|
|
{
|
||
|
|
waitTransferPackage.Status = TouchSocketStatus.Success.ToValue();
|
||
|
|
waitTransferPackage.SwitchId();
|
||
|
|
SendPackage(TouchRpcUtility.P_1501_BeginPullFile_Response, waitTransferPackage);
|
||
|
|
long position = waitTransferPackage.Position;
|
||
|
|
reader.Position = position;
|
||
|
|
fileOperator.SetFileCompletedLength(position);
|
||
|
|
while (true)
|
||
|
|
{
|
||
|
|
if (fileOperator.Token.IsCancellationRequested)
|
||
|
|
{
|
||
|
|
channel.Cancel("主动取消");
|
||
|
|
fileOperator.SetResult(new Result(ResultCode.Canceled));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
int r = reader.Read(byteBlock.Buffer, 0,
|
||
|
|
(int)Math.Min(TouchRpcUtility.TransferPackage, fileOperator.MaxSpeed / 10.0));
|
||
|
|
if (r == 0)
|
||
|
|
{
|
||
|
|
channel.Complete();
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
position += r;
|
||
|
|
if (channel.TryWrite(byteBlock.Buffer, 0, r))
|
||
|
|
{
|
||
|
|
fileOperator.AddFlow(r);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
byteBlock.Dispose();
|
||
|
|
|
||
|
|
e = new FileTransferStatusEventArgs(
|
||
|
|
fileOperator.SetResult(new Result(channel.Status.ToResultCode())), args);
|
||
|
|
OnFileTransfered?.Invoke(this, e);
|
||
|
|
}
|
||
|
|
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
waitTransferPackage.Status = TouchSocketStatus.SetChannelFail.ToValue();
|
||
|
|
e = new FileTransferStatusEventArgs(new Result(ResultCode.Error, StringResStore.GetDescription(TouchSocketStatus.SetChannelFail)), args);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
waitTransferPackage.Status = TouchSocketStatus.Exception.ToValue();
|
||
|
|
waitTransferPackage.Message = ex.Message;
|
||
|
|
e = new FileTransferStatusEventArgs(new Result(ResultCode.Error, StringResStore.GetDescription(TouchSocketStatus.LoadStreamFail)), args);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
e = new FileTransferStatusEventArgs(TransferType.Pull, default, default, new Result(ResultCode.Overtime, StringResStore.GetDescription(TouchSocketStatus.GetEventArgsFail)));
|
||
|
|
waitTransferPackage.Status = TouchSocketStatus.GetEventArgsFail.ToValue();
|
||
|
|
}
|
||
|
|
|
||
|
|
waitTransferPackage.SwitchId();
|
||
|
|
SendPackage(TouchRpcUtility.P_1501_BeginPullFile_Response, waitTransferPackage);
|
||
|
|
|
||
|
|
OnFileTransfered?.Invoke(this, e);
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void RequestPullFile(object o)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
WaitFileInfoPackage waitFileInfoPackage = (WaitFileInfoPackage)o;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
FileOperator fileOperator = new FileOperator()
|
||
|
|
{
|
||
|
|
Flags = waitFileInfoPackage.Flags,
|
||
|
|
ResourcePath = waitFileInfoPackage.ResourcePath,
|
||
|
|
SavePath = waitFileInfoPackage.SavePath,
|
||
|
|
Metadata = waitFileInfoPackage.Metadata
|
||
|
|
};
|
||
|
|
|
||
|
|
FileOperationEventArgs args = new FileOperationEventArgs(TransferType.Pull,
|
||
|
|
fileOperator, null);
|
||
|
|
|
||
|
|
OnFileTransfering?.Invoke(this, args);
|
||
|
|
|
||
|
|
args.ResourcePath = FileController.GetFullPath(m_rootPath, args.ResourcePath);
|
||
|
|
|
||
|
|
if (args.IsPermitOperation)
|
||
|
|
{
|
||
|
|
if (File.Exists(args.ResourcePath))
|
||
|
|
{
|
||
|
|
//合法传输
|
||
|
|
TouchRpcFileInfo touchRpcFileInfo = new TouchRpcFileInfo();
|
||
|
|
FileController.GetFileInfo(args.ResourcePath, args.Flags.HasFlag(TransferFlags.MD5Verify), ref touchRpcFileInfo);
|
||
|
|
waitFileInfoPackage.FileInfo = touchRpcFileInfo;
|
||
|
|
waitFileInfoPackage.Status = TouchSocketStatus.Success.ToValue();
|
||
|
|
waitFileInfoPackage.EventHashCode = args.GetHashCode();
|
||
|
|
if (m_eventArgs.TryAdd(args.GetHashCode(), args))
|
||
|
|
{
|
||
|
|
EasyTask.DelayRun(1000 * 60, args, (a) =>
|
||
|
|
{
|
||
|
|
if (m_eventArgs.TryRemove(a.GetHashCode(), out object obj) && obj is FileOperationEventArgs eventArgs)
|
||
|
|
{
|
||
|
|
FileTransferStatusEventArgs e = new FileTransferStatusEventArgs(
|
||
|
|
new Result(ResultCode.Overtime, StringResStore.GetDescription(TouchSocketStatus.Overtime)), eventArgs);
|
||
|
|
OnFileTransfered?.Invoke(this, e);
|
||
|
|
}
|
||
|
|
});
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
waitFileInfoPackage.Status = TouchSocketStatus.UnknownError.ToValue();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
waitFileInfoPackage.Status = TouchSocketStatus.FileNotExists.ToValue();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
waitFileInfoPackage.Message = args.Message;
|
||
|
|
waitFileInfoPackage.Status = TouchSocketStatus.RemoteRefuse.ToValue();
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
waitFileInfoPackage.Status = TouchSocketStatus.Exception.ToValue();
|
||
|
|
waitFileInfoPackage.Message = ex.Message;
|
||
|
|
}
|
||
|
|
waitFileInfoPackage.SwitchId();
|
||
|
|
this.SendPackage(TouchRpcUtility.P_1500_PullFile_Response, waitFileInfoPackage);
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private void RequestPushFile(object o)
|
||
|
|
{
|
||
|
|
try
|
||
|
|
{
|
||
|
|
WaitFileInfoPackage waitFileInfoPackage = (WaitFileInfoPackage)o;
|
||
|
|
TouchRpcFileInfo fileInfo = waitFileInfoPackage.FileInfo;
|
||
|
|
FileOperator fileOperator = new FileOperator()
|
||
|
|
{
|
||
|
|
ResourcePath = waitFileInfoPackage.ResourcePath,
|
||
|
|
SavePath = waitFileInfoPackage.SavePath,
|
||
|
|
Flags = waitFileInfoPackage.Flags,
|
||
|
|
Metadata = waitFileInfoPackage.Metadata,
|
||
|
|
};
|
||
|
|
WaitTransferPackage waitTransferPackage = new WaitTransferPackage()
|
||
|
|
{
|
||
|
|
Sign = waitFileInfoPackage.Sign,
|
||
|
|
TargetId = waitFileInfoPackage.SourceId,
|
||
|
|
SourceId = waitFileInfoPackage.TargetId,
|
||
|
|
Route = waitFileInfoPackage.Route,
|
||
|
|
};
|
||
|
|
|
||
|
|
FileOperationEventArgs args = new FileOperationEventArgs(TransferType.Push, fileOperator, fileInfo);
|
||
|
|
OnFileTransfering?.Invoke(this, args);
|
||
|
|
|
||
|
|
waitTransferPackage.Path = args.ResourcePath;
|
||
|
|
waitTransferPackage.EventHashCode = args.GetHashCode();
|
||
|
|
|
||
|
|
if (!args.IsPermitOperation)
|
||
|
|
{
|
||
|
|
fileOperator.SetResult(new Result(ResultCode.Fail, TouchSocketStatus.RemoteRefuse.GetDescription(args.Message)));
|
||
|
|
waitTransferPackage.Message = args.Message;
|
||
|
|
waitTransferPackage.Status = TouchSocketStatus.RemoteRefuse.ToValue();
|
||
|
|
OnFileTransfered?.Invoke(this, new FileTransferStatusEventArgs(fileOperator.Result, args));
|
||
|
|
SendPackage(TouchRpcUtility.P_1502_PushFile_Response, waitTransferPackage);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
string saveFullPath = FileController.GetFullPath(m_rootPath, args.SavePath);
|
||
|
|
|
||
|
|
if (!Directory.Exists(Path.GetDirectoryName(saveFullPath)))
|
||
|
|
{
|
||
|
|
fileOperator.SetResult(new Result(ResultCode.Fail, TouchSocketStatus.DirectoryNotExists.GetDescription(Path.GetDirectoryName(saveFullPath))));
|
||
|
|
waitTransferPackage.Message = args.Message;
|
||
|
|
waitTransferPackage.Status = TouchSocketStatus.DirectoryNotExists.ToValue();
|
||
|
|
waitTransferPackage.Path = Path.GetDirectoryName(saveFullPath);
|
||
|
|
OnFileTransfered?.Invoke(this, new FileTransferStatusEventArgs(fileOperator.Result, args));
|
||
|
|
SendPackage(TouchRpcUtility.P_1502_PushFile_Response, waitTransferPackage);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
Channel channel = null;
|
||
|
|
try
|
||
|
|
{
|
||
|
|
FileController.TryReadTempInfo(saveFullPath, args.Flags, ref fileInfo);
|
||
|
|
using (TouchRpcFileStream stream = TouchRpcFileStream.Create(saveFullPath, ref fileInfo, args.Flags.HasFlag(TransferFlags.MD5Verify)))
|
||
|
|
{
|
||
|
|
if (waitFileInfoPackage.Route)
|
||
|
|
{
|
||
|
|
channel = CreateChannel(waitTransferPackage.SourceId);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
channel = CreateChannel();
|
||
|
|
}
|
||
|
|
|
||
|
|
waitTransferPackage.ChannelID = channel.ID;
|
||
|
|
waitTransferPackage.Position = fileInfo.Position;
|
||
|
|
waitTransferPackage.Status = TouchSocketStatus.Success.ToValue();
|
||
|
|
SendPackage(TouchRpcUtility.P_1502_PushFile_Response, waitTransferPackage);
|
||
|
|
|
||
|
|
fileOperator.SetFileCompletedLength(fileInfo.Position);
|
||
|
|
fileOperator.SetLength(fileInfo.Length);
|
||
|
|
while (channel.MoveNext())
|
||
|
|
{
|
||
|
|
if (fileOperator.Token.IsCancellationRequested)
|
||
|
|
{
|
||
|
|
channel.Cancel();
|
||
|
|
fileOperator.SetResult(new Result(ResultCode.Canceled));
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
byte[] data = channel.GetCurrent();
|
||
|
|
if (data != null)
|
||
|
|
{
|
||
|
|
stream.Write(data, 0, data.Length);
|
||
|
|
fileInfo.Position = stream.FileWriter.Position;
|
||
|
|
fileOperator.AddFlow(data.Length);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (channel.Status == ChannelStatus.Completed)
|
||
|
|
{
|
||
|
|
stream.FinishStream();
|
||
|
|
fileOperator.SetResult(new Result(ResultCode.Success));
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
fileOperator.SetResult(new Result(channel.Status.ToResultCode()));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch (Exception ex)
|
||
|
|
{
|
||
|
|
fileOperator.SetResult(new Result(ResultCode.Error, ex.Message));
|
||
|
|
channel?.Cancel(ex.Message);
|
||
|
|
}
|
||
|
|
finally
|
||
|
|
{
|
||
|
|
channel.SafeDispose();
|
||
|
|
}
|
||
|
|
|
||
|
|
OnFileTransfered?.Invoke(this, new FileTransferStatusEventArgs(fileOperator.Result, args));
|
||
|
|
if (channel?.Status == ChannelStatus.Completed && fileOperator.Result.IsSuccess())
|
||
|
|
{
|
||
|
|
SendPackage(TouchRpcUtility.P_509_PushFileAck_Request, new WaitPushFileAckPackage()
|
||
|
|
{
|
||
|
|
TargetId = waitFileInfoPackage.SourceId,
|
||
|
|
SourceId = waitFileInfoPackage.TargetId,
|
||
|
|
Route = waitFileInfoPackage.Route,
|
||
|
|
Sign = args.GetHashCode(),
|
||
|
|
Status = TouchSocketStatus.Success.ToValue(),
|
||
|
|
Message = fileOperator.Result.Message
|
||
|
|
});
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
SendPackage(TouchRpcUtility.P_509_PushFileAck_Request, new WaitPushFileAckPackage()
|
||
|
|
{
|
||
|
|
TargetId = waitFileInfoPackage.SourceId,
|
||
|
|
SourceId = waitFileInfoPackage.TargetId,
|
||
|
|
Route = waitFileInfoPackage.Route,
|
||
|
|
Sign = args.GetHashCode(),
|
||
|
|
Status = TouchSocketStatus.Exception.ToValue(),
|
||
|
|
Message = fileOperator.Result.Message
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
catch
|
||
|
|
{
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|