//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 loyalsoft. All rights reserved.
// Homepage: http://www.game7000.com/
// Feedback: http://www.game7000.com/
//------------------------------------------------------------
using System;
using System.IO;
namespace GameFramework.Download
{
internal sealed partial class DownloadManager : GameFrameworkModule, IDownloadManager
{
///
/// 下载代理。
///
private sealed class DownloadAgent : ITaskAgent, IDisposable
{
private readonly IDownloadAgentHelper m_Helper;
private DownloadTask m_Task;
private FileStream m_FileStream;
private int m_WaitFlushSize;
private float m_WaitTime;
private long m_StartLength;
private long m_DownloadedLength;
private long m_SavedLength;
private bool m_Disposed;
public GameFrameworkAction DownloadAgentStart;
public GameFrameworkAction DownloadAgentUpdate;
public GameFrameworkAction DownloadAgentSuccess;
public GameFrameworkAction DownloadAgentFailure;
///
/// 初始化下载代理的新实例。
///
/// 下载代理辅助器。
public DownloadAgent(IDownloadAgentHelper downloadAgentHelper)
{
if (downloadAgentHelper == null)
{
throw new GameFrameworkException("Download agent helper is invalid.");
}
m_Helper = downloadAgentHelper;
m_Task = null;
m_FileStream = null;
m_WaitFlushSize = 0;
m_WaitTime = 0f;
m_StartLength = 0L;
m_DownloadedLength = 0L;
m_SavedLength = 0L;
m_Disposed = false;
DownloadAgentStart = null;
DownloadAgentUpdate = null;
DownloadAgentSuccess = null;
DownloadAgentFailure = null;
}
///
/// 获取下载任务。
///
public DownloadTask Task
{
get
{
return m_Task;
}
}
///
/// 获取已经等待时间。
///
public float WaitTime
{
get
{
return m_WaitTime;
}
}
///
/// 获取开始下载时已经存在的大小。
///
public long StartLength
{
get
{
return m_StartLength;
}
}
///
/// 获取本次已经下载的大小。
///
public long DownloadedLength
{
get
{
return m_DownloadedLength;
}
}
///
/// 获取当前的大小。
///
public long CurrentLength
{
get
{
return m_StartLength + m_DownloadedLength;
}
}
///
/// 获取已经存盘的大小。
///
public long SavedLength
{
get
{
return m_SavedLength;
}
}
///
/// 初始化下载代理。
///
public void Initialize()
{
m_Helper.DownloadAgentHelperUpdateBytes += OnDownloadAgentHelperUpdateBytes;
m_Helper.DownloadAgentHelperUpdateLength += OnDownloadAgentHelperUpdateLength;
m_Helper.DownloadAgentHelperComplete += OnDownloadAgentHelperComplete;
m_Helper.DownloadAgentHelperError += OnDownloadAgentHelperError;
}
///
/// 下载代理轮询。
///
/// 逻辑流逝时间,以秒为单位。
/// 真实流逝时间,以秒为单位。
public void Update(float elapseSeconds, float realElapseSeconds)
{
if (m_Task.Status == DownloadTaskStatus.Doing)
{
m_WaitTime += realElapseSeconds;
if (m_WaitTime >= m_Task.Timeout)
{
DownloadAgentHelperErrorEventArgs downloadAgentHelperErrorEventArgs = DownloadAgentHelperErrorEventArgs.Create(false, "Timeout");
OnDownloadAgentHelperError(this, downloadAgentHelperErrorEventArgs);
ReferencePool.Release(downloadAgentHelperErrorEventArgs);
}
}
}
///
/// 关闭并清理下载代理。
///
public void Shutdown()
{
Dispose();
m_Helper.DownloadAgentHelperUpdateBytes -= OnDownloadAgentHelperUpdateBytes;
m_Helper.DownloadAgentHelperUpdateLength -= OnDownloadAgentHelperUpdateLength;
m_Helper.DownloadAgentHelperComplete -= OnDownloadAgentHelperComplete;
m_Helper.DownloadAgentHelperError -= OnDownloadAgentHelperError;
}
///
/// 开始处理下载任务。
///
/// 要处理的下载任务。
/// 开始处理任务的状态。
public StartTaskStatus Start(DownloadTask task)
{
if (task == null)
{
throw new GameFrameworkException("Task is invalid.");
}
m_Task = task;
m_Task.Status = DownloadTaskStatus.Doing;
string downloadFile = Utility.Text.Format("{0}.download", m_Task.DownloadPath);
try
{
if (File.Exists(downloadFile))
{
m_FileStream = File.OpenWrite(downloadFile);
m_FileStream.Seek(0L, SeekOrigin.End);
m_StartLength = m_SavedLength = m_FileStream.Length;
m_DownloadedLength = 0L;
}
else
{
string directory = Path.GetDirectoryName(m_Task.DownloadPath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
m_FileStream = new FileStream(downloadFile, FileMode.Create, FileAccess.Write);
m_StartLength = m_SavedLength = m_DownloadedLength = 0L;
}
if (DownloadAgentStart != null)
{
DownloadAgentStart(this);
}
if (m_StartLength > 0L)
{
m_Helper.Download(m_Task.DownloadUri, m_StartLength, m_Task.UserData);
}
else
{
m_Helper.Download(m_Task.DownloadUri, m_Task.UserData);
}
return StartTaskStatus.CanResume;
}
catch (Exception exception)
{
DownloadAgentHelperErrorEventArgs downloadAgentHelperErrorEventArgs = DownloadAgentHelperErrorEventArgs.Create(false, exception.ToString());
OnDownloadAgentHelperError(this, downloadAgentHelperErrorEventArgs);
ReferencePool.Release(downloadAgentHelperErrorEventArgs);
return StartTaskStatus.UnknownError;
}
}
///
/// 重置下载代理。
///
public void Reset()
{
m_Helper.Reset();
if (m_FileStream != null)
{
m_FileStream.Close();
m_FileStream = null;
}
m_Task = null;
m_WaitFlushSize = 0;
m_WaitTime = 0f;
m_StartLength = 0L;
m_DownloadedLength = 0L;
m_SavedLength = 0L;
}
///
/// 释放资源。
///
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
///
/// 释放资源。
///
/// 释放资源标记。
private void Dispose(bool disposing)
{
if (m_Disposed)
{
return;
}
if (disposing)
{
if (m_FileStream != null)
{
m_FileStream.Dispose();
m_FileStream = null;
}
}
m_Disposed = true;
}
private void OnDownloadAgentHelperUpdateBytes(object sender, DownloadAgentHelperUpdateBytesEventArgs e)
{
m_WaitTime = 0f;
try
{
m_FileStream.Write(e.GetBytes(), e.Offset, e.Length);
m_WaitFlushSize += e.Length;
m_SavedLength += e.Length;
if (m_WaitFlushSize >= m_Task.FlushSize)
{
m_FileStream.Flush();
m_WaitFlushSize = 0;
}
}
catch (Exception exception)
{
DownloadAgentHelperErrorEventArgs downloadAgentHelperErrorEventArgs = DownloadAgentHelperErrorEventArgs.Create(false, exception.ToString());
OnDownloadAgentHelperError(this, downloadAgentHelperErrorEventArgs);
ReferencePool.Release(downloadAgentHelperErrorEventArgs);
}
}
private void OnDownloadAgentHelperUpdateLength(object sender, DownloadAgentHelperUpdateLengthEventArgs e)
{
m_WaitTime = 0f;
m_DownloadedLength += e.DeltaLength;
if (DownloadAgentUpdate != null)
{
DownloadAgentUpdate(this, e.DeltaLength);
}
}
private void OnDownloadAgentHelperComplete(object sender, DownloadAgentHelperCompleteEventArgs e)
{
m_WaitTime = 0f;
m_DownloadedLength = e.Length;
if (m_SavedLength != CurrentLength)
{
throw new GameFrameworkException("Internal download error.");
}
m_Helper.Reset();
m_FileStream.Close();
m_FileStream = null;
if (File.Exists(m_Task.DownloadPath))
{
File.Delete(m_Task.DownloadPath);
}
File.Move(Utility.Text.Format("{0}.download", m_Task.DownloadPath), m_Task.DownloadPath);
m_Task.Status = DownloadTaskStatus.Done;
if (DownloadAgentSuccess != null)
{
DownloadAgentSuccess(this, e.Length);
}
m_Task.Done = true;
}
private void OnDownloadAgentHelperError(object sender, DownloadAgentHelperErrorEventArgs e)
{
m_Helper.Reset();
if (m_FileStream != null)
{
m_FileStream.Close();
m_FileStream = null;
}
if (e.DeleteDownloading)
{
File.Delete(Utility.Text.Format("{0}.download", m_Task.DownloadPath));
}
m_Task.Status = DownloadTaskStatus.Error;
if (DownloadAgentFailure != null)
{
DownloadAgentFailure(this, e.ErrorMessage);
}
m_Task.Done = true;
}
}
}
}