Skip to content
This repository has been archived by the owner on Jan 6, 2025. It is now read-only.

Commit

Permalink
Optimize DownloadManager code.
Browse files Browse the repository at this point in the history
  • Loading branch information
qwqcode committed Aug 10, 2019
1 parent 23b25a0 commit 308c06c
Show file tree
Hide file tree
Showing 5 changed files with 187 additions and 172 deletions.
297 changes: 163 additions & 134 deletions Nacollector/Browser/DownloadManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,184 +15,213 @@
namespace Nacollector.Browser
{
/// <summary>
/// 浏览器下载管理器
/// 配合 JS
/// 浏览器 - 下载管理器
/// </summary>
public class DownloadManager
class DownloadManager
{
public CrBrowser _crBrowser;
public static DownloadHandler downloadHandler;

private static Dictionary<int, string> dlTaskIndex = new Dictionary<int, string>();
private static Dictionary<string, int> dlTaskAction = new Dictionary<string, int>();
private CrBrowser _crBrowser;
private ChromiumWebBrowser browser;

private Dictionary<int, DownloadTask> dlTaskDict = new Dictionary<int, DownloadTask>(); // key 为 dlItem.id

/// NOTE: 任务ID (taskId, 前端使用) 区别于 下载ID (dlItem.Id)

// 前端状态
public enum Status
{
Downloading = 1, // 下载中
Pause = 2, // 暂停
Done = 3, // 下载完毕
Cancelled = 4, // 已取消
Fail = 5, // 下载错误
}

// 前端操作
public enum Action
{
Pause = 1, // 暂停
Resume = 2, // 重试
Cancel = 3 // 取消
}

public DownloadManager(CrBrowser crBrowser)
{
_crBrowser = crBrowser;
browser = _crBrowser.GetBrowser();

downloadHandler = new DownloadHandler();
downloadHandler.OnBeforeDownloadFired += (s, e) =>
{
DownloadDo("add", _crBrowser.GetBrowser(), e);
};
downloadHandler.OnDownloadUpdatedFired += (s, e) =>
{
DownloadDo("update", _crBrowser.GetBrowser(), e);
};
var handler = new DownloadHandler();
handler.OnBeforeDownloadFired += (s, e) => OnBeforeDownload(e, e.downloadItem);
handler.OnDownloadUpdatedFired += (s, e) => OnDownloadUpdated(e, e.downloadItem);

_crBrowser.GetBrowser().DownloadHandler = downloadHandler;
_crBrowser.GetBrowser().RegisterAsyncJsObject("CrDownloadsCallBack", new CrDownloadsCallBack());
_crBrowser.GetBrowser().DownloadHandler = handler;
_crBrowser.GetBrowser().RegisterAsyncJsObject("CrDownloadsCallBack", new CrDownloadsCallBack(this));
}

public class CrDownloadsCallBack
// 每个 dlItem 仅会调用一次;不一定在 OnDownloadUpdated 被调用前调用
private void OnBeforeDownload(BeforeDownloadEventArgs e, DownloadItem dlItem)
{
// 文件在资源管理器中显示
public bool fileShowInExplorer(string fileFullPath)
{
if (string.IsNullOrEmpty(fileFullPath))
return false;
DownloadTask dlTask = TryGetDlTask(dlItem);
}

if (!File.Exists(fileFullPath))
return false;
private void OnDownloadUpdated(DownloadUpdatedEventArgs e, DownloadItem dlItem)
{
DownloadTask dlTask = TryGetDlTask(dlItem);
dlTask.Update(dlItem, e.callback);
}

string argument = "/select, \"" + fileFullPath + "\"";
Process.Start("explorer.exe", argument);
return true;
}
/// <summary>
/// 获取 dlTask,若为 新dlItem,则通知前端并创建 新dlTask
/// </summary>
private DownloadTask TryGetDlTask(DownloadItem dlItem)
{
// 若不存在,则实例化一个新的
if (!dlTaskDict.ContainsKey(dlItem.Id))
dlTaskDict[dlItem.Id] = new DownloadTask(this, dlItem);

// 文件启动
public bool fileLaunch(string fileFullPath)
{
if (string.IsNullOrEmpty(fileFullPath))
return false;
return dlTaskDict[dlItem.Id];
}

if (!File.Exists(fileFullPath))
return false;
/// <summary>
/// 下载任务
/// </summary>
public class DownloadTask
{
private readonly DownloadManager DownloadManager;

Process.Start(fileFullPath);
return true;
}
public string Id { get; }

// URL 在系统默认浏览器中打开
public void urlOpenInDefaultBrowser(string url)
{
Process.Start("explorer.exe", url);
}
public DownloadItem DlItem { get; set; }

// 下达任务操作命令
public void downloadingTaskAction(string key, int action)
{
dlTaskAction[key] = action;
}
}
public IDownloadItemCallback Callback { get; set; } = null; // Callback 用于执行 Cancel, Pause 等操作

private void DownloadDo(string doType, ChromiumWebBrowser browser, EventArgs e)
{
DownloadItem downloadItem = null;
if (doType == "add")
downloadItem = ((BeforeDownloadUpdatedEventArgs)e).downloadItem;
else if (doType == "update")
downloadItem = ((DownloadUpdatedEventArgs)e).downloadItem;

// Key
string key;
if (!dlTaskIndex.ContainsKey(downloadItem.Id) && doType == "update")
{ // 若在索引中找不到 并且 doType = update
return;
}
else if (!dlTaskIndex.ContainsKey(downloadItem.Id) && doType == "add")
{
key = Utils.GetTimeStamp();
dlTaskIndex.Add(downloadItem.Id, key);
}
else
public Status Status { get; set; } // set 过后记得调用 CallFrontendUpdate

/// <summary>
/// 初始化
/// </summary>
public DownloadTask(DownloadManager downloadManager, DownloadItem dlItem)
{
key = dlTaskIndex[downloadItem.Id];
DownloadManager = downloadManager;
Id = Utils.GetTimeStamp();
DlItem = dlItem;
CallFrontendCreate();
}

// 状态
var statusList = new
{
downloading = 1, // 下载中
pause = 2, // 暂停
done = 3, // 下载完毕
cancelled = 4, // 已取消
fail = 5, // 下载错误
};

int status;
if (downloadItem.IsInProgress)
status = statusList.downloading;
else if (downloadItem.IsComplete)
status = statusList.done;
else if (downloadItem.IsCancelled)
status = statusList.cancelled;
else
status = statusList.fail;

// 任务操作
if (doType == "update")
/// <summary>
/// 更新
/// </summary>
public void Update(DownloadItem dlItem = null, IDownloadItemCallback callback = null, Status ?status = null)
{
var actionList = new
{
pause = 1,
resume = 2,
cancel = 3
};
if (dlItem != null) DlItem = dlItem;
if (callback != null) Callback = callback;

var callback = ((DownloadUpdatedEventArgs)e).callback;

int action = 0;
if (dlTaskAction.ContainsKey(key))
if (status == null)
{
action = dlTaskAction[key];
if (dlItem.IsInProgress) Status = Status.Downloading;
else if (dlItem.IsComplete) Status = Status.Done;
else if (dlItem.IsCancelled) Status = Status.Cancelled;
else Status = Status.Fail;
}
else Status = (Status)status;

CallFrontendUpdate();
}

if (action == actionList.pause) // 暂停
/// <summary>
/// 操作
/// </summary>
public void Handle(Action action)
{
if (action == Action.Cancel)
{
status = statusList.pause;
callback.Pause();
Callback.Cancel();
Update(status: Status.Cancelled);
}

if (action == actionList.resume) // 恢复
else if (action == Action.Pause)
{
status = statusList.downloading;
callback.Resume();
dlTaskAction[key] = 0; // 命令下达一次就够了!
Callback.Pause();
Update(status: Status.Pause);
}

if (action == actionList.cancel) // 取消
else if (action == Action.Resume)
{
status = statusList.cancelled;
callback.Cancel();
Callback.Resume(); // 命令仅需下达一次
Update(status: Status.Downloading);
}
}

// 回调
if (doType == "add")
/// <summary>
/// 通知前端 更新任务
/// </summary>
public void CallFrontendUpdate()
{
string callbackObj = JsonConvert.SerializeObject(new
{
key = key,
fullPath = downloadItem.SuggestedFileName,
downloadUrl = downloadItem.OriginalUrl,
totalBytes = downloadItem.TotalBytes,
key = Id,
receivedBytes = DlItem.ReceivedBytes,
currentSpeed = DlItem.CurrentSpeed,
status = Status,
fullPath = DlItem.FullPath,
downloadUrl = DlItem.Url
});
browser.ExecuteScriptAsync($"Downloads.addTask({callbackObj})");
DownloadManager.browser.ExecuteScriptAsync($"Downloads.updateTask({callbackObj})");
}
else if (doType == "update")

/// <summary>
/// 通知前端 创建新任务
/// </summary>
public void CallFrontendCreate()
{
string callbackObj = JsonConvert.SerializeObject(new
{
key = key,
receivedBytes = downloadItem.ReceivedBytes,
currentSpeed = downloadItem.CurrentSpeed,
status = status,
fullPath = downloadItem.FullPath,
downloadUrl = downloadItem.Url
key = Id,
fullPath = DlItem.SuggestedFileName,
downloadUrl = DlItem.OriginalUrl,
totalBytes = DlItem.TotalBytes,
});
browser.ExecuteScriptAsync($"Downloads.updateTask({callbackObj})");
DownloadManager.browser.ExecuteScriptAsync($"Downloads.addTask({callbackObj})");
}
}

/// <summary>
/// 暴露给前端的 methods
/// </summary>
public class CrDownloadsCallBack
{
private DownloadManager _DownloadManager;

public CrDownloadsCallBack(DownloadManager downloadManager)
{
_DownloadManager = downloadManager;
}

// 文件启动
public bool FileLaunch(string fileFullPath)
{
if (string.IsNullOrEmpty(fileFullPath) || !File.Exists(fileFullPath)) return false;
Process.Start(fileFullPath);
return true;
}

// 文件在资源管理器中显示
public bool FileShowInExplorer(string fileFullPath)
{
if (string.IsNullOrEmpty(fileFullPath) || !File.Exists(fileFullPath)) return false;
Process.Start("explorer.exe", "/select, \"" + fileFullPath + "\"");
return true;
}

// URL 在系统默认浏览器中打开
public void UrlOpenInDefaultBrowser(string url)
{
Process.Start("explorer.exe", url);
}

// 下达任务操作命令
public void DownloadingTaskAction(string dlTaskId, Action action)
{
DownloadTask dlTask = _DownloadManager.dlTaskDict.Where(o => o.Value.Id.Equals(dlTaskId)).FirstOrDefault().Value;
dlTask.Handle(action);
}
}
}
}
}
15 changes: 0 additions & 15 deletions Nacollector/Browser/Handler/BeforeDownloadUpdatedEventArgs.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ public class DownloadUpdatedEventArgs : EventArgs
public DownloadItem downloadItem { get; set; }
public IDownloadItemCallback callback { get; set; }
}

public class BeforeDownloadEventArgs : EventArgs
{
public DownloadItem downloadItem { get; set; }
public IBeforeDownloadCallback callback { get; set; }
}
}
Loading

0 comments on commit 308c06c

Please sign in to comment.