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.
738 lines
24 KiB
738 lines
24 KiB
3 years ago
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.IO;
|
||
|
using AX.Network.Common;
|
||
|
using AX.Network.Protocols;
|
||
|
using IAppSession = AX.Network.Common.IAppSession<AX.Network.Protocols.BinaryProtocol, AX.Network.Protocols.BinaryMessage>;
|
||
|
|
||
|
namespace AX.NetworkSystem
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// 表示传输类型。
|
||
|
/// </summary>
|
||
|
public enum TransferType
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// 下载。
|
||
|
/// </summary>
|
||
|
Download,
|
||
|
/// <summary>
|
||
|
/// 上传。
|
||
|
/// </summary>
|
||
|
Upload
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示文件块信息。
|
||
|
/// </summary>
|
||
|
public class ChunkInfo
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// 表示文件块对应的文件。
|
||
|
/// </summary>
|
||
|
public string Filename;
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示文件的大小。
|
||
|
/// </summary>
|
||
|
public int FileSize;
|
||
|
/// <summary>
|
||
|
/// 表示文件块的 ID。
|
||
|
/// </summary>
|
||
|
public int ChunkID;
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示文件块的总数。
|
||
|
/// </summary>
|
||
|
public int ChunkCount;
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示文件块划分的标准大小。
|
||
|
/// </summary>
|
||
|
public int ChunkSize;
|
||
|
|
||
|
public ChunkInfo() { }
|
||
|
|
||
|
public ChunkInfo(string filename, int fileSize, int chunkID, int chunkCount, int chunkSize)
|
||
|
{
|
||
|
this.Filename = filename;
|
||
|
this.FileSize = fileSize;
|
||
|
this.ChunkID = chunkID;
|
||
|
this.ChunkCount = chunkCount;
|
||
|
this.ChunkSize = chunkSize;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示简单的文件块信息。
|
||
|
/// </summary>
|
||
|
public struct SimpleChunkInfo
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// 表示文件块对应的文件。
|
||
|
/// </summary>
|
||
|
public string Filename;
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示文件块的 ID。
|
||
|
/// </summary>
|
||
|
public int ChunkID;
|
||
|
|
||
|
public SimpleChunkInfo(string filename, int chunkID)
|
||
|
{
|
||
|
this.Filename = filename;
|
||
|
this.ChunkID = chunkID;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示有附加数据的文件块信息。
|
||
|
/// </summary>
|
||
|
public struct AttachedChunkInfo
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// 表示文件块对应的文件。
|
||
|
/// </summary>
|
||
|
public string Filename;
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示文件块的 ID。
|
||
|
/// </summary>
|
||
|
public int ChunkID;
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示文件块的总数。
|
||
|
/// </summary>
|
||
|
public int ChunkCount;
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示文件块划分的标准。
|
||
|
/// </summary>
|
||
|
public int ChunkSize;
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示文件块的数据。
|
||
|
/// </summary>
|
||
|
public ArraySegment<byte> Data;
|
||
|
|
||
|
public AttachedChunkInfo(string filename, int chunkID, int chunkCount, int chunkSize, ArraySegment<byte> data)
|
||
|
{
|
||
|
this.Filename = filename;
|
||
|
this.ChunkID = chunkID;
|
||
|
this.ChunkCount = chunkCount;
|
||
|
this.ChunkSize = chunkSize;
|
||
|
this.Data = data;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示一个文件传输任务。
|
||
|
/// </summary>
|
||
|
public class TransferTask : IDisposable
|
||
|
{
|
||
|
private static readonly BufferPool BufferPool = new BufferPool(1, ChunkSize);
|
||
|
|
||
|
private const string DOWNLOAD_FILE_INFO_REQUEST = "DOWNLOAD_FILE_INFO_REQUEST";
|
||
|
private const string DOWNLOAD_CHUNK_INFO_REQUEST = "DOWNLOAD_CHUNK_INFO_REQUEST";
|
||
|
|
||
|
private const string UPLOAD_FILE_INFO_REQUEST = "UPLOAD_FILE_INFO_REQUEST";
|
||
|
private const string UPLOAD_CHUNK_INFO_REQUEST = "UPLOAD_CHUNK_INFO_REQUEST";
|
||
|
|
||
|
private const int ChunkSize = 64 * 1024;
|
||
|
|
||
|
private IAppSession appSession;
|
||
|
private FileStream filestream;
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示该任务的 ID。
|
||
|
/// </summary>
|
||
|
public int ID { get; internal set; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示本地的存储文件路径。
|
||
|
/// </summary>
|
||
|
public string[] StoragePath { get; private set; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示该传输任务的传输文件路径。
|
||
|
/// </summary>
|
||
|
public string[] TransferPath { get; private set; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示当前正在传输的文件所对应的索引位置。
|
||
|
/// </summary>
|
||
|
public int Position { get; private set; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示当前正在传输的文件块。
|
||
|
/// </summary>
|
||
|
public ChunkInfo CurrentChunk { get; private set; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示当前传输任务是下载还是上传。
|
||
|
/// </summary>
|
||
|
public TransferType TransferType { get; private set; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// 表示该任务是否已暂停。
|
||
|
/// </summary>
|
||
|
public bool IsPaused { get; private set; }
|
||
|
|
||
|
private bool isStopped;
|
||
|
|
||
|
internal TransferTask(IAppSession session, string[] storagePath, string[] transferPath, TransferType type, int taskID)
|
||
|
{
|
||
|
if (session == null)
|
||
|
throw new ArgumentNullException("session");
|
||
|
|
||
|
this.Reset(storagePath, transferPath, type, taskID);
|
||
|
|
||
|
this.appSession = session;
|
||
|
}
|
||
|
|
||
|
public event Action<string> Started;
|
||
|
public event Action<string> Paused;
|
||
|
public event Action<string> Resumed;
|
||
|
public event Action Stopped;
|
||
|
public event Action<string> TransferFileCompleted;
|
||
|
public event Action TransferTaskCompleted;
|
||
|
public event Action<float, float> ProgressChanged;
|
||
|
|
||
|
protected virtual void OnStarted(string filename)
|
||
|
{
|
||
|
if (Started != null)
|
||
|
Started(filename);
|
||
|
}
|
||
|
|
||
|
protected virtual void OnPaused(string filename)
|
||
|
{
|
||
|
if (Paused != null)
|
||
|
Paused(filename);
|
||
|
}
|
||
|
|
||
|
protected virtual void OnResumed(string filename)
|
||
|
{
|
||
|
if (Resumed != null)
|
||
|
Resumed(filename);
|
||
|
}
|
||
|
|
||
|
protected virtual void OnStopped()
|
||
|
{
|
||
|
if (Stopped != null)
|
||
|
Stopped();
|
||
|
}
|
||
|
|
||
|
protected virtual void OnTransferFileCompleted(string filename)
|
||
|
{
|
||
|
if (TransferFileCompleted != null)
|
||
|
TransferFileCompleted(filename);
|
||
|
}
|
||
|
|
||
|
protected virtual void OnTransferTaskCompleted()
|
||
|
{
|
||
|
if (TransferTaskCompleted != null)
|
||
|
TransferTaskCompleted();
|
||
|
}
|
||
|
|
||
|
protected virtual void OnProgressChanged(float curr, float total)
|
||
|
{
|
||
|
if (ProgressChanged != null)
|
||
|
ProgressChanged(curr, total);
|
||
|
}
|
||
|
|
||
|
public void Start()
|
||
|
{
|
||
|
isStopped = false;
|
||
|
|
||
|
OnStarted(CurrentChunk.Filename);
|
||
|
|
||
|
// 下载
|
||
|
if (TransferType == TransferType.Download)
|
||
|
{
|
||
|
if (CurrentChunk.ChunkID == 0 && CurrentChunk.ChunkCount == 0 && CurrentChunk.FileSize == 0)
|
||
|
appSession.SendRequestAsync(DOWNLOAD_FILE_INFO_REQUEST, CurrentChunk.Filename);
|
||
|
else
|
||
|
{
|
||
|
var info = new SimpleChunkInfo(CurrentChunk.Filename, CurrentChunk.ChunkID);
|
||
|
appSession.SendRequestAsync(DOWNLOAD_CHUNK_INFO_REQUEST, info);
|
||
|
}
|
||
|
}
|
||
|
// 上传
|
||
|
else
|
||
|
{
|
||
|
var filename = StoragePath[Position];
|
||
|
var fileinfo = new FileInfo(filename);
|
||
|
|
||
|
var fileSize = (int)fileinfo.Length;
|
||
|
var chunkCount = fileSize % ChunkSize == 0 ? fileSize / ChunkSize : fileSize / ChunkSize + 1;
|
||
|
|
||
|
CurrentChunk.FileSize = fileSize;
|
||
|
CurrentChunk.ChunkCount = chunkCount;
|
||
|
|
||
|
if (CurrentChunk.ChunkID == 0)
|
||
|
{
|
||
|
var info = new ChunkInfo(CurrentChunk.Filename, fileSize, CurrentChunk.ChunkID, CurrentChunk.ChunkCount, CurrentChunk.ChunkSize);
|
||
|
|
||
|
appSession.SendRequestAsync(UPLOAD_FILE_INFO_REQUEST, info);
|
||
|
}
|
||
|
else
|
||
|
UploadFileChunk(filename);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Pause()
|
||
|
{
|
||
|
if (!isStopped && !IsPaused)
|
||
|
{
|
||
|
IsPaused = true;
|
||
|
|
||
|
OnPaused(CurrentChunk.Filename);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Resume()
|
||
|
{
|
||
|
if (!isStopped && IsPaused)
|
||
|
{
|
||
|
IsPaused = false;
|
||
|
|
||
|
OnResumed(CurrentChunk.Filename);
|
||
|
|
||
|
if (TransferType == TransferType.Download)
|
||
|
{
|
||
|
if (CurrentChunk.ChunkID == 0 && CurrentChunk.ChunkCount == 0 && CurrentChunk.FileSize == 0)
|
||
|
appSession.SendRequestAsync(DOWNLOAD_FILE_INFO_REQUEST, CurrentChunk.Filename);
|
||
|
else
|
||
|
{
|
||
|
var info = new SimpleChunkInfo(CurrentChunk.Filename, CurrentChunk.ChunkID);
|
||
|
|
||
|
appSession.SendRequestAsync(DOWNLOAD_CHUNK_INFO_REQUEST, info);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var filename = StoragePath[Position];
|
||
|
var fileinfo = new FileInfo(filename);
|
||
|
|
||
|
var fileSize = (int)fileinfo.Length;
|
||
|
var chunkCount = fileSize % ChunkSize == 0 ? fileSize / ChunkSize : fileSize / ChunkSize + 1;
|
||
|
|
||
|
CurrentChunk.FileSize = fileSize;
|
||
|
CurrentChunk.ChunkCount = chunkCount;
|
||
|
|
||
|
if (CurrentChunk.ChunkID == 0)
|
||
|
{
|
||
|
var info = new ChunkInfo(CurrentChunk.Filename, fileSize, CurrentChunk.ChunkID, CurrentChunk.ChunkCount, CurrentChunk.ChunkSize);
|
||
|
|
||
|
appSession.SendRequestAsync(UPLOAD_FILE_INFO_REQUEST, info);
|
||
|
}
|
||
|
else
|
||
|
UploadFileChunk(filename);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public void Stop()
|
||
|
{
|
||
|
isStopped = true;
|
||
|
IsPaused = false;
|
||
|
|
||
|
OnStopped();
|
||
|
}
|
||
|
|
||
|
public void Dispose()
|
||
|
{
|
||
|
this.Reset();
|
||
|
|
||
|
if (filestream != null)
|
||
|
filestream.Dispose();
|
||
|
|
||
|
if (appSession != null)
|
||
|
appSession = null;
|
||
|
}
|
||
|
|
||
|
public void Reset()
|
||
|
{
|
||
|
this.Position = 0;
|
||
|
this.IsPaused = false;
|
||
|
this.isStopped = false;
|
||
|
|
||
|
this.CurrentChunk = new ChunkInfo(); ;
|
||
|
this.CurrentChunk.Filename = ID + "://" + TransferPath[0];
|
||
|
this.CurrentChunk.FileSize = 0;
|
||
|
this.CurrentChunk.ChunkID = 0;
|
||
|
this.CurrentChunk.ChunkCount = 0;
|
||
|
this.CurrentChunk.ChunkSize = ChunkSize;
|
||
|
}
|
||
|
|
||
|
public void Reset(string[] storagePath, string[] transferPath, TransferType type, int taskID)
|
||
|
{
|
||
|
if (storagePath == null)
|
||
|
throw new ArgumentNullException("storagePath");
|
||
|
|
||
|
if (transferPath == null)
|
||
|
throw new ArgumentNullException("transferPath");
|
||
|
|
||
|
if (storagePath.Length != transferPath.Length)
|
||
|
throw new ArgumentOutOfRangeException("storagePath or transferPath");
|
||
|
|
||
|
for (var i = 0; i < storagePath.Length; ++i)
|
||
|
if (string.IsNullOrEmpty(storagePath[i]))
|
||
|
throw new ArgumentException("storagePath or transferPath");
|
||
|
|
||
|
this.StoragePath = storagePath;
|
||
|
this.TransferPath = transferPath;
|
||
|
this.TransferType = type;
|
||
|
this.ID = taskID;
|
||
|
|
||
|
this.Reset();
|
||
|
}
|
||
|
|
||
|
internal void ProcessDownloadFileReplyInfo(ref ChunkInfo info)
|
||
|
{
|
||
|
CurrentChunk.FileSize = info.FileSize;
|
||
|
CurrentChunk.ChunkID = 0;
|
||
|
CurrentChunk.ChunkCount = info.ChunkCount;
|
||
|
|
||
|
// 先创建文件夹
|
||
|
var filename = StoragePath[Position];
|
||
|
|
||
|
var folder = Path.GetDirectoryName(filename);
|
||
|
|
||
|
if (!string.IsNullOrEmpty(folder) && !Directory.Exists(folder))
|
||
|
Directory.CreateDirectory(folder);
|
||
|
|
||
|
if (isStopped || IsPaused)
|
||
|
return;
|
||
|
|
||
|
var chunkInfo = new SimpleChunkInfo(CurrentChunk.Filename, CurrentChunk.ChunkID);
|
||
|
|
||
|
appSession.SendRequestAsync(DOWNLOAD_CHUNK_INFO_REQUEST, chunkInfo);
|
||
|
}
|
||
|
|
||
|
internal void ProcessDownloadChunkReplyInfo(ref AttachedChunkInfo info)
|
||
|
{
|
||
|
var filename = StoragePath[Position];
|
||
|
|
||
|
if (filestream == null)
|
||
|
filestream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write, info.Data.Count, false);
|
||
|
|
||
|
// 写入文件
|
||
|
filestream.Seek(info.ChunkID * info.ChunkSize, SeekOrigin.Begin);
|
||
|
filestream.Write(info.Data.Array, info.Data.Offset, info.Data.Count);
|
||
|
filestream.Flush();
|
||
|
|
||
|
CurrentChunk.ChunkID += 1;
|
||
|
|
||
|
// 还未下载完该文件的所有文件块
|
||
|
if (CurrentChunk.ChunkID != CurrentChunk.ChunkCount)
|
||
|
{
|
||
|
var currProgress = ((float)info.ChunkID / (float)info.ChunkCount) * 100.0f;
|
||
|
var totalProgress = ((float)Position / (float)StoragePath.Length) * 100.0f;
|
||
|
|
||
|
// 报告进度
|
||
|
OnProgressChanged(currProgress, totalProgress);
|
||
|
|
||
|
if (isStopped || IsPaused)
|
||
|
return;
|
||
|
|
||
|
// 继续下载剩余文件块
|
||
|
var chunkInfo = new SimpleChunkInfo(CurrentChunk.Filename, CurrentChunk.ChunkID);
|
||
|
|
||
|
appSession.SendRequestAsync(DOWNLOAD_CHUNK_INFO_REQUEST, chunkInfo);
|
||
|
}
|
||
|
// 已下载完一个文件的所有文件块
|
||
|
else
|
||
|
{
|
||
|
if (filestream != null)
|
||
|
{
|
||
|
filestream.Close();
|
||
|
filestream = null;
|
||
|
}
|
||
|
|
||
|
++Position;
|
||
|
|
||
|
// 全部下载完成
|
||
|
if (Position == StoragePath.Length)
|
||
|
{
|
||
|
var currProgress = 100.0f;
|
||
|
var totalProgress = 100.0f;
|
||
|
|
||
|
// 报告进度
|
||
|
OnProgressChanged(currProgress, totalProgress);
|
||
|
OnTransferTaskCompleted();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var currProgress = 100.0f;
|
||
|
var totalProgress = ((float)Position / (float)StoragePath.Length) * 100.0f;
|
||
|
|
||
|
// 报告进度
|
||
|
OnProgressChanged(currProgress, totalProgress);
|
||
|
OnTransferFileCompleted(info.Filename);
|
||
|
|
||
|
CurrentChunk.Filename = ID + "://" + TransferPath[Position];
|
||
|
CurrentChunk.ChunkID = 0;
|
||
|
CurrentChunk.ChunkCount = 0;
|
||
|
CurrentChunk.FileSize = 0;
|
||
|
|
||
|
if (isStopped || IsPaused)
|
||
|
return;
|
||
|
|
||
|
// 继续下载剩余的文件
|
||
|
appSession.SendRequestAsync(DOWNLOAD_FILE_INFO_REQUEST, CurrentChunk.Filename);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
internal void ProcessUploadFileReplyInfo(ref SimpleChunkInfo info)
|
||
|
{
|
||
|
CurrentChunk.ChunkID = 0;
|
||
|
|
||
|
if (isStopped || IsPaused)
|
||
|
return;
|
||
|
|
||
|
// 开始上传文件块
|
||
|
UploadFileChunk(StoragePath[Position]);
|
||
|
}
|
||
|
|
||
|
internal void ProcessUploadChunkReplyInfo(ref SimpleChunkInfo info)
|
||
|
{
|
||
|
CurrentChunk.ChunkID += 1;
|
||
|
|
||
|
// 表示还没上传完一个文件
|
||
|
if (CurrentChunk.ChunkID != CurrentChunk.ChunkCount)
|
||
|
{
|
||
|
var currProgress = ((float)CurrentChunk.ChunkID / (float)CurrentChunk.ChunkCount) * 100.0f;
|
||
|
var totalProgress = ((float)Position / (float)StoragePath.Length) * 100.0f;
|
||
|
|
||
|
// 报告进度
|
||
|
OnProgressChanged(currProgress, totalProgress);
|
||
|
|
||
|
if (isStopped || IsPaused)
|
||
|
return;
|
||
|
|
||
|
// 继续上传剩余的文件块
|
||
|
UploadFileChunk(StoragePath[Position]);
|
||
|
}
|
||
|
// 已上传完一个文件的所有文件块
|
||
|
else
|
||
|
{
|
||
|
if (filestream != null)
|
||
|
{
|
||
|
filestream.Close();
|
||
|
filestream = null;
|
||
|
}
|
||
|
|
||
|
++Position;
|
||
|
|
||
|
// 全部上传完成
|
||
|
if (Position == StoragePath.Length)
|
||
|
{
|
||
|
var currProgress = 100.0f;
|
||
|
var totalProgress = 100.0f;
|
||
|
|
||
|
// 报告进度
|
||
|
OnProgressChanged(currProgress, totalProgress);
|
||
|
OnTransferTaskCompleted();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var currProgress = 100.0f;
|
||
|
var totalProgress = ((float)Position / (float)StoragePath.Length) * 100.0f;
|
||
|
|
||
|
// 报告进度
|
||
|
OnProgressChanged(currProgress, totalProgress);
|
||
|
OnTransferFileCompleted(info.Filename);
|
||
|
|
||
|
CurrentChunk.Filename = ID + "://" + TransferPath[Position];
|
||
|
CurrentChunk.ChunkID = 0;
|
||
|
|
||
|
var fileinfo = new FileInfo(StoragePath[Position]);
|
||
|
|
||
|
var fileSize = (int)fileinfo.Length;
|
||
|
var chunkCount = fileSize % ChunkSize == 0 ? fileSize / ChunkSize : fileSize / ChunkSize + 1;
|
||
|
|
||
|
CurrentChunk.FileSize = fileSize;
|
||
|
CurrentChunk.ChunkCount = chunkCount;
|
||
|
|
||
|
if (isStopped || IsPaused)
|
||
|
return;
|
||
|
|
||
|
// 继续上传剩余的文件
|
||
|
var upInfo = new ChunkInfo(CurrentChunk.Filename, CurrentChunk.FileSize, CurrentChunk.ChunkID, CurrentChunk.ChunkCount, CurrentChunk.ChunkSize);
|
||
|
|
||
|
appSession.SendRequestAsync(UPLOAD_FILE_INFO_REQUEST, upInfo);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private void UploadFileChunk(string filename)
|
||
|
{
|
||
|
if (filestream == null)
|
||
|
filestream = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Read, FileShare.Read, ChunkSize, false);
|
||
|
|
||
|
var buffer = BufferPool.Acquire();
|
||
|
|
||
|
var count = filestream.Read(buffer, 0, ChunkSize);
|
||
|
var data = new ArraySegment<byte>(buffer, 0, count);
|
||
|
|
||
|
var info = new AttachedChunkInfo(CurrentChunk.Filename, CurrentChunk.ChunkID, CurrentChunk.ChunkCount, CurrentChunk.ChunkSize, data);
|
||
|
|
||
|
appSession.SendRequestAsync(UPLOAD_CHUNK_INFO_REQUEST, info);
|
||
|
|
||
|
BufferPool.Release(buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 该类用于文件传输,可下载,也可上传。
|
||
|
/// </summary>
|
||
|
public static class FileTransfer
|
||
|
{
|
||
|
private const string DOWNLOAD_FILE_INFO_REPLY = "DOWNLOAD_FILE_INFO_REPLY";
|
||
|
private const string DOWNLOAD_CHUNK_INFO_REPLY = "DOWNLOAD_CHUNK_INFO_REPLY";
|
||
|
|
||
|
private const string UPLOAD_FILE_INFO_REPLY = "UPLOAD_FILE_INFO_REPLY";
|
||
|
private const string UPLOAD_CHUNK_INFO_REPLY = "UPLOAD_CHUNK_INFO_REPLY";
|
||
|
|
||
|
private static readonly string[] Delimiters = new string[] { "://" };
|
||
|
|
||
|
private static List<TransferTask> taskList = new List<TransferTask>();
|
||
|
|
||
|
/// <summary>
|
||
|
/// 初始化。
|
||
|
/// </summary>
|
||
|
public static void Initialize()
|
||
|
{
|
||
|
NetworkMessageDispatcher.AddListener(DOWNLOAD_FILE_INFO_REPLY, ProcessDownloadFileReplyInfo);
|
||
|
NetworkMessageDispatcher.AddListener(DOWNLOAD_CHUNK_INFO_REPLY, ProcessDownloadChunkReplyInfo);
|
||
|
NetworkMessageDispatcher.AddListener(UPLOAD_FILE_INFO_REPLY, ProcessUploadFileReplyInfo);
|
||
|
NetworkMessageDispatcher.AddListener(UPLOAD_CHUNK_INFO_REPLY, UploadChunkReplyInfo);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 销毁资源。
|
||
|
/// </summary>
|
||
|
public static void Dispose()
|
||
|
{
|
||
|
NetworkMessageDispatcher.RemoveListener(DOWNLOAD_FILE_INFO_REPLY, ProcessDownloadFileReplyInfo);
|
||
|
NetworkMessageDispatcher.RemoveListener(DOWNLOAD_CHUNK_INFO_REPLY, ProcessDownloadChunkReplyInfo);
|
||
|
NetworkMessageDispatcher.RemoveListener(UPLOAD_FILE_INFO_REPLY, ProcessUploadFileReplyInfo);
|
||
|
NetworkMessageDispatcher.RemoveListener(UPLOAD_CHUNK_INFO_REPLY, UploadChunkReplyInfo);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// 开启一个传输任务。
|
||
|
/// </summary>
|
||
|
/// <param name="session">传输时使用的会话</param>
|
||
|
/// <param name="storagePath">本地的存储文件路径</param>
|
||
|
/// <param name="transferPath">要传输的文件路径</param>
|
||
|
/// <param name="type">传输类型</param>
|
||
|
public static TransferTask CreateTransferTask(IAppSession session, string[] storagePath, string[] transferPath, TransferType type)
|
||
|
{
|
||
|
var task = new TransferTask(session, storagePath, transferPath, type, taskList.Count);
|
||
|
taskList.Add(task);
|
||
|
return task;
|
||
|
}
|
||
|
|
||
|
public static bool DestroyTransferTask(TransferTask task)
|
||
|
{
|
||
|
if (task == null)
|
||
|
return true;
|
||
|
|
||
|
task.Dispose();
|
||
|
return taskList.Remove(task);
|
||
|
}
|
||
|
|
||
|
public static bool DestroyTransferTask(int taskID)
|
||
|
{
|
||
|
var index = taskList.FindIndex((task) => task.ID == taskID);
|
||
|
|
||
|
if (index < 0)
|
||
|
return false;
|
||
|
|
||
|
taskList[index].Dispose();
|
||
|
taskList.RemoveAt(index);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
public static TransferTask GetTransferTask(int taskID)
|
||
|
{
|
||
|
var index = taskList.FindIndex((task) => task.ID == taskID);
|
||
|
|
||
|
if (index < 0)
|
||
|
return null;
|
||
|
|
||
|
return taskList[index];
|
||
|
}
|
||
|
|
||
|
public static List<TransferTask> GetTaskList()
|
||
|
{
|
||
|
return taskList;
|
||
|
}
|
||
|
|
||
|
public static void Clear()
|
||
|
{
|
||
|
for (var i = 0; i < taskList.Count; ++i)
|
||
|
taskList[i].Dispose();
|
||
|
|
||
|
taskList.Clear();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
private static void ProcessDownloadFileReplyInfo(BinaryMessage message)
|
||
|
{
|
||
|
var info = message.Body.Deserialize<ChunkInfo>();
|
||
|
var array = info.Filename.Split(Delimiters, StringSplitOptions.None);
|
||
|
|
||
|
var taskID = int.Parse(array[0]);
|
||
|
|
||
|
var task = GetTransferTask(taskID);
|
||
|
|
||
|
if (task != null)
|
||
|
task.ProcessDownloadFileReplyInfo(ref info);
|
||
|
}
|
||
|
|
||
|
private static void ProcessDownloadChunkReplyInfo(BinaryMessage message)
|
||
|
{
|
||
|
var info = message.Body.Deserialize<AttachedChunkInfo>();
|
||
|
var array = info.Filename.Split(Delimiters, StringSplitOptions.None);
|
||
|
|
||
|
var taskID = int.Parse(array[0]);
|
||
|
|
||
|
var task = GetTransferTask(taskID);
|
||
|
|
||
|
if (task != null)
|
||
|
task.ProcessDownloadChunkReplyInfo(ref info);
|
||
|
}
|
||
|
|
||
|
private static void ProcessUploadFileReplyInfo(BinaryMessage message)
|
||
|
{
|
||
|
var info = message.Body.Deserialize<SimpleChunkInfo>();
|
||
|
var array = info.Filename.Split(Delimiters, StringSplitOptions.None);
|
||
|
|
||
|
var taskID = int.Parse(array[0]);
|
||
|
|
||
|
var task = GetTransferTask(taskID);
|
||
|
|
||
|
if (task != null)
|
||
|
task.ProcessUploadFileReplyInfo(ref info);
|
||
|
}
|
||
|
|
||
|
private static void UploadChunkReplyInfo(BinaryMessage message)
|
||
|
{
|
||
|
var info = message.Body.Deserialize<SimpleChunkInfo>();
|
||
|
var array = info.Filename.Split(Delimiters, StringSplitOptions.None);
|
||
|
|
||
|
var taskID = int.Parse(array[0]);
|
||
|
|
||
|
var task = GetTransferTask(taskID);
|
||
|
|
||
|
if (task != null)
|
||
|
task.ProcessUploadChunkReplyInfo(ref info);
|
||
|
}
|
||
|
}
|
||
|
}
|