SunnyUI/SunnyUI/Common/UThunder.cs
2024-05-02 23:37:18 +08:00

773 lines
21 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/******************************************************************************
* SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
* CopyRight (C) 2012-2024 ShenYongHua(沈永华).
* QQ群56829229 QQ17612584 EMailSunnyUI@QQ.Com
*
* Blog: https://www.cnblogs.com/yhuse
* Gitee: https://gitee.com/yhuse/SunnyUI
* GitHub: https://github.com/yhuse/SunnyUI
*
* SunnyUI.dll can be used for free under the GPL-3.0 license.
* If you use this code, please keep this note.
* 如果您使用此代码,请保留此说明。
******************************************************************************
* 文件名称: UThunder.cs
* 文件说明: 迅雷下载帮助类
* 当前版本: V3.1
* 创建日期: 2020-01-01
*
* 2020-01-01: V2.2.0 增加文件说明
******************************************************************************/
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
#pragma warning disable 1591
namespace Sunny.UI
{
public class Thunder : IDisposable
{
private readonly Timer timer;
private bool Exit;
public delegate void OnTaskInfoChange(object sender, ThunderTask task);
public readonly ConcurrentDictionary<string, ThunderTask> Tasks = new ConcurrentDictionary<string, ThunderTask>();
public event OnTaskInfoChange TaskInfoChange;
public event OnTaskInfoChange TaskComplete;
public bool InitSuccess { get; }
public bool AutoManage { get; set; }
public int MaxTaskCount { get; set; } = 10;
public Thunder()
{
InitSuccess = ThunderDll.Init();
timer = new Timer();
timer.Interval = 1000;
timer.Tick += Timer_Tick;
timer.Start();
}
~Thunder()
{
timer?.Stop();
timer?.Dispose();
}
private void Timer_Tick(object sender, EventArgs e)
{
timer.Stop();
foreach (var task in Tasks.Values)
{
if (!task.IsStart || task.IsStop || task.IsComplete)
{
continue;
}
ThunderDll.QueryTaskInfo(task.ID, task.Info);
if (task.Info.Status == ThunderDll.DOWN_TASK_STATUS.TSC_STOPENDING)
{
task.IsStop = true;
}
if (task.Info.Status == ThunderDll.DOWN_TASK_STATUS.TSC_COMPLETE)
{
TaskComplete?.Invoke(this, task);
task.IsComplete = true;
}
TaskInfoChange?.Invoke(this, task);
}
if (AutoManage)
{
int cnt = RunTaskCount();
if (cnt < MaxTaskCount)
{
foreach (var task in Tasks.Values)
{
if (!task.IsStart)
{
task.StartTask();
cnt++;
}
if (cnt >= MaxTaskCount)
{
break;
}
}
}
DeleteCompleted();
}
if (!Exit)
{
timer.Start();
}
}
public int RunTaskCount()
{
int cnt = 0;
foreach (var task in Tasks.Values)
{
if (task.IsStart && !task.IsComplete)
{
cnt++;
}
}
return cnt;
}
/// <summary>
/// 析构函数
/// </summary>
public void Dispose()
{
timer.Stop();
Exit = true;
ThunderDll.Final();
}
public ThunderTask CreateTask(string url, string savefile)
{
if (Tasks.ContainsKey(url))
{
return Tasks[url];
}
ThunderTask task = new ThunderTask(url, savefile);
task.ID = ThunderDll.CreateTask(task.Param);
Tasks.TryAdd(url, task);
return task;
}
public bool DeleteTask(ThunderTask task, bool deletefile = false)
{
bool result = ThunderDll.DeleteTask(task.ID);
if (deletefile)
{
ThunderDll.DelTempFile(task.Param);
}
Tasks.TryRemove(task.URL, out _);
return result;
}
public void DeleteCompleted()
{
List<string> urls = new List<string>();
foreach (var task in Tasks.Values)
{
if (task.IsComplete)
{
urls.Add(task.URL);
}
}
foreach (var url in urls)
{
Tasks.TryRemove(url, out _);
}
}
}
public class ThunderTask
{
public IntPtr ID { get; set; }
public ThunderDll.DownTaskInfo Info { get; set; }
public ThunderDll.DownTaskParam Param { get; set; }
public bool IsStart { get; set; }
public bool IsStop { get; set; }
public bool IsComplete { get; set; }
public string URL { get; private set; }
public string SaveFile { get; private set; }
public ThunderTask(string url, string savefile)
{
URL = url;
SaveFile = savefile;
Param = ThunderDll.CreateDownTaskParam(url, savefile);
Info = new ThunderDll.DownTaskInfo();
}
}
public static class ThunderDll
{
public static bool StartTask(this ThunderTask task)
{
bool result = StartTask(task.ID);
task.IsStart = result;
task.IsStop = false;
return result;
}
public static bool StopTask(this ThunderTask task)
{
return StopTask(task.ID);
}
public static bool Init()
{
return XL_Init();
}
public static bool Final()
{
return XL_UnInit();
}
public static IntPtr CreateTask(string url, string savefile)
{
return XL_CreateTask(CreateDownTaskParam(url, savefile));
}
public static IntPtr CreateTask(DownTaskParam param)
{
return XL_CreateTask(param);
}
public static DownTaskParam CreateDownTaskParam(string url, string savefile)
{
return new DownTaskParam
{
szTaskUrl = url,
szFilename = Path.GetFileName(savefile),
szSavePath = Path.GetDirectoryName(savefile)
};
}
public static bool StartTask(IntPtr task)
{
return XL_StartTask(task);
}
public static bool StopTask(IntPtr task)
{
return XL_StopTask(task);
}
public static object SetSpeedLimit(int KBps)
{
return XL_SetSpeedLimit(KBps);
}
public static object DelTempFile(DownTaskParam param)
{
return XL_DelTempFile(param);
}
public static bool DeleteTask(IntPtr task)
{
return XL_DeleteTask(task);
}
public static bool GetFileSize(string url, long filesize)
{
return XL_GetFileSizeWithUrl(url, filesize);
}
public static bool QueryTaskInfo(IntPtr task, DownTaskInfo info)
{
return XL_QueryTaskInfoEx(task, info);
}
public static DownTaskInfo QueryTaskInfo(IntPtr task)
{
DownTaskInfo info = new DownTaskInfo();
return XL_QueryTaskInfoEx(task, info) ? info : null;
}
public static IntPtr CreateBTTask(DownBTTaskParam param)
{
return XL_CreateBTTask(param);
}
public static long QueryBTFileInfo(IntPtr task, UIntPtr fileindex, ulong filesize, ulong completesize, UIntPtr status)
{
return XL_QueryBTFileInfo(task, fileindex, filesize, completesize, status);
}
public static BTTaskInfo QueryBTFileInfo(IntPtr task)
{
BTTaskInfo info = new BTTaskInfo();
XL_QueryBTFileInfo(task, info);
return info;
}
public static long QueryBTFileInfo(IntPtr task, BTTaskInfo info)
{
return XL_QueryBTFileInfo(task, info);
}
[DllImport("xldl.dll", CharSet = CharSet.Unicode)]
private static extern bool XL_Init();
[DllImport("xldl.dll", CharSet = CharSet.Unicode)]
private static extern bool XL_UnInit();
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr XL_CreateTask([In] DownTaskParam stParam);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool XL_StartTask(IntPtr hTask);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool XL_StopTask(IntPtr hTask);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern object XL_SetSpeedLimit(int nKBps);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern int XL_CreateTaskByThunder(string pszUrl, string pszFileName, string pszReferUrl, string pszCharSet, string pszCookie);
//LONG XL_CreateTaskByThunder(wchar_t *pszUrl, wchar_t *pszFileName, wchar_t *pszReferUrl, wchar_t *pszCharSet, wchar_t *pszCookie)
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern object XL_SetUploadSpeedLimit(int nTcpKBps, int nOtherKBps);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern object XL_SetProxy(DOWN_PROXY_INFO stProxyInfo);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern object XL_DelTempFile(DownTaskParam stParam);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool XL_DeleteTask(IntPtr hTask);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool XL_GetBtDataFileList(string szFilePath, string szSeedFileFullPath);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool XL_SetUserAgent(string pszUserAgent);
[DllImport("xldl.dll", CallingConvention = CallingConvention.Cdecl)]
private static extern bool XL_GetFileSizeWithUrl(string lpURL, long iFileSize);
[DllImport("xldl.dll", EntryPoint = "XL_QueryTaskInfoEx", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool XL_QueryTaskInfoEx(IntPtr hTask, [Out] DownTaskInfo stTaskInfo);
[DllImport("xldl.dll", EntryPoint = "XL_QueryTaskInfoEx", CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr XL_CreateBTTask(DownBTTaskParam stParam);
[DllImport("xldl.dll", EntryPoint = "XL_QueryTaskInfoEx", CallingConvention = CallingConvention.Cdecl)]
private static extern long XL_QueryBTFileInfo(IntPtr hTask, UIntPtr dwFileIndex, ulong ullFileSize, ulong ullCompleteSize, UIntPtr dwStatus);
[DllImport("xldl.dll", EntryPoint = "XL_QueryTaskInfoEx", CallingConvention = CallingConvention.Cdecl)]
private static extern long XL_QueryBTFileInfo(IntPtr hTask, BTTaskInfo pTaskInfo);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)]
public class DownTaskParam
{
public int nReserved;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2084)]
public string szTaskUrl;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2084)]
public string szRefUrl;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 4096)]
public string szCookies;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szFilename;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szReserved0;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szSavePath;
public IntPtr hReserved;
public int bReserved = 0;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string szReserved1;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string szReserved2;
public int IsOnlyOriginal = 0;
public uint nReserved1 = 5;
public int DisableAutoRename = 0;
public int IsResume = 1;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2048, ArraySubType = UnmanagedType.U4)]
public uint[] reserved;
}
[StructLayout(LayoutKind.Sequential)]
public struct BTTaskInfo
{
public int lTaskStatus;
public uint dwUsingResCount;
public uint dwSumResCount;
public ulong ullRecvBytes;
public ulong ullSendBytes;
[MarshalAs(UnmanagedType.Bool)]
public bool bFileCreated;
public uint dwSeedCount;
public uint dwConnectedBTPeerCount;
public uint dwAllBTPeerCount;
public uint dwHealthyGrade;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class DownTaskInfo
{
public DOWN_TASK_STATUS Status;
public TASK_ERROR_TYPE FailCode;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string Filename;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string ReservedString;
public long TotalSize;
public long TotalDownload;
public float Percent;
public int Reserved0;
public int SrcTotal;
public int SrcUsing;
public int Reserved1;
public int Reserved2;
public int Reserved3;
public int Reserved4;
public long Reserved5;
public long DonationP2P;
public long Reserved6;
public long DonationOrgin;
public long DonationP2S;
public long Reserved7;
public long Reserved8;
public int Speed;
public int SpeedP2S;
public int SpeedP2P;
public bool IsOriginUsable;
public float HashPercent;
public int IsCreatingFile;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 64, ArraySubType = UnmanagedType.U4)]
public uint[] Reserved;
public override string ToString()
{
return Status.DisplayText() + ",已完成:" + (Percent * 100.0f).ToString("F2") + "%,速度:" + Speed + "KB/s";
}
}
/// <summary>
/// 状态
/// </summary>
public enum DOWN_TASK_STATUS
{
/// <summary>
/// 无
/// </summary>
[DisplayText("无")]
NOITEM = 0,
/// <summary>
/// 错误
/// </summary>
[DisplayText("错误")]
TSC_ERROR,
/// <summary>
/// 暂停
/// </summary>
[DisplayText("暂停")]
TSC_PAUSE,
/// <summary>
/// 下载
/// </summary>
[DisplayText("下载中")]
TSC_DOWNLOAD,
/// <summary>
/// 完成
/// </summary>
[DisplayText("完成")]
TSC_COMPLETE,
/// <summary>
/// 停止开始
/// </summary>
[DisplayText("已开始")]
TSC_STARTENDING,
/// <summary>
/// 停止完成
/// </summary>
[DisplayText("已停止")]
TSC_STOPENDING
}
/// <summary>
/// 错误码
/// </summary>
public enum TASK_ERROR_TYPE
{
TASK_ERROR_UNKNOWN = 0,
TASK_ERROR_DISK_CREATE = 1,
TASK_ERROR_DISK_WRITE = 2,
TASK_ERROR_DISK_READ = 3,
TASK_ERROR_DISK_RENAME = 4,
TASK_ERROR_DISK_PIECEHASH = 5,
TASK_ERROR_DISK_FILEHASH = 6,
TASK_ERROR_DISK_DELETE = 7,
TASK_ERROR_DOWN_INVALID = 16,
TASK_ERROR_PROXY_AUTH_TYPE_UNKOWN = 32,
TASK_ERROR_PROXY_AUTH_TYPE_FAILED = 33,
TASK_ERROR_HTTPMGR_NOT_IP = 48,
TASK_ERROR_TIMEOUT = 64,
TASK_ERROR_CANCEL = 65,
TASK_ERROR_TP_CRASHED = 66,
TASK_ERROR_ID_INVALID = 67
}
/// <summary>
/// 代理类型
/// </summary>
public enum DOWN_PROXY_TYPE
{
PROXY_TYPE_IE = 0,
PROXY_TYPE_HTTP = 1,
PROXY_TYPE_SOCK4 = 2,
PROXY_TYPE_SOCK5 = 3,
PROXY_TYPE_FTP = 4,
PROXY_TYPE_UNKOWN = 255
}
/// <summary>
/// 代理模式
/// </summary>
public enum DOWN_PROXY_AUTH_TYPE
{
PROXY_AUTH_NONE = 0,
PROXY_AUTH_AUTO,
PROXY_AUTH_BASE64,
PROXY_AUTH_NTLM,
PROXY_AUTH_DEGEST,
PROXY_AUTH_UNKOWN
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public class DOWN_PROXY_INFO
{
[MarshalAs(UnmanagedType.Bool)]
public bool bIEProxy;
[MarshalAs(UnmanagedType.Bool)]
public bool bProxy;
public DOWN_PROXY_TYPE stPType;
public DOWN_PROXY_AUTH_TYPE stAType;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2048)]
public string szHost;
public int nPort;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string szUser;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 50)]
public string szPwd;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 2048)]
public string szDomain;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class TrackerInfo
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string szTrackerUrl;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
public class DownBTTaskParam
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szSeedFullPath;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string szFilePath;
public uint dwNeedDownloadFileCount;
public IntPtr dwNeedDownloadFileIndexArray;
public uint dwTrackerInfoCount;
public IntPtr pTrackerInfoArray;
public int IsResume;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class tracker_info
{
public uint tracker_url_len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string tracker_url;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class bt_file_info
{
public ulong file_size;
public uint path_len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string file_path;
public uint name_len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string file_name;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class bt_seed_file_info
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
public string info_id;
public uint title_len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string title;
public uint file_info_count;
public IntPtr file_info_array;
public uint tracker_count;
public IntPtr tracker_info_array;
public uint publisher_len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 8192)]
public string publisher;
public uint publisher_url_len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string publisher_url;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class bt_data_file_item
{
public uint path_len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string file_path;
public uint name_len;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 1024)]
public string file_name;
}
[StructLayout(LayoutKind.Sequential)]
public class bt_data_file_list
{
public uint item_count;
public IntPtr item_array;
}
}
}