Kaynağa Gözat

mxg:添加调度器

mengxiangge 5 yıl önce
işleme
6eb0d7001c
59 değiştirilmiş dosya ile 3382 ekleme ve 0 silme
  1. 29 0
      Dispatcher/.gitignore
  2. 25 0
      Dispatcher/Client/Class1.cs
  3. 149 0
      Dispatcher/Client/Client.csproj
  4. 64 0
      Dispatcher/Client/ClientApp.cs
  5. 89 0
      Dispatcher/Client/ClientInfo.cs
  6. 20 0
      Dispatcher/Client/IRevitCommandExcutor.cs
  7. 112 0
      Dispatcher/Client/MessageHandler.cs
  8. 36 0
      Dispatcher/Client/Properties/AssemblyInfo.cs
  9. 25 0
      Dispatcher/Client/Readme.txt
  10. 41 0
      Dispatcher/Client/Start/CustomMessage.cs
  11. 32 0
      Dispatcher/Client/Start/RevitCmdExecutor.cs
  12. 32 0
      Dispatcher/Client/Start/ServiceMBIClientHandler.cs
  13. 193 0
      Dispatcher/Client/TaskHandler.cs
  14. 71 0
      Dispatcher/Client/app.config
  15. 69 0
      Dispatcher/Client/packages.config
  16. BIN
      Dispatcher/Dlls/R2017/AdWindows.dll
  17. BIN
      Dispatcher/Dlls/R2017/RevitAPI.dll
  18. BIN
      Dispatcher/Dlls/R2017/RevitAPIIFC.dll
  19. BIN
      Dispatcher/Dlls/R2017/RevitAPILink.dll
  20. BIN
      Dispatcher/Dlls/R2017/RevitAPIUI.dll
  21. BIN
      Dispatcher/Dlls/R2017/RevitAPIUILink.dll
  22. BIN
      Dispatcher/Dlls/RevitRefDll/AdWindows.dll
  23. BIN
      Dispatcher/Dlls/RevitRefDll/RevitAPI.dll
  24. BIN
      Dispatcher/Dlls/RevitRefDll/RevitAPIIFC.dll
  25. BIN
      Dispatcher/Dlls/RevitRefDll/RevitAPILink.dll
  26. BIN
      Dispatcher/Dlls/RevitRefDll/RevitAPIUI.dll
  27. BIN
      Dispatcher/Dlls/RevitRefDll/RevitAPIUILink.dll
  28. BIN
      Dispatcher/Dlls/RevitRefDll/RevitAddInUtility.dll
  29. BIN
      Dispatcher/Dlls/SAGA.DotNetUtils.dll
  30. BIN
      Dispatcher/Dlls/SAGA.Models.dll
  31. BIN
      Dispatcher/Dlls/SAGA.RevitAPI.dll
  32. BIN
      Dispatcher/Dlls/SAGA.RevitUtils.dll
  33. 150 0
      Dispatcher/HttpDownload/DownloadTask.cs
  34. 51 0
      Dispatcher/HttpDownload/HttpDownload.csproj
  35. 281 0
      Dispatcher/HttpDownload/HttpDownloader.cs
  36. 184 0
      Dispatcher/HttpDownload/LimitedConcurrencyLevelTaskScheduler.cs
  37. 36 0
      Dispatcher/HttpDownload/Properties/AssemblyInfo.cs
  38. 128 0
      Dispatcher/HttpDownload/TaskDownloadManager.cs
  39. 13 0
      Dispatcher/NettyClient/ClientWrapper.cs
  40. 132 0
      Dispatcher/NettyClient/NettyClient.csproj
  41. 6 0
      Dispatcher/NettyClient/NettyClient.csproj.user
  42. 36 0
      Dispatcher/NettyClient/Properties/AssemblyInfo.cs
  43. 82 0
      Dispatcher/NettyClient/SimpleMessageHandler.cs
  44. 109 0
      Dispatcher/NettyClient/TaskNettyClient.cs
  45. 75 0
      Dispatcher/NettyClient/app.config
  46. 72 0
      Dispatcher/NettyClient/packages.config
  47. 224 0
      Dispatcher/NettyClient/proto/MessageProto - 复制.cs
  48. 225 0
      Dispatcher/NettyClient/proto/MessageProto.cs
  49. 19 0
      Dispatcher/NettyClient/proto/MessageUtil.cs
  50. 79 0
      Dispatcher/ServiceMBI.sln
  51. 44 0
      Dispatcher/TaskDatabase/Mappings/TaskModel.hbm.xml
  52. 15 0
      Dispatcher/TaskDatabase/Model/DownloadTaskModel.cs
  53. 28 0
      Dispatcher/TaskDatabase/Model/TaskModel.cs
  54. 42 0
      Dispatcher/TaskDatabase/NHibernateHelper.cs
  55. 36 0
      Dispatcher/TaskDatabase/Properties/AssemblyInfo.cs
  56. 94 0
      Dispatcher/TaskDatabase/TaskDatabase.csproj
  57. 213 0
      Dispatcher/TaskDatabase/TaskService.cs
  58. 11 0
      Dispatcher/TaskDatabase/hibernate.cfg.xml
  59. 10 0
      Dispatcher/TaskDatabase/packages.config

+ 29 - 0
Dispatcher/.gitignore

@@ -0,0 +1,29 @@
+################################################################################
+# 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。
+################################################################################
+
+/SAGA.RevitMenu/obj
+/OutputDll
+/ServiceMBI/obj/Debug
+/.vs/ServiceMBI/v15/sqlite3
+/Client/bin/Debug
+/Client/obj/Debug
+/.vs/ServiceMBI/v15
+/ClientTests/bin/Debug
+/ClientTests/obj/Debug
+/HttpDownload/bin/Debug
+/HttpDownload/obj/Debug
+/NettyClient/bin/Debug
+/NettyClient/obj/Debug
+/packages
+/SAGA.Revit/obj/Debug
+/SAGA.Revit/obj/RR17
+/ServiceMBI.Modes/obj/Debug
+/TaskDatabase/bin/Debug
+/TaskDatabase/obj/Debug
+/testDll/bin/Debug
+/testDll/obj/Debug
+/MBIUtility/bin/Debug
+/MBIUtility/obj/Debug
+/ServiceMBI.Request/bin/Debug
+/ServiceMBI.Request/obj/Debug

+ 25 - 0
Dispatcher/Client/Class1.cs

@@ -0,0 +1,25 @@
+using System;
+using System.Windows.Forms;
+using Client.Start;
+
+namespace Client
+{
+    public class Class1
+    {
+        public static void Main()
+        {
+            MessageBox.Show("start");
+            try
+            {
+                ServiceMBIClientHandler.Start();
+            }
+            catch (Exception ex)
+            {
+
+                MessageBox.Show(ex.Message);
+            }
+
+            MessageBox.Show("end");
+        }
+    }
+}

+ 149 - 0
Dispatcher/Client/Client.csproj

@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}</ProjectGuid>
+    <OutputType>Exe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>Client</RootNamespace>
+    <AssemblyName>Client</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\OutputDll\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject />
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="DotNetty.Buffers, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Buffers.0.6.0\lib\net45\DotNetty.Buffers.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Common, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Common.0.6.0\lib\net45\DotNetty.Common.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Transport, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Transport.0.6.0\lib\net45\DotNetty.Transport.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Protobuf, Version=3.2.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+      <HintPath>..\packages\Google.Protobuf.3.2.0\lib\net45\Google.Protobuf.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Binder, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Logging.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Options, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Options.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Primitives, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Primitives.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=12.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\packages\Newtonsoft.Json.12.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="SAGA.DotNetUtils, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\Dlls\SAGA.DotNetUtils.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.ComponentModel.Annotations.4.5.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ComponentModel.Composition" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
+    </Reference>
+    <Reference Include="System.IO.Compression.FileSystem" />
+    <Reference Include="System.Management" />
+    <Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Numerics" />
+    <Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Class1.cs" />
+    <Compile Include="ClientApp.cs" />
+    <Compile Include="ClientInfo.cs" />
+    <Compile Include="IRevitCommandExcutor.cs" />
+    <Compile Include="MessageHandler.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Start\CustomMessage.cs" />
+    <Compile Include="Start\RevitCmdExecutor.cs" />
+    <Compile Include="Start\ServiceMBIClientHandler.cs" />
+    <Compile Include="TaskHandler.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\HttpDownload\HttpDownload.csproj">
+      <Project>{9f423033-98a9-4b6b-9bb1-f1aa8c648a02}</Project>
+      <Name>HttpDownload</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\NettyClient\NettyClient.csproj">
+      <Project>{7a08d4e8-a171-47bd-a527-bc9ba1833305}</Project>
+      <Name>NettyClient</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\TaskDatabase\TaskDatabase.csproj">
+      <Project>{ade36aa5-fca8-4e5b-a27e-2360884404b3}</Project>
+      <Name>TaskDatabase</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Readme.txt" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 64 - 0
Dispatcher/Client/ClientApp.cs

@@ -0,0 +1,64 @@
+using HttpDownload;
+using NettyClient;
+using System.Threading;
+using TaskDatabase;
+
+namespace Client
+{
+    public class ClientApp
+    {
+        TaskNettyClient client;                    // 网络传输客户端
+        SimpleMessageHandler simpleHandler;        // 网络传输处理
+        TaskService taskService;                   // 持久化任务
+        TaskDownloadManager taskDownloadManager;   // 下载任务文件(Http)
+        MessageHandler messageHandler;             // 处理客户端收到的消息
+        TaskHandler taskHandler;                   // 处理服务端发送的任务(监视下载状况等待)
+        int maxTaskCount;                          // 能处理的最大任务数量, 影响是否拒绝服务器分发的任务
+        string defaultFileDir;                     // 默认文件目录
+        IRevitCommandExcutor revitCommandExcutor;  
+        public ClientApp(string ip, int port, string dir, int maxTaskCount, IRevitCommandExcutor revitCommandExcutor, int maxDownTaskCount=5) {
+            client = new TaskNettyClient(ip, port);
+            taskService = new TaskService();
+            taskDownloadManager = new TaskDownloadManager(maxDownTaskCount);
+            this.maxTaskCount = maxTaskCount;
+            defaultFileDir = dir;
+            this.revitCommandExcutor = revitCommandExcutor;
+        }
+
+        public void Start() {
+            
+            simpleHandler = new SimpleMessageHandler();
+            if (messageHandler == null)
+            {
+                taskHandler = new TaskHandler(simpleHandler, taskService, taskDownloadManager, defaultFileDir, revitCommandExcutor);
+                taskHandler.SyncAllTask();
+                messageHandler = new MessageHandler(simpleHandler, maxTaskCount, taskHandler);
+                messageHandler.ResumeAllTasks();
+                ThreadPool.QueueUserWorkItem(messageHandler.HandleMessage);
+                ThreadPool.QueueUserWorkItem(taskHandler.RunTasks);
+            }
+            else
+            {
+                messageHandler.setSimpleMessageHandler(simpleHandler);
+                taskHandler.setSimpleMessageHandler(simpleHandler);
+            }
+            client.RunClientAsync(simpleHandler).Wait();
+        }
+
+        public void Close() {
+            client.CloseAsync().Wait();
+        }
+
+        public void PauseAllTask() {
+            taskDownloadManager.pauseAllTasks();
+            messageHandler.PauseAllTasks();
+        }
+        public void ResumeAllTask()
+        {
+            taskDownloadManager.resumeAllTasks();
+            messageHandler.ResumeAllTasks();
+        }
+    }
+
+    
+}

+ 89 - 0
Dispatcher/Client/ClientInfo.cs

@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Management;
+using System.Net;
+
+namespace Client
+{
+    public class ClientInfo
+    {
+        public string MacAddr { get; set; }
+        public string Ipv4 { get; set; }
+        public string Name { get; set; }
+    }
+    public class ClientInfoUtil {
+        /// <summary>  
+        /// 获取本机MAC地址  
+        /// </summary>  
+        /// <returns>本机MAC地址</returns>  
+        public static string GetMacAddress()
+        {
+            try
+            {
+                string strMac = string.Empty;
+                ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
+                ManagementObjectCollection moc = mc.GetInstances();
+                foreach (ManagementObject mo in moc)
+                {
+                    if ((bool)mo["IPEnabled"] == true)
+                    {
+                        strMac = mo["MacAddress"].ToString();
+                    }
+                }
+                moc = null;
+                mc = null;
+                return strMac;
+            }
+            catch
+            {
+                return "unknown";
+            }
+        }
+        /// <summary>  
+        /// 操作系统的登录用户名  
+        /// </summary>  
+        /// <returns>系统的登录用户名</returns>  
+        public static string GetUserName()
+        {
+            try
+            {
+                string strUserName = string.Empty;
+                ManagementClass mc = new ManagementClass("Win32_ComputerSystem");
+                ManagementObjectCollection moc = mc.GetInstances();
+                foreach (ManagementObject mo in moc)
+                {
+                    strUserName = mo["UserName"].ToString();
+                }
+                moc = null;
+                mc = null;
+                return strUserName;
+            }
+            catch
+            {
+                return "unknown";
+            }
+        }
+        /// <summary>  
+        /// 获取客户端内网IPv4地址  
+        /// </summary>  
+        /// <returns>客户端内网IPv4地址</returns>  
+        public static string GetClientLocalIPv4Address()
+        {
+            string strLocalIP = string.Empty;
+            try
+            {
+                IPHostEntry ipHost = Dns.Resolve(Dns.GetHostName());
+                IPAddress ipAddress = ipHost.AddressList[0];
+                strLocalIP = ipAddress.ToString();
+                return strLocalIP;
+            }
+            catch
+            {
+                return "unknown";
+            }
+        }
+    }
+}

+ 20 - 0
Dispatcher/Client/IRevitCommandExcutor.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Client
+{
+    public interface IRevitCommandExcutor
+    {
+        /// <summary>
+        /// 执行Revit命令
+        /// </summary>
+        /// <param name="revitCmd">被执行的Revit命令</param>
+        /// <param name="param">执行命令的参数</param>
+        /// <param name="filePathList">用到的文件的路径</param>
+        /// <returns>任务执行结果返回json格式字符串</returns>
+        string ExecuteCmd(string revitCmd, string param, HashSet<string> filePathList);
+    }
+}

+ 112 - 0
Dispatcher/Client/MessageHandler.cs

@@ -0,0 +1,112 @@
+using NettyClient;
+using NettyClient.proto;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Client
+{
+    class MessageHandler
+    {
+        private SimpleMessageHandler simpleHandler;
+        private TaskHandler taskHandler;
+        private bool isPauseTask = false;
+        private int maxTaskCount;
+        public MessageHandler(SimpleMessageHandler simpleHandler, int maxTaskCount, TaskHandler taskHandler) {
+            this.simpleHandler = simpleHandler;
+            this.maxTaskCount = maxTaskCount;
+            this.taskHandler = taskHandler;
+        }
+        public void setSimpleMessageHandler(SimpleMessageHandler simpleHandler) {
+            this.simpleHandler = simpleHandler;
+        }
+        public void HandleMessage(object obj) {
+            while (true) {
+                Message message;
+                bool hasMsg = SimpleMessageHandler.messageQueue.TryDequeue(out message);
+                if (!hasMsg) {
+                    Thread.Sleep(500);
+                    continue;
+                }
+                Command command = Command.Useless;
+                try
+                {
+                     command = (Command)Enum.Parse(typeof(Command), message.Cmd);
+                }
+                catch { command = Command.Useless; }
+                Message retMsg;
+                switch (command) {
+                    case Command.SendTask:
+                        // 1. 检测是否接受该任务 
+                        if (checkIsAcceptTask(message.TaskId))
+                        {
+                            // 2. 如果接受, 保存任务到数据库, 并同步该任务到内存, 并交由任务执行线程开始执行
+                            bool isSuccess = taskHandler.addOneTask(message.TaskId, message.Content);
+                            if (isSuccess)
+                            {
+                                retMsg = MessageUtil.generateMessage(Command.AcceptTask.ToString(), message.TaskId, "");
+                                simpleHandler.WriteMessage(retMsg);
+                            }
+                        }
+                        else {
+                            // 3. 如果拒绝, 直接返回拒绝消息
+                            retMsg = MessageUtil.generateMessage(Command.RefuseTask.ToString(), message.TaskId, "");
+                            simpleHandler.WriteMessage(retMsg);
+                        }
+                        break;
+                    case Command.ClientInfo: // 服务端要求客户端返回客户端信息
+                        ClientInfo info = new ClientInfo();
+                        info.Ipv4 = ClientInfoUtil.GetClientLocalIPv4Address();
+                        info.MacAddr = ClientInfoUtil.GetMacAddress();
+                        info.Name = ClientInfoUtil.GetUserName();
+                        retMsg = MessageUtil.generateMessage(Command.ClientInfo.ToString(), 0, JsonConvert.SerializeObject(info, Formatting.None));
+                        simpleHandler.WriteMessage(retMsg);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+
+        private bool checkIsAcceptTask(int taskId)
+        {
+            //一. isPauseTask == true的时候拒绝任务, 二. 如果已存在该任务, 则拒绝, 三. 如果当前任务数达到maxTaskCount, 拒绝
+            if (isPauseTask)
+                return false;
+            if (taskHandler.isContainTask(taskId)) {
+                return false;
+            }
+            if (taskHandler.taskModels.Count >= maxTaskCount)
+                return false;
+            return true;
+
+
+        }
+
+        internal void PauseAllTasks()
+        {
+            isPauseTask = true;
+        }
+
+        internal void ResumeAllTasks()
+        {
+            isPauseTask = false;
+        }
+    }
+
+    enum Command
+    {
+        SendTask,
+        RefuseTask,
+        AcceptTask,
+        DownloadError,
+        CommandError,
+        TaskSuccess,
+        ClientInfo,
+        Useless
+    }
+}

+ 36 - 0
Dispatcher/Client/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("Client")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Client")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("6a52af44-63c6-4ab6-92d4-2a05173d45fb")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 25 - 0
Dispatcher/Client/Readme.txt

@@ -0,0 +1,25 @@
+用到的dll
+DotNetty.Transport (>= 0.6.0)
+DotNetty.Buffers (>= 0.6.0)
+DotNetty.Common (>= 0.6.0)
+Microsoft.Extensions.Logging (1.1.0)
+Microsoft.Extensions.Logging.Abstractions(1.1.0)
+
+DotNetty.Codecs.Protobuf
+DotNetty.Codecs
+
+Google.Protobuf 3.2.0(最新版本3.7.0)
+
+数据库
+
+Mysql.Data 8.0
+NHibernate  5.2.5
+
+
+
+JSON
+newtonsoft.json
+
+
+直接运行Client会报错。
+启动Revit可以通信。

+ 41 - 0
Dispatcher/Client/Start/CustomMessage.cs

@@ -0,0 +1,41 @@
+/* ==============================================================================
+ * 功能描述:自定义消息
+ * 创 建 者:Garrett
+ * 创建日期:2019/4/12 11:55:31
+ * ==============================================================================*/
+
+namespace Client.Start
+{
+    /// <summary>
+    /// DotMessage
+    /// </summary>
+    class CustomMessage
+    {
+        public CustomMessage(bool mResult, string mResultMsg)
+        {
+            m_Result = mResult;
+            m_ResultMsg = mResultMsg;
+        }
+        private bool m_Result;
+        /// <summary>
+        /// 状态,暂定为bool类型
+        /// </summary>
+        public bool Result
+        {
+            get { return m_Result; }
+            set { m_Result = value; }
+        }
+
+        private string m_ResultMsg;
+        /// <summary>
+        /// 消息提示
+        /// </summary>
+        public string ResultMsg
+        {
+            get { return m_ResultMsg; }
+            set { m_ResultMsg = value; }
+        }
+
+
+    }
+}

+ 32 - 0
Dispatcher/Client/Start/RevitCmdExecutor.cs

@@ -0,0 +1,32 @@
+/* ==============================================================================
+ * 功能描述:RevitCmdExecutor  
+ * 创 建 者:Garrett
+ * 创建日期:2019/4/16 11:46:37
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+
+namespace Client.Start
+{
+    /// <summary>
+    /// RevitCmdExecutor
+    /// </summary>
+    public class RevitCmdExecutor : IRevitCommandExcutor
+    {
+        public string ExecuteCmd(string revitCmd, string param, HashSet<string> filePathList)
+        {
+            //由revitCmd生成实体类
+            //实体类传入参数、参考楼层列表
+            //执行方法,返回执行结果 
+            Console.WriteLine("准备执行命令");
+
+            string msg = null;
+            MessageBox.Show("命令执行完成 ");
+
+            return msg;
+        }
+     
+    }
+}

+ 32 - 0
Dispatcher/Client/Start/ServiceMBIClientHandler.cs

@@ -0,0 +1,32 @@
+/* ==============================================================================
+ * 功能描述:ServiceMBIClientHandler  
+ * 创 建 者:Garrett
+ * 创建日期:2019/4/12 15:08:46
+ * ==============================================================================*/
+
+using System;
+using System.Windows.Forms;
+using TaskDatabase;
+using TaskDatabase.Model;
+
+namespace Client.Start
+{
+    /// <summary>
+    /// ServiceMBIClientHandler
+    /// </summary>
+    public class ServiceMBIClientHandler
+    {
+        private static ClientApp m_Client;
+        public static void Start()
+        {
+            m_Client = new ClientApp("172.16.0.131", 6666, "E:\\", 3, new RevitCmdExecutor(), 5);
+            m_Client.Start();
+            //Console.ReadKey();
+        }
+
+        public static void Stop()
+        {
+            m_Client?.Close();
+        }
+    }
+}

+ 193 - 0
Dispatcher/Client/TaskHandler.cs

@@ -0,0 +1,193 @@
+using HttpDownload;
+using NettyClient;
+using NettyClient.proto;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using TaskDatabase;
+using TaskDatabase.Model;
+
+namespace Client
+{
+    class TaskHandler
+    {
+        private SimpleMessageHandler simpleHandler;
+        private TaskService taskService;
+        public IList<TaskModel> taskModels;
+        private TaskDownloadManager taskDownloadManager;
+        private string defaultFileDir;
+        IRevitCommandExcutor revitCommandExcutor;
+
+        public void RunTasks(object obj) {
+            while (true) {
+                try
+                {
+                    for (int i = taskModels.Count - 1; i > -1; --i) {
+                        TaskModel task = taskModels[i];
+                        TaskModel downloadException = null, commandException = null;
+                        bool isAllDownloaded = true;
+                        // 看当前任务依赖的文件下载状况
+                        foreach (DownloadTaskModel downloadTaskModel in task.DownloadTaskModelList) {
+                            DownloadTask download = taskDownloadManager.getDownloadTaskByDownloadTaskId(downloadTaskModel.Tid);
+                            if (download == null) // 如果还未加入下载队列
+                            {
+                                // 开始下载
+                                if (downloadTaskModel.Local_dir == null) {
+                                    downloadTaskModel.Local_dir = defaultFileDir + downloadTaskModel.Tid + ".rvt";
+                                } 
+                                download = taskDownloadManager.enqueueTask(task.Id, downloadTaskModel.Tid, downloadTaskModel.Task_url,
+                                    downloadTaskModel.Local_dir, downloadTaskModel.Task_md5, downloadTaskModel.Downloaded_bytes);
+                                taskDownloadManager.runTask(download);
+                                isAllDownloaded &= false;
+                            }
+                            else {
+                                // 如果该下载发生异常
+                                if (download.Status == DownloadStatus.ExceptionStopped) {
+                                    isAllDownloaded &= false;
+                                    downloadException = task;
+                                    break;
+                                }
+                                // 同步当前状态到数据库
+                                if (download.Status == DownloadStatus.Completed)
+                                {
+                                    downloadTaskModel.Finish_time = GetTimeStampSeconds();
+                                    isAllDownloaded &= true;
+                                }
+                                else {
+                                    isAllDownloaded &= false;
+                                }
+                                syncSingleDownTask(download, downloadTaskModel);
+                            }
+                        } // foreach end
+                        // 如果该下载任务下载失败
+                        if (downloadException != null)
+                        {
+                            task.Task_status = -1;
+                            taskService.UpdateTask(task);
+                            taskModels.RemoveAt(i);
+                            simpleHandler.WriteMessage(MessageUtil.generateMessage(Command.DownloadError.ToString(), task.Id, ""));
+                            continue;
+                        }
+                        // 如果该任务的所有下载文件均已完成, 开始执行Revit命令
+                        if (isAllDownloaded) {
+                            try
+                            {
+                                HashSet<string> fileSet = new HashSet<string>();
+                                foreach(var downloadModel in task.DownloadTaskModelList) {
+                                    fileSet.Add(downloadModel.Local_dir);
+                                }
+                                try
+                                {
+                                    string resultJson = revitCommandExcutor.ExecuteCmd(task.Task_cmd, task.Task_param, fileSet);
+                                    simpleHandler.WriteMessage(MessageUtil.generateMessage(Command.TaskSuccess.ToString(), task.Id, resultJson));
+                                    task.Task_status = 1;
+                                    task.Task_result_json = resultJson;
+                                    taskService.UpdateTask(task);
+                                    taskModels.RemoveAt(i);
+                                }
+                                catch(Exception ex) {
+                                    Console.WriteLine(ex.StackTrace);
+                                    commandException = task;
+                                }
+                            }
+                            catch(Exception ex) {
+                                Console.WriteLine(ex.StackTrace);
+                            }
+                        }
+                        if (commandException != null)
+                        {
+                            task.Task_status = -2;
+                            taskService.UpdateTask(task);
+                            taskModels.RemoveAt(i);
+                            simpleHandler.WriteMessage(MessageUtil.generateMessage(Command.CommandError.ToString(), task.Id, ""));
+                            continue;
+                        }
+                    }
+                    taskService.removeErrorTask();
+                }
+                catch (Exception ex){
+                    Console.WriteLine(ex.StackTrace);
+                }
+                Thread.Sleep(1000);
+                
+            }
+        }
+
+        private void syncSingleDownTask(DownloadTask downTask, DownloadTaskModel downloadModel)
+        {
+            bool changed = false;
+            if (downloadModel.Downloaded_bytes != downTask.BytesWritten)
+            {
+                downloadModel.Downloaded_bytes = downTask.BytesWritten;
+                changed = true;
+            }
+            if (downloadModel.File_bytes != downTask.totalFileSize)
+            {
+                downloadModel.File_bytes = downTask.totalFileSize;
+                changed = true;
+            }
+            if(changed)
+                taskService.UpdateDownload(downloadModel);
+        }
+
+        public void setSimpleMessageHandler(SimpleMessageHandler simpleHandler)
+        {
+            this.simpleHandler = simpleHandler;
+        }
+
+        private TaskHandler(SimpleMessageHandler simpleHandler, TaskService taskService)
+        {
+            this.simpleHandler = simpleHandler;
+            this.taskService = taskService;
+        }
+
+        public TaskHandler(SimpleMessageHandler simpleHandler, TaskService taskService, TaskDownloadManager taskDownloadManager, string defaultFileDir, IRevitCommandExcutor revitCommandExcutor) : this(simpleHandler, taskService)
+        {
+            this.taskDownloadManager = taskDownloadManager;
+            this.defaultFileDir = defaultFileDir;
+            this.revitCommandExcutor = revitCommandExcutor;
+        }
+    
+        internal void SyncAllTask()
+        {
+            IList<TaskModel> tasks = taskService.GetTasksByStatus(0); // 任务状态 0 未执行完的任务, 1 执行完成  -1 下载出错  -2 revit命令执行异常
+            taskModels = tasks;
+        }
+        internal bool addOneTask(int taskId, string msgContent) {
+            try
+            {
+                TaskModel taskModel = JsonConvert.DeserializeObject<TaskModel>(msgContent);
+                taskService.AddTask(taskModel);
+                TaskModel task = taskService.GetTasksByTaskId(taskId)[0];
+                taskModels.Add(task);
+                foreach (DownloadTaskModel download in taskModel.DownloadTaskModelList) {
+                    download.Local_dir = defaultFileDir + download.Tid + ".rvt";
+                    taskService.UpdateDownload(download);
+                }
+                return true;
+            }
+            catch(Exception ex) {
+                Console.WriteLine(ex.Message+ex.StackTrace);
+                return false;
+            }
+        }
+
+        internal bool isContainTask(int taskId)
+        {
+            try
+            {
+                return taskService.isContainsTask(taskId);
+            }
+            catch (Exception ex){
+                Console.WriteLine(ex.StackTrace);
+                return true;
+            }
+        }
+
+        public static long GetTimeStampSeconds() {
+            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
+            return (long)ts.TotalSeconds;
+        }
+    }
+}

+ 71 - 0
Dispatcher/Client/app.config

@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Google.Protobuf" publicKeyToken="a7d26565bac4d604" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-3.2.0.0" newVersion="3.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options.ConfigurationExtensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Transport" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Buffers" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Common" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Codecs" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-12.0.0.0" newVersion="12.0.0.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>

+ 69 - 0
Dispatcher/Client/packages.config

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="DotNetty.Buffers" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Common" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Transport" version="0.6.0" targetFramework="net461" />
+  <package id="Google.Protobuf" version="3.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration.Abstractions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration.Binder" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Logging" version="1.1.1" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Logging.Abstractions" version="1.1.1" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Options" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Primitives" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net461" />
+  <package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="NETStandard.Library" version="1.6.1" targetFramework="net461" />
+  <package id="Newtonsoft.Json" version="12.0.1" targetFramework="net461" />
+  <package id="System.AppContext" version="4.3.0" targetFramework="net461" />
+  <package id="System.Buffers" version="4.4.0" targetFramework="net461" />
+  <package id="System.Collections" version="4.3.0" targetFramework="net461" />
+  <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" />
+  <package id="System.ComponentModel" version="4.3.0" targetFramework="net461" />
+  <package id="System.ComponentModel.Annotations" version="4.5.0" targetFramework="net461" />
+  <package id="System.Console" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net461" />
+  <package id="System.Globalization" version="4.3.0" targetFramework="net461" />
+  <package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Linq" version="4.3.0" targetFramework="net461" />
+  <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Memory" version="4.5.1" targetFramework="net461" />
+  <package id="System.Net.Http" version="4.3.0" targetFramework="net461" />
+  <package id="System.Net.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Net.Sockets" version="4.3.0" targetFramework="net461" />
+  <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net461" />
+  <package id="System.ObjectModel" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net461" />
+  <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.Handles" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net461" />
+  <package id="System.Threading.Timer" version="4.3.0" targetFramework="net461" />
+  <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" />
+  <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" />
+</packages>

BIN
Dispatcher/Dlls/R2017/AdWindows.dll


BIN
Dispatcher/Dlls/R2017/RevitAPI.dll


BIN
Dispatcher/Dlls/R2017/RevitAPIIFC.dll


BIN
Dispatcher/Dlls/R2017/RevitAPILink.dll


BIN
Dispatcher/Dlls/R2017/RevitAPIUI.dll


BIN
Dispatcher/Dlls/R2017/RevitAPIUILink.dll


BIN
Dispatcher/Dlls/RevitRefDll/AdWindows.dll


BIN
Dispatcher/Dlls/RevitRefDll/RevitAPI.dll


BIN
Dispatcher/Dlls/RevitRefDll/RevitAPIIFC.dll


BIN
Dispatcher/Dlls/RevitRefDll/RevitAPILink.dll


BIN
Dispatcher/Dlls/RevitRefDll/RevitAPIUI.dll


BIN
Dispatcher/Dlls/RevitRefDll/RevitAPIUILink.dll


BIN
Dispatcher/Dlls/RevitRefDll/RevitAddInUtility.dll


BIN
Dispatcher/Dlls/SAGA.DotNetUtils.dll


BIN
Dispatcher/Dlls/SAGA.Models.dll


BIN
Dispatcher/Dlls/SAGA.RevitAPI.dll


BIN
Dispatcher/Dlls/SAGA.RevitUtils.dll


+ 150 - 0
Dispatcher/HttpDownload/DownloadTask.cs

@@ -0,0 +1,150 @@
+using System;
+using System.IO;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HttpDownload
+{
+    public class DownloadTask
+    {
+        public int BelongingId { get; set; }
+        public int DownloadTaskId { get; set; }
+        public string FileUrl { get; }
+        public string FileDir { get; }
+        public long Offset { get; } // 开始下载的位置
+        public string ExpectedMD5 { get; }
+
+        private volatile DownloadStatus status;
+        public DownloadStatus Status { get { return status; } }
+        private string exceptionInfo;
+        public string ExceptionInfo { get { return exceptionInfo; } } //  保存发生异常时的Message
+        private double percentage = 0d;
+        private HttpDownloader httpDownloader = null;
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="fileUrl"></param>
+        /// <param name="fileDir"></param>
+        /// <param name="expectedMD5"></param>
+        /// <param name="offset">如果 offset == -1, 则把已写入文件的字节数当作offset</param>
+        public DownloadTask(string fileUrl, string fileDir, string expectedMD5, long offset = 0L)
+        {
+            this.FileUrl = fileUrl;
+            this.FileDir = fileDir;
+            this.Offset = offset;
+            this.ExpectedMD5 = expectedMD5;
+            status = DownloadStatus.Created;
+            exceptionInfo = string.Empty;
+            httpDownloader = new HttpDownloader(fileUrl, fileDir, offset);
+
+        }
+
+        public DownloadTask(int belongingId, int downTaskId, string fileUrl, string fileDir, string expectedMD5, long offset = 0L)
+        {
+            this.BelongingId = belongingId;
+            this.DownloadTaskId = downTaskId;
+            this.FileUrl = fileUrl;
+            this.FileDir = fileDir;
+            this.Offset = offset;
+            this.ExpectedMD5 = expectedMD5;
+            status = DownloadStatus.Created;
+            exceptionInfo = string.Empty;
+            httpDownloader = new HttpDownloader(fileUrl, fileDir, offset);
+        }
+
+
+        internal static void download(DownloadTask dTask)
+        {
+            try
+            {
+                if (dTask.status.Equals(DownloadStatus.Paused))
+                    return;
+                dTask.status = DownloadStatus.Processing;
+                dTask.httpDownloader.DownloadFile();
+                if (dTask.httpDownloader.running)
+                    dTask.status = DownloadStatus.Completed;
+            }
+            catch (Exception ex)
+            {
+                dTask.status = DownloadStatus.ExceptionStopped;
+                dTask.exceptionInfo = ex.Message;
+            }
+        }
+
+        public string calculateMD5()
+        {
+            if (Status.Equals(DownloadStatus.Completed))
+            {
+                string md5Digest = "";
+                return md5Digest;
+            }
+            return null;
+        }
+
+        public void pauseTask()
+        {
+            if (status == DownloadStatus.Completed)
+                return;
+            httpDownloader.running = false;
+            status = DownloadStatus.Paused;
+        }
+        public void resumeTask()
+        {
+            if (!httpDownloader.running)
+            {
+                httpDownloader.running = true;
+                status = DownloadStatus.WaitToRun;
+            }
+        }
+        public bool isFinished()
+        {
+            return httpDownloader.Finished;
+        }
+        public string getFileName()
+        {
+            return Path.GetFileName(FileDir);
+        }
+
+        public long totalFileSize
+        {
+            get
+            {
+                if (httpDownloader != null)
+                    return httpDownloader.TotalRemoteFileSize;
+                return 0;
+            }
+        }
+        public long BytesWritten
+        {
+            get
+            {
+                if (httpDownloader != null)
+                    return httpDownloader.BytesWritten;
+                return 0;
+            }
+        }
+        public string getSpeed(bool isFormatted)
+        {
+            if (httpDownloader != null && DownloadStatus.Processing.Equals(status))
+                return httpDownloader.getSpeed(isFormatted);
+            return "0 B/s";
+        }
+        public double getPercentage(int decimals)
+        {
+            if (httpDownloader != null)
+                return httpDownloader.getPercentage(decimals);
+            return 0d;
+        }
+    }
+    public enum DownloadStatus
+    {
+        Created, // 初始状态
+        WaitToRun, // 进入队列等待被执行 
+        Paused,    // 已暂停
+        Processing,// 正在执行
+        Completed, // 完成
+        ExceptionStopped // 出现异常已暂停
+    }
+}

+ 51 - 0
Dispatcher/HttpDownload/HttpDownload.csproj

@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>HttpDownload</RootNamespace>
+    <AssemblyName>HttpDownload</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\OutputDll\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="DownloadTask.cs" />
+    <Compile Include="HttpDownloader.cs" />
+    <Compile Include="LimitedConcurrencyLevelTaskScheduler.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TaskDownloadManager.cs" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 281 - 0
Dispatcher/HttpDownload/HttpDownloader.cs

@@ -0,0 +1,281 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.IO;
+using System.Net;
+
+namespace HttpDownload
+{
+    class HttpDownloader
+    {
+        const int bytebuff = 4096;
+        const int ReadWriteTimeOut = 10 * 1000;// 在写入超时或读取超时之前的毫秒数
+        const int TimeOutWait = 10 * 1000;// 请求超时前等待的毫秒数
+        const int MaxTryTime = 10; // 最大重试次数
+        int currentRetryTimes = 0;
+        private bool finished = false;
+        public bool Finished { get { return finished; } }
+        private long totalRemoteFileSize = 0L; // 要下载的文件的总大小
+        public long TotalRemoteFileSize { get { return totalRemoteFileSize; } }
+        public long BytesWritten { get { return offset; } }
+
+        string url, destPath;
+        private long offset, timeStamp, bytesAtTimeStamp;
+        volatile private int speed;
+        FileStream fs;
+        internal volatile bool running = false;
+
+
+        public HttpDownloader(string url, string destPath, long offset = 0)
+        {
+            this.destPath = destPath;
+            this.url = url;
+            this.offset = offset;
+        }
+
+        public void DownloadFile()
+        {
+            if (isDownloadFinished(offset))
+            {
+                return;
+            }
+            try
+            {
+                for (; !finished && running;)
+                    HttpDownloadFile();
+            }
+            catch (Exception ex)
+            {
+                throw ex;
+            }
+        }
+        const string errorInfo = "下载结束, 但是文件长度与下载字节数不一致!";
+        /// <summary>
+        /// 下载文件(同步)  支持断点续传
+        /// </summary>
+        private bool HttpDownloadFile()
+        {
+            //打开上次下载的文件
+            //long lStartPos = 0;
+            fs = getFileStream();
+            HttpWebRequest request = null;
+            WebResponse respone = null;
+            Stream ns = null;
+            try
+            {
+                request = (HttpWebRequest)WebRequest.Create(url);
+                request.ReadWriteTimeout = ReadWriteTimeOut;
+                request.Timeout = TimeOutWait;
+                if (offset > 0)
+                    request.AddRange(offset);//设置Range值,断点续传
+
+                //向服务器请求,获得服务器回应数据流
+                respone = request.GetResponse();
+                ns = respone.GetResponseStream();
+                byte[] nbytes = new byte[bytebuff];
+                int nReadSize = ns.Read(nbytes, 0, bytebuff);
+                if (timeStamp == 0)
+                {
+                    timeStamp = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds);
+                    bytesAtTimeStamp = offset;
+                }
+                while (nReadSize > 0 && running)
+                {
+                    long now = Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalMilliseconds);
+                    if (now - timeStamp >= 1000)
+                    {
+                        long dataDiff = offset - bytesAtTimeStamp, timeDiff = now - timeStamp;
+                        speed = (int)(dataDiff * 1000 / timeDiff);     // 1000是由ms转为s
+                        timeStamp = now;
+                        bytesAtTimeStamp = offset;
+                    }
+                    fs.Write(nbytes, 0, nReadSize);
+                    fs.Flush();
+                    offset += nReadSize;
+                    //Thread.Sleep(20);
+                    nReadSize = ns.Read(nbytes, 0, bytebuff);
+                }
+                if (!running)
+                    return true;
+                if (offset != totalRemoteFileSize && running)//文件长度不等于下载长度,下载出错
+                {
+                    throw new Exception(errorInfo);
+                }
+                if (running)
+                    finished = true;
+            }
+            catch (Exception ex)
+            {
+                if (ex.Message.Equals(errorInfo))
+                    throw ex;
+                ++currentRetryTimes;
+                if (currentRetryTimes > MaxTryTime)
+                {
+                    throw ex;
+                }
+            }
+            finally
+            {
+                if (ns != null)
+                    ns.Close();
+                if (fs != null)
+                    fs.Close();
+                if (request != null)
+                    request.Abort();
+            }
+            return false;
+        }
+
+        private FileStream getFileStream()
+        {
+            if (fs != null)
+            {
+                fs.Close();
+            }
+            if (File.Exists(destPath))
+            {
+                fs = File.OpenWrite(destPath);
+                // offset < 0 则按照文件的大小定为offset
+                if (offset < 0)
+                {
+                    offset = fs.Length;
+                }
+                fs.Seek(offset, SeekOrigin.Current);//移动文件流中的当前指针
+            }
+            else
+            {
+                string dirName = Path.GetDirectoryName(destPath);
+
+                if (!Directory.Exists(dirName))//如果不存在保存文件夹路径,新建文件夹
+                {
+                    Directory.CreateDirectory(dirName);
+                }
+                fs = new FileStream(destPath, FileMode.Create);
+                offset = 0;
+            }
+            return fs;
+        }
+
+        /// <summary>
+        /// 获取下载文件长度
+        /// </summary>
+        /// <param name="url"></param>
+        /// <returns></returns>
+        public static long GetFileContentLength(string url)
+        {
+            HttpWebRequest request = null;
+            try
+            {
+                request = (HttpWebRequest)HttpWebRequest.Create(url);
+                request.Timeout = TimeOutWait;
+                request.ReadWriteTimeout = ReadWriteTimeOut;
+                //向服务器请求,获得服务器回应数据流
+                WebResponse respone = request.GetResponse();
+                request.Abort();
+                return respone.ContentLength;
+            }
+            catch (Exception e)
+            {
+                if (request != null)
+                    request.Abort();
+                return 0;
+            }
+        }
+        private bool isDownloadFinished(long offset)
+        {
+            if (finished)
+                return true;
+            if (totalRemoteFileSize == 0)
+                totalRemoteFileSize = GetFileContentLength(url);
+            if (totalRemoteFileSize != 0 && totalRemoteFileSize == offset)
+            {
+                //下载完成
+                finished = true;
+                return true;
+            }
+            return false;
+        }
+        /// <summary>
+        /// 获取当前速度
+        /// </summary>
+        /// <param name="formatted"></param>
+        /// <returns></returns>
+        public string getSpeed(bool formatted)
+        {
+            if (formatted)
+            {
+                if (finished)
+                    return "0 kB/s";
+                else
+                {
+                    return formatSpeed(speed, 0L, 0);
+                }
+            }
+            else
+            {
+                if (finished)
+                    return "0";
+                else
+                    return speed + "";
+            }
+        }
+        private string formatSpeed(long speed, long decimalDigit, int depth)
+        {
+            if (speed < 1024)
+            {
+                return handleDigit(speed, decimalDigit) + getUnitByDepth(depth);
+            }
+            else
+            {
+                return formatSpeed(speed / 1024, speed % 1024, depth + 1);
+            }
+        }
+        private string handleDigit(long integer, long decimalDigit)
+        {
+            if (decimalDigit == 0)
+            {
+                return integer.ToString();
+            }
+            else
+            {
+                return integer.ToString() + Math.Round((double)decimalDigit / 1024, 1).ToString().Substring(1);
+            }
+        }
+        private string getUnitByDepth(int depth)
+        {
+            string val = string.Empty;
+            switch (depth)
+            {
+                case 0:
+                    val = " B/s";
+                    break;
+                case 1:
+                    val = " kB/s";
+                    break;
+                case 2:
+                    val = " MB/s";
+                    break;
+                case 3:
+                    val = " GB/s";
+                    break;
+                default:
+                    val = " unknown/s";
+                    break;
+            }
+            return val;
+        }
+        public double getPercentage(int decimals)
+        {
+            if (totalRemoteFileSize == 0L)
+            {
+                return Math.Round(0d, decimals);
+            }
+            if (finished)
+                return Math.Round(100d, decimals);
+            double percentage = (double)offset * 100d / totalRemoteFileSize;
+            return Math.Round(percentage, decimals);
+        }
+    }
+}

+ 184 - 0
Dispatcher/HttpDownload/LimitedConcurrencyLevelTaskScheduler.cs

@@ -0,0 +1,184 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace HttpDownload
+{
+    class LimitedConcurrencyLevelTaskScheduler : TaskScheduler
+    {
+        /// <summary>Whether the current thread is processing work items.</summary>
+        [ThreadStatic]
+        private static bool _currentThreadIsProcessingItems;
+        /// <summary>The list of tasks to be executed.</summary>
+        private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)
+                                                                           /// <summary>The maximum concurrency level allowed by this scheduler.</summary>
+        private readonly int _maxDegreeOfParallelism;
+        /// <summary>Whether the scheduler is currently processing work items.</summary>
+        private int _delegatesQueuedOrRunning = 0; // protected by lock(_tasks)
+
+        /// <summary>
+        /// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the
+        /// specified degree of parallelism.
+        /// </summary>
+        /// <param name="maxDegreeOfParallelism">The maximum degree of parallelism provided by this scheduler.</param>
+        public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism)
+        {
+            if (maxDegreeOfParallelism < 1) throw new ArgumentOutOfRangeException("maxDegreeOfParallelism");
+            _maxDegreeOfParallelism = maxDegreeOfParallelism;
+        }
+
+        /// <summary>Queues a task to the scheduler.</summary>
+        /// <param name="task">The task to be queued.</param>
+        protected sealed override void QueueTask(Task task)
+        {
+            // Add the task to the list of tasks to be processed.  If there aren't enough
+            // delegates currently queued or running to process tasks, schedule another.
+            lock (_tasks)
+            {
+                _tasks.AddLast(task);
+                if (_delegatesQueuedOrRunning < _maxDegreeOfParallelism)
+                {
+                    ++_delegatesQueuedOrRunning;
+                    NotifyThreadPoolOfPendingWork();
+                }
+            }
+        }
+
+        /// <summary>
+        /// Informs the ThreadPool that there's work to be executed for this scheduler.
+        /// </summary>
+        private void NotifyThreadPoolOfPendingWork()
+        {
+            ThreadPool.UnsafeQueueUserWorkItem(_ =>
+            {
+                // Note that the current thread is now processing work items.
+                // This is necessary to enable inlining of tasks into this thread.
+                _currentThreadIsProcessingItems = true;
+                try
+                {
+                    // Process all available items in the queue.
+                    while (true)
+                    {
+                        Task item;
+                        lock (_tasks)
+                        {
+                            // When there are no more items to be processed,
+                            // note that we're done processing, and get out.
+                            if (_tasks.Count == 0)
+                            {
+                                --_delegatesQueuedOrRunning;
+                                break;
+                            }
+
+                            // Get the next item from the queue
+                            item = _tasks.First.Value;
+                            _tasks.RemoveFirst();
+                        }
+
+                        // Execute the task we pulled out of the queue
+                        base.TryExecuteTask(item);
+                    }
+                }
+                // We're done processing items on the current thread
+                finally { _currentThreadIsProcessingItems = false; }
+            }, null);
+        }
+
+        /// <summary>Attempts to execute the specified task on the current thread.</summary>
+        /// <param name="task">The task to be executed.</param>
+        /// <param name="taskWasPreviouslyQueued"></param>
+        /// <returns>Whether the task could be executed on the current thread.</returns>
+        protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
+        {
+            // If this thread isn't already processing a task, we don't support inlining
+            if (!_currentThreadIsProcessingItems) return false;
+
+            // If the task was previously queued, remove it from the queue
+            if (taskWasPreviouslyQueued) TryDequeue(task);
+
+            // Try to run the task.
+            return base.TryExecuteTask(task);
+        }
+
+        /// <summary>Attempts to remove a previously scheduled task from the scheduler.</summary>
+        /// <param name="task">The task to be removed.</param>
+        /// <returns>Whether the task could be found and removed.</returns>
+        protected sealed override bool TryDequeue(Task task)
+        {
+            lock (_tasks) return _tasks.Remove(task);
+        }
+
+        /// <summary>Gets the maximum concurrency level supported by this scheduler.</summary>
+        public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } }
+
+        /// <summary>Gets an enumerable of the tasks currently scheduled on this scheduler.</summary>
+        /// <returns>An enumerable of the tasks currently scheduled.</returns>
+        protected sealed override IEnumerable<Task> GetScheduledTasks()
+        {
+            bool lockTaken = false;
+            try
+            {
+                Monitor.TryEnter(_tasks, ref lockTaken);
+                if (lockTaken) return _tasks.ToArray();
+                else throw new NotSupportedException();
+            }
+            finally
+            {
+                if (lockTaken) Monitor.Exit(_tasks);
+            }
+        }
+    }
+    class TaskFactoryMananger
+    {
+        //USE
+        public static void Run()
+        {
+
+            try
+            {
+                while (true)
+                {
+                    LimitedConcurrencyLevelTaskScheduler lcts = new LimitedConcurrencyLevelTaskScheduler(10);
+                    TaskFactory factory = new TaskFactory(lcts);
+                    Task[] spiderTask = new Task[] {
+                        factory.StartNew(() =>
+                        {
+                            //Log.Logger.Information("{0} Start on thread {1}", "111", Thread.CurrentThread.ManagedThreadId);
+                            //Log.Logger.Information("{0} Finish  on thread {1}", "111", Thread.CurrentThread.ManagedThreadId);
+                        }),
+                        factory.StartNew(() =>
+                        {
+                            Thread.Sleep(TimeSpan.FromSeconds(3));
+                            //Log.Logger.Information("{0} Start on thread {1}", "222", Thread.CurrentThread.ManagedThreadId);
+                            //Log.Logger.Information("{0} Finish  on thread {1}", "222", Thread.CurrentThread.ManagedThreadId);
+                        }),
+                        factory.StartNew(() =>
+                        {
+                            Thread.Sleep(TimeSpan.FromSeconds(5));
+                            //Log.Logger.Information("{0} Start on thread {1}", "333", Thread.CurrentThread.ManagedThreadId);
+                            //Log.Logger.Information("{0} Finish  on thread {1}", "333", Thread.CurrentThread.ManagedThreadId);
+                        })
+                        };
+                    Task.WaitAll(spiderTask);
+                    Thread.Sleep(TimeSpan.FromMinutes(1));
+                }
+            }
+            catch (AggregateException ex)
+            {
+                foreach (Exception inner in ex.InnerExceptions)
+                {
+                    //Log.Logger.Error(inner.Message);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Provides a task scheduler that ensures a maximum concurrency level while
+        /// running on top of the ThreadPool.
+        /// </summary>
+
+    }
+}

+ 36 - 0
Dispatcher/HttpDownload/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("HttpDownload")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("HttpDownload")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("9f423033-98a9-4b6b-9bb1-f1aa8c648a02")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 128 - 0
Dispatcher/HttpDownload/TaskDownloadManager.cs

@@ -0,0 +1,128 @@
+using System;
+using System.Collections;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HttpDownload
+{
+    public class TaskDownloadManager
+    {
+        public int Capacity { get; set; }
+
+        // DownloadTask list
+        ArrayList allTasks = new ArrayList();
+
+        LimitedConcurrencyLevelTaskScheduler lcts = null;
+        TaskFactory factory = null;
+
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <param name="count">最大同时任务数[1, 30], 异常为5</param>
+        public TaskDownloadManager(int count)
+        {
+            //ThreadPool.SetMaxThreads(count, count);
+            if (count >= 1 && count <= 30)
+                Capacity = count;
+            else
+                Capacity = 5;
+            lcts = new LimitedConcurrencyLevelTaskScheduler(Capacity);
+            factory = new TaskFactory(lcts);
+        }
+        /// <summary>
+        /// 添加任务到队列
+        /// </summary>
+        /// <param name="fileUrl">文件的下载地址</param>
+        /// <param name="fileDir">文件再本地的保存路径</param>
+        /// <param name="offset">在文件中开始下载的的位置, byte</param>
+        /// <returns>任务</returns>
+        public DownloadTask enqueueTask(string fileUrl, string fileDir, string expectedMD5, long offset = 0L)
+        {
+            DownloadTask task = new DownloadTask(fileUrl, fileDir, expectedMD5, offset);
+            allTasks.Add(task);
+            return task;
+        }
+        public DownloadTask enqueueTask(int belongingId, int downTaskId, string fileUrl, string fileDir, string expectedMD5, long offset = 0L)
+        {
+            DownloadTask task = new DownloadTask(belongingId, downTaskId, fileUrl, fileDir, expectedMD5, offset);
+            allTasks.Add(task);
+            return task;
+        }
+
+        public DownloadTask getDownloadTaskByDownloadTaskId(int downloadTaskId) {
+            foreach (DownloadTask down in allTasks) {
+                if (downloadTaskId == down.DownloadTaskId) {
+                    return down;
+                }
+            }
+            return null;
+        }
+        public void runAllTasks()
+        {
+            foreach (DownloadTask task in allTasks)
+            {
+                task.resumeTask();
+                factory.StartNew(() => { DownloadTask.download(task); });
+            }
+        }
+
+        public void pauseAllTasks()
+        {
+            foreach (DownloadTask task in allTasks)
+            {
+                task.pauseTask();
+            }
+        }
+        public void resumeAllTasks()
+        {
+            foreach (DownloadTask task in allTasks)
+            {
+                task.resumeTask();
+                factory.StartNew(() => { DownloadTask.download(task); });
+            }
+        }
+
+        public ArrayList getAllTasks() { return allTasks; }
+
+        public Hashtable getAllTasksMap() {
+            Hashtable table = new Hashtable();
+            foreach (DownloadTask down in allTasks) {
+                int belongingid = down.BelongingId;
+                if (table.ContainsKey(belongingid))
+                {
+                    ArrayList arr = (ArrayList)table[belongingid];
+                    arr.Add(down);
+                }
+                else {
+                    ArrayList arr = new ArrayList();
+                    arr.Add(down);
+                    table.Add(belongingid, arr);
+                }
+            }
+            return table;
+        }
+
+        public void runTask(DownloadTask task)
+        {
+            task.resumeTask();
+            factory.StartNew(() => { DownloadTask.download(task); });
+        }
+
+        public void pauseTask(DownloadTask task)
+        {
+            task.pauseTask();
+        }
+        public void resumeTask(DownloadTask task)
+        {
+            task.resumeTask();
+            factory.StartNew(() => { DownloadTask.download(task); });
+        }
+        public void removeTask(DownloadTask task)
+        {
+            task.pauseTask();
+            allTasks.Remove(task);
+        }
+    }
+}

+ 13 - 0
Dispatcher/NettyClient/ClientWrapper.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NettyClient
+{
+    class ClientWrapper
+    {
+        
+    }
+}

+ 132 - 0
Dispatcher/NettyClient/NettyClient.csproj

@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{7A08D4E8-A171-47BD-A527-BC9BA1833305}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>NettyClient</RootNamespace>
+    <AssemblyName>NettyClient</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\OutputDll\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject />
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="DotNetty.Buffers, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Buffers.0.6.0\lib\net45\DotNetty.Buffers.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Codecs, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Codecs.0.6.0\lib\net45\DotNetty.Codecs.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Codecs.Protobuf, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Codecs.Protobuf.0.6.0\lib\net45\DotNetty.Codecs.Protobuf.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Common, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Common.0.6.0\lib\net45\DotNetty.Common.dll</HintPath>
+    </Reference>
+    <Reference Include="DotNetty.Transport, Version=0.6.0.0, Culture=neutral, PublicKeyToken=bc13ca065fa06c29, processorArchitecture=MSIL">
+      <HintPath>..\packages\DotNetty.Transport.0.6.0\lib\net45\DotNetty.Transport.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Protobuf, Version=3.2.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+      <HintPath>..\packages\Google.Protobuf.3.2.0\lib\net45\Google.Protobuf.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Configuration.Binder, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Logging.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=1.1.1.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.1.1.1\lib\netstandard1.1\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Options, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Options.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Options.ConfigurationExtensions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Options.ConfigurationExtensions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.ConfigurationExtensions.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Extensions.Primitives, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
+      <HintPath>..\packages\Microsoft.Extensions.Primitives.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Buffers, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Buffers.4.4.0\lib\netstandard2.0\System.Buffers.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Collections.Immutable, Version=1.2.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.ComponentModel.Annotations.4.5.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
+    </Reference>
+    <Reference Include="System.ComponentModel.Composition" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.3.0\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
+    </Reference>
+    <Reference Include="System.IO.Compression.FileSystem" />
+    <Reference Include="System.Memory, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Memory.4.5.1\lib\netstandard2.0\System.Memory.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Numerics" />
+    <Reference Include="System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Numerics.Vectors.4.4.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.2\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.1\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="ClientWrapper.cs" />
+    <Compile Include="proto\MessageProto.cs" />
+    <Compile Include="proto\MessageUtil.cs" />
+    <Compile Include="TaskNettyClient.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="SimpleMessageHandler.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="app.config" />
+    <None Include="packages.config" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 6 - 0
Dispatcher/NettyClient/NettyClient.csproj.user

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <ProjectView>ShowAllFiles</ProjectView>
+  </PropertyGroup>
+</Project>

+ 36 - 0
Dispatcher/NettyClient/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("NettyClient")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("NettyClient")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("7a08d4e8-a171-47bd-a527-bc9ba1833305")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 82 - 0
Dispatcher/NettyClient/SimpleMessageHandler.cs

@@ -0,0 +1,82 @@
+using DotNetty.Transport.Channels;
+using System;
+using System.Collections.Concurrent;
+using System.Windows.Forms;
+using Message = NettyClient.proto.Message;
+
+namespace NettyClient
+{
+    public class SimpleMessageHandler : ChannelHandlerAdapter
+    {
+        public SimpleMessageHandler()
+        {
+
+            //var protobufEncoder = new ProtobufEncoder();
+        }
+        public static ConcurrentQueue<Message> messageQueue = new ConcurrentQueue<Message>();
+        public IChannelHandlerContext context;
+        public override void ChannelActive(IChannelHandlerContext context)
+        {
+            MessageBox.Show("connected");
+            this.context = context;
+        }
+        public override void ChannelRead(IChannelHandlerContext context, object message)
+        {
+            if (message is Message msg)
+            {
+                toString(msg);
+                messageQueue.Enqueue(msg);
+            }
+        }
+
+        public override void ChannelReadComplete(IChannelHandlerContext context)
+        {
+            context.Flush();
+        }
+
+        public override void ExceptionCaught(IChannelHandlerContext context, Exception exception)
+        {
+            Console.WriteLine("Exception: " + exception);
+            context.CloseAsync();
+        }
+        public override void ChannelInactive(IChannelHandlerContext context)
+        {
+            base.ChannelInactive(context);
+            Console.WriteLine("1");
+        }
+
+        public override void ChannelUnregistered(IChannelHandlerContext context)
+        {
+            base.ChannelUnregistered(context);
+            Console.WriteLine("2");
+        }
+
+        public override void HandlerRemoved(IChannelHandlerContext context)
+        {
+            base.HandlerRemoved(context);
+        }
+
+
+
+        public void toString(Message msg)
+        {
+            Console.WriteLine("Received from server: cmd : " + msg.Cmd + ", taskId : " + msg.TaskId + ", content : " + msg.Content);
+        }
+        public bool WriteMessage(Message message)
+        {
+            if (context == null || !context.Channel.Active)
+            {
+                return false;
+            }
+            try
+            {
+                context.WriteAndFlushAsync(message);
+            }
+            catch
+            {
+                return false;
+            }
+            return true;
+        }
+    }
+}

+ 109 - 0
Dispatcher/NettyClient/TaskNettyClient.cs

@@ -0,0 +1,109 @@
+using DotNetty.Transport.Bootstrapping;
+using DotNetty.Transport.Channels;
+using DotNetty.Transport.Channels.Sockets;
+using System;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows.Forms;
+using DotNetty.Codecs.Protobuf;
+using Message = NettyClient.proto.Message;
+
+namespace NettyClient
+{
+    public class TaskNettyClient
+    {
+        private string ip;
+        private int port;
+        IChannel clientChannel;
+        MultithreadEventLoopGroup group;
+        Bootstrap bootstrap;
+        public TaskNettyClient(string ip, int port)
+        {
+            this.ip = ip;
+            this.port = port;
+        }
+        public async Task RunClientAsync(ChannelHandlerAdapter channelHandler)
+        {
+            group = new MultithreadEventLoopGroup();
+            try
+            {
+                bootstrap = new Bootstrap();
+                bootstrap
+                    .Group(group)
+                    .Channel<TcpSocketChannel>()
+                    .Option(ChannelOption.TcpNodelay, true)
+                    .Handler(
+                        new ActionChannelInitializer<ISocketChannel>(
+                            channel =>
+                            {
+                                //var protobufEncoder = new ProtobufEncoder();
+                                IChannelPipeline pipeline = channel.Pipeline;
+                                pipeline.AddLast(new ProtobufVarint32LengthFieldPrepender());
+                                pipeline.AddLast(new ProtobufVarint32FrameDecoder());
+                                pipeline.AddLast("encoder", new ProtobufEncoder());
+                                pipeline.AddLast("decoder", new ProtobufDecoder(Message.Parser));
+                                pipeline.AddLast("simple", channelHandler);
+
+                            }));
+                clientChannel = await bootstrap.ConnectAsync(new IPEndPoint(IPAddress.Parse(ip), port));
+                //await clientChannel.CloseAsync();
+            }
+            catch (Exception ex)
+            {
+                MessageBox.Show(ex.Message + "\r\n" + ex.StackTrace + $"ip:{ip};port{port}");
+            }
+            finally
+            {
+                //await Task.WhenAll(group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)));
+            }
+        }
+        public async Task CloseAsync()
+        {
+            try
+            {
+                await clientChannel.CloseAsync();
+            }
+            catch { }
+            finally
+            {
+                await Task.WhenAll(group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)));
+            }
+        }
+
+        public static void Main(string[] args)
+        {
+            TaskNettyClient client = new TaskNettyClient("127.0.0.1", 6666);
+            SimpleMessageHandler simpleHandler = new SimpleMessageHandler();
+            client.RunClientAsync(simpleHandler).Wait();
+            while (true)
+            {
+                Thread.Sleep(15000);
+                client.CloseAsync().Wait();
+                // 重启
+                //client.RunClientAsync(new SimpleHandler()).Wait();
+            }
+        }
+    }
+
+    public static class NettyHelper
+    {
+        //static NettyHelper()
+        //{
+        //    Configuration = new ConfigurationBuilder()
+        //    //    .SetBasePath(ProcessDirectory)
+        //    //    .AddJsonFile("appsettings.json")
+        //        .Build();
+        //}
+
+        //public static IConfigurationRoot Configuration { get; }
+
+        //public static void SetConsoleLogger() => InternalLoggerFactory.DefaultFactory.AddProvider(new ConsoleLoggerProvider((s, level) => true, false));
+        //public static void SetConsoleLogger()
+        //{
+        //    InternalLoggerFactory.DefaultFactory.AddProvider(
+        //        new ConsoleLoggerProvider((s, level) => { level = Microsoft.Extensions.Logging.LogLevel.Error; return true; }, false)
+        //    );
+        //}
+    }
+}

+ 75 - 0
Dispatcher/NettyClient/app.config

@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<configuration>
+  <runtime>
+    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
+      <dependentAssembly>
+        <assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.1.0" newVersion="4.0.1.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Logging" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.1.0.0" newVersion="2.1.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Google.Protobuf" publicKeyToken="a7d26565bac4d604" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-3.4.0.0" newVersion="3.4.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.DependencyInjection.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration.Abstractions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Configuration" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Options.ConfigurationExtensions" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="Microsoft.Extensions.Primitives" publicKeyToken="adb9793829ddae60" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-2.2.0.0" newVersion="2.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Common" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Threading.Tasks.Extensions" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-4.2.0.0" newVersion="4.2.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="System.Collections.Immutable" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-1.2.3.0" newVersion="1.2.3.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Codecs" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Buffers" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+      <dependentAssembly>
+        <assemblyIdentity name="DotNetty.Transport" publicKeyToken="bc13ca065fa06c29" culture="neutral" />
+        <bindingRedirect oldVersion="0.0.0.0-0.6.0.0" newVersion="0.6.0.0" />
+      </dependentAssembly>
+    </assemblyBinding>
+  </runtime>
+</configuration>

+ 72 - 0
Dispatcher/NettyClient/packages.config

@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="DotNetty.Buffers" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Codecs" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Codecs.Protobuf" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Common" version="0.6.0" targetFramework="net461" />
+  <package id="DotNetty.Transport" version="0.6.0" targetFramework="net461" />
+  <package id="Google.Protobuf" version="3.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration.Abstractions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Configuration.Binder" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Logging" version="1.1.1" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Logging.Abstractions" version="1.1.1" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Options" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Options.ConfigurationExtensions" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.Extensions.Primitives" version="2.2.0" targetFramework="net461" />
+  <package id="Microsoft.NETCore.Platforms" version="1.1.0" targetFramework="net461" />
+  <package id="Microsoft.Win32.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="NETStandard.Library" version="1.6.1" targetFramework="net461" />
+  <package id="System.AppContext" version="4.3.0" targetFramework="net461" />
+  <package id="System.Buffers" version="4.4.0" targetFramework="net461" />
+  <package id="System.Collections" version="4.3.0" targetFramework="net461" />
+  <package id="System.Collections.Concurrent" version="4.3.0" targetFramework="net461" />
+  <package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
+  <package id="System.ComponentModel" version="4.3.0" targetFramework="net461" />
+  <package id="System.ComponentModel.Annotations" version="4.5.0" targetFramework="net461" />
+  <package id="System.Console" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Debug" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.DiagnosticSource" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Tools" version="4.3.0" targetFramework="net461" />
+  <package id="System.Diagnostics.Tracing" version="4.3.0" targetFramework="net461" />
+  <package id="System.Globalization" version="4.3.0" targetFramework="net461" />
+  <package id="System.Globalization.Calendars" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.Compression" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.Compression.ZipFile" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.FileSystem" version="4.3.0" targetFramework="net461" />
+  <package id="System.IO.FileSystem.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Linq" version="4.3.0" targetFramework="net461" />
+  <package id="System.Linq.Expressions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Memory" version="4.5.1" targetFramework="net461" />
+  <package id="System.Net.Http" version="4.3.0" targetFramework="net461" />
+  <package id="System.Net.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Net.Sockets" version="4.3.0" targetFramework="net461" />
+  <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net461" />
+  <package id="System.ObjectModel" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Reflection.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Resources.ResourceManager" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.2" targetFramework="net461" />
+  <package id="System.Runtime.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.Handles" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.InteropServices" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.InteropServices.RuntimeInformation" version="4.3.0" targetFramework="net461" />
+  <package id="System.Runtime.Numerics" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
+  <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.Encoding" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.Encoding.Extensions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Text.RegularExpressions" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading.Tasks" version="4.3.0" targetFramework="net461" />
+  <package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net461" />
+  <package id="System.Threading.Timer" version="4.3.0" targetFramework="net461" />
+  <package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net461" />
+  <package id="System.Xml.XDocument" version="4.3.0" targetFramework="net461" />
+</packages>

+ 224 - 0
Dispatcher/NettyClient/proto/MessageProto - 复制.cs

@@ -0,0 +1,224 @@
+// <auto-generated>
+//     Generated by the protocol buffer compiler.  DO NOT EDIT!
+//     source: MessageProto.proto
+// </auto-generated>
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+using pb = Google.Protobuf;
+using pbr = Google.Protobuf.Reflection;
+namespace Cn.Sagacloud.Proto
+{
+
+    /// <summary>Holder for reflection information generated from MessageProto.proto</summary>
+    public static partial class MessageProtoReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for MessageProto.proto</summary>
+    public static pbr.FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr.FileDescriptor descriptor;
+
+    static MessageProtoReflection() {
+      byte[] descriptorData = System.Convert.FromBase64String(
+          string.Concat(
+            "ChJNZXNzYWdlUHJvdG8ucHJvdG8SEmNuLnNhZ2FjbG91ZC5wcm90byI3CgdN",
+            "ZXNzYWdlEgsKA2NtZBgBIAEoCRIOCgZ0YXNrSWQYAiABKAUSDwoHY29udGVu",
+            "dBgDIAEoCUIQQgxNZXNzYWdlUHJvdG9IAWIGcHJvdG8z"));
+      descriptor = pbr.FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr.FileDescriptor[] { },
+          new pbr.GeneratedClrTypeInfo(null, new pbr.GeneratedClrTypeInfo[] {
+            new pbr.GeneratedClrTypeInfo(typeof(Cn.Sagacloud.Proto.Message), Cn.Sagacloud.Proto.Message.Parser, new[]{ "Cmd", "TaskId", "Content" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  public sealed partial class Message : pb.IMessage<Message> {
+    private static readonly pb.MessageParser<Message> _parser = new pb.MessageParser<Message>(() => new Message());
+     private pb.UnknownFieldSet _unknownFields;
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb.MessageParser<Message> Parser { get { return _parser; } }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr.MessageDescriptor Descriptor {
+      get { return Cn.Sagacloud.Proto.MessageProtoReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr.MessageDescriptor pb.IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message(Message other) : this() {
+      cmd_ = other.cmd_;
+      taskId_ = other.taskId_;
+      content_ = other.content_;
+         _unknownFields = pb.UnknownFieldSet.Clone(other._unknownFields);
+        }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message Clone() {
+      return new Message(this);
+    }
+
+    /// <summary>Field number for the "cmd" field.</summary>
+    public const int CmdFieldNumber = 1;
+    private string cmd_ = "";
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string Cmd {
+      get { return cmd_; }
+      set {
+        cmd_ = pb.ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "taskId" field.</summary>
+    public const int TaskIdFieldNumber = 2;
+    private int taskId_;
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int TaskId {
+      get { return taskId_; }
+      set {
+        taskId_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "content" field.</summary>
+    public const int ContentFieldNumber = 3;
+    private string content_ = "";
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string Content {
+      get { return content_; }
+      set {
+        content_ = pb.ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as Message);
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(Message other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Cmd != other.Cmd) return false;
+      if (TaskId != other.TaskId) return false;
+      if (Content != other.Content) return false;
+        return Equals(_unknownFields, other._unknownFields);
+            return true;
+    }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Cmd.Length != 0) hash ^= Cmd.GetHashCode();
+      if (TaskId != 0) hash ^= TaskId.GetHashCode();
+      if (Content.Length != 0) hash ^= Content.GetHashCode();
+            if (_unknownFields != null) {hash ^= _unknownFields.GetHashCode();}
+            return hash;
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override string ToString() {
+      return pb.JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void WriteTo(pb.CodedOutputStream output) {
+      if (Cmd.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Cmd);
+      }
+      if (TaskId != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(TaskId);
+      }
+      if (Content.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(Content);
+      }
+
+            if (_unknownFields != null){_unknownFields.WriteTo(output);}
+        }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (Cmd.Length != 0) {
+        size += 1 + pb.CodedOutputStream.ComputeStringSize(Cmd);
+      }
+      if (TaskId != 0) {
+        size += 1 + pb.CodedOutputStream.ComputeInt32Size(TaskId);
+      }
+      if (Content.Length != 0) {
+        size += 1 + pb.CodedOutputStream.ComputeStringSize(Content);
+      }
+
+             if (_unknownFields != null){size += _unknownFields.CalculateSize();}
+            return size;
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(Message other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Cmd.Length != 0) {
+        Cmd = other.Cmd;
+      }
+      if (other.TaskId != 0) {
+        TaskId = other.TaskId;
+      }
+      if (other.Content.Length != 0) {
+        Content = other.Content;
+      }
+        _unknownFields = pb.UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+        }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(pb.CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+_unknownFields = Google.Protobuf.UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+                        break;
+          case 10: {
+            Cmd = input.ReadString();
+            break;
+          }
+          case 16: {
+            TaskId = input.ReadInt32();
+            break;
+          }
+          case 26: {
+            Content = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code

+ 225 - 0
Dispatcher/NettyClient/proto/MessageProto.cs

@@ -0,0 +1,225 @@
+// <auto-generated>
+//     Generated by the protocol buffer compiler.  DO NOT EDIT!
+//     source: MessageProto.proto
+// </auto-generated>
+#pragma warning disable 1591, 0612, 3021
+#region Designer generated code
+
+using pb = Google.Protobuf;
+using pbr = Google.Protobuf.Reflection;
+namespace NettyClient.proto
+{
+
+    /// <summary>Holder for reflection information generated from MessageProto.proto</summary>
+    public static partial class MessageProtoReflection {
+
+    #region Descriptor
+    /// <summary>File descriptor for MessageProto.proto</summary>
+    public static pbr.FileDescriptor Descriptor {
+      get { return descriptor; }
+    }
+    private static pbr.FileDescriptor descriptor;
+
+    static MessageProtoReflection() {
+      byte[] descriptorData = System.Convert.FromBase64String(
+          string.Concat(
+            "ChJNZXNzYWdlUHJvdG8ucHJvdG8SEmNuLnNhZ2FjbG91ZC5wcm90byI3CgdN",
+            "ZXNzYWdlEgsKA2NtZBgBIAEoCRIOCgZ0YXNrSWQYAiABKAUSDwoHY29udGVu",
+            "dBgDIAEoCUIQQgxNZXNzYWdlUHJvdG9IAWIGcHJvdG8z"));
+      descriptor = pbr.FileDescriptor.FromGeneratedCode(descriptorData,
+          new pbr.FileDescriptor[] { },
+          new pbr.GeneratedClrTypeInfo(null, new pbr.GeneratedClrTypeInfo[] {
+            new pbr.GeneratedClrTypeInfo(typeof(Message), Message.Parser, new[]{ "Cmd", "TaskId", "Content" }, null, null, null)
+          }));
+    }
+    #endregion
+
+  }
+  #region Messages
+  public sealed partial class Message : pb.IMessage<Message> {
+    private static readonly pb.MessageParser<Message> _parser = new pb.MessageParser<Message>(() => new Message());
+     //04 private pb.UnknownFieldSet _unknownFields;
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb.MessageParser<Message> Parser { get { return _parser; } }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr.MessageDescriptor Descriptor {
+      get { return MessageProtoReflection.Descriptor.MessageTypes[0]; }
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr.MessageDescriptor pb.IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message(Message other) : this() {
+      cmd_ = other.cmd_;
+      taskId_ = other.taskId_;
+      content_ = other.content_;
+        //04  _unknownFields = pb.UnknownFieldSet.Clone(other._unknownFields);
+        }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public Message Clone() {
+      return new Message(this);
+    }
+
+    /// <summary>Field number for the "cmd" field.</summary>
+    public const int CmdFieldNumber = 1;
+    private string cmd_ = "";
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string Cmd {
+      get { return cmd_; }
+      set {
+        cmd_ = pb.ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    /// <summary>Field number for the "taskId" field.</summary>
+    public const int TaskIdFieldNumber = 2;
+    private int taskId_;
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int TaskId {
+      get { return taskId_; }
+      set {
+        taskId_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "content" field.</summary>
+    public const int ContentFieldNumber = 3;
+    private string content_ = "";
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public string Content {
+      get { return content_; }
+      set {
+        content_ = pb.ProtoPreconditions.CheckNotNull(value, "value");
+      }
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as Message);
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(Message other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (Cmd != other.Cmd) return false;
+      if (TaskId != other.TaskId) return false;
+      if (Content != other.Content) return false;
+        //04  return Equals(_unknownFields, other._unknownFields);
+            return true;
+    }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (Cmd.Length != 0) hash ^= Cmd.GetHashCode();
+      if (TaskId != 0) hash ^= TaskId.GetHashCode();
+      if (Content.Length != 0) hash ^= Content.GetHashCode();
+            //04   if (_unknownFields != null) {hash ^= _unknownFields.GetHashCode();}
+            return hash;
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override string ToString() {
+      return pb.JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void WriteTo(pb.CodedOutputStream output) {
+      if (Cmd.Length != 0) {
+        output.WriteRawTag(10);
+        output.WriteString(Cmd);
+      }
+      if (TaskId != 0) {
+        output.WriteRawTag(16);
+        output.WriteInt32(TaskId);
+      }
+      if (Content.Length != 0) {
+        output.WriteRawTag(26);
+        output.WriteString(Content);
+      }
+
+        //04    if (_unknownFields != null){_unknownFields.WriteTo(output);}
+        }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (Cmd.Length != 0) {
+        size += 1 + pb.CodedOutputStream.ComputeStringSize(Cmd);
+      }
+      if (TaskId != 0) {
+        size += 1 + pb.CodedOutputStream.ComputeInt32Size(TaskId);
+      }
+      if (Content.Length != 0) {
+        size += 1 + pb.CodedOutputStream.ComputeStringSize(Content);
+      }
+
+            //04    if (_unknownFields != null){size += _unknownFields.CalculateSize();}
+            return size;
+    }
+
+    [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(Message other) {
+      if (other == null) {
+        return;
+      }
+      if (other.Cmd.Length != 0) {
+        Cmd = other.Cmd;
+      }
+      if (other.TaskId != 0) {
+        TaskId = other.TaskId;
+      }
+      if (other.Content.Length != 0) {
+        Content = other.Content;
+      }
+        //04  _unknownFields = pb.UnknownFieldSet.MergeFrom(_unknownFields, other._unknownFields);
+        }
+
+        [System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(pb.CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+              //04 _unknownFields = Google.Protobuf.UnknownFieldSet.MergeFieldFrom(_unknownFields, input);
+                        break;
+          case 10: {
+            Cmd = input.ReadString();
+            break;
+          }
+          case 16: {
+            TaskId = input.ReadInt32();
+            break;
+          }
+          case 26: {
+            Content = input.ReadString();
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  #endregion
+
+}
+
+#endregion Designer generated code

+ 19 - 0
Dispatcher/NettyClient/proto/MessageUtil.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NettyClient.proto
+{
+    public class MessageUtil
+    {
+        public static Message generateMessage(string cmd, int taskId, string content) {
+            Message msg = new Message();
+            msg.Cmd = cmd;
+            msg.TaskId = taskId;
+            msg.Content = content;
+            return msg;
+        }
+    }
+}

+ 79 - 0
Dispatcher/ServiceMBI.sln

@@ -0,0 +1,79 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.26730.3
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Client", "Client\Client.csproj", "{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HttpDownload", "HttpDownload\HttpDownload.csproj", "{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NettyClient", "NettyClient\NettyClient.csproj", "{7A08D4E8-A171-47BD-A527-BC9BA1833305}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskDatabase", "TaskDatabase\TaskDatabase.csproj", "{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|x64.Build.0 = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Debug|x86.Build.0 = Debug|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|Any CPU.Build.0 = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|x64.ActiveCfg = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|x64.Build.0 = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|x86.ActiveCfg = Release|Any CPU
+		{6A52AF44-63C6-4AB6-92D4-2A05173D45FB}.Release|x86.Build.0 = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|x64.Build.0 = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Debug|x86.Build.0 = Debug|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|Any CPU.Build.0 = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|x64.ActiveCfg = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|x64.Build.0 = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|x86.ActiveCfg = Release|Any CPU
+		{9F423033-98A9-4B6B-9BB1-F1AA8C648A02}.Release|x86.Build.0 = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|x64.Build.0 = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Debug|x86.Build.0 = Debug|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|Any CPU.Build.0 = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|x64.ActiveCfg = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|x64.Build.0 = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|x86.ActiveCfg = Release|Any CPU
+		{7A08D4E8-A171-47BD-A527-BC9BA1833305}.Release|x86.Build.0 = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|x64.Build.0 = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Debug|x86.Build.0 = Debug|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|Any CPU.Build.0 = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|x64.ActiveCfg = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|x64.Build.0 = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|x86.ActiveCfg = Release|Any CPU
+		{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {EF8DCEE9-4A1C-4EFD-A378-13ABCBBBA018}
+	EndGlobalSection
+EndGlobal

+ 44 - 0
Dispatcher/TaskDatabase/Mappings/TaskModel.hbm.xml

@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
+                   assembly="TaskDatabase" default-lazy="false"
+                   namespace="TaskDatabase.Model">
+
+  <!-- more mapping info here -->
+  <class name="TaskModel" table="task" entity-name="TaskModel">
+    <id name="Tid">
+      <!--<generator class="guid" />-->
+      <generator class="native" />
+      <!--  <generator class="native" />主键自增。使用数据库自带的生成器 -->
+    </id>
+    <property name="Id" />
+    <property name="Task_name"/>
+    <property name="Task_cmd" update="false" />
+    <property name="Task_param" update="false"/>
+    <property name="Task_status"/>
+    <property name="Task_result_json" />
+    <property name="Task_expected_finish_time"  update="false"/>
+    <property name="Task_add_time" insert="false" update="false"/>
+    <set name="DownloadTaskModelList">
+      <key column="Task_id" property-ref="Id"/>
+      <one-to-many class="DownloadTaskModel"/>
+    </set>
+  </class>
+
+  <class name="DownloadTaskModel" table="download">
+    <id name="Tid">
+      <!--<generator class="guid" />-->
+      <generator class="native" />
+      <!--  <generator class="native" />主键自增。使用数据库自带的生成器 -->
+    </id>
+    <property name="Id" />
+    <property name="Task_id" >
+      <!--<many-to-one class="DownloadTaskModel" column="Task_Id"/>-->
+    </property>
+    <property name="Task_url" />
+    <property name="Task_md5" />
+    <property name="Local_dir" />
+    <property name="Downloaded_bytes" />
+    <property name="File_bytes" />
+    <property name="Finish_time" />
+  </class>
+</hibernate-mapping>

+ 15 - 0
Dispatcher/TaskDatabase/Model/DownloadTaskModel.cs

@@ -0,0 +1,15 @@
+namespace TaskDatabase.Model
+{
+    public class DownloadTaskModel
+    {
+        public virtual int Tid { get; set; }
+        public virtual int Id { get; set; }
+        public virtual string Task_id { get; set; }
+        public virtual string Task_url { get; set; }
+        public virtual string Task_md5 { get; set; }
+        public virtual string Local_dir { get; set; }
+        public virtual long Downloaded_bytes { get; set; }
+        public virtual long File_bytes { get; set; }
+        public virtual long Finish_time { get; set; }
+    }
+}

+ 28 - 0
Dispatcher/TaskDatabase/Model/TaskModel.cs

@@ -0,0 +1,28 @@
+/* ==============================================================================
+ * 功能描述:TaskModel  
+ * 创 建 者:Garrett
+ * 创建日期:2019/4/22 15:52:12
+ * ==============================================================================*/
+
+using System;
+using System.Collections.Generic;
+
+namespace TaskDatabase.Model
+{
+    /// <summary>
+    /// TaskModel
+    /// </summary>
+    public class TaskModel
+    {
+        public virtual int Tid { get; set; }
+        public virtual int Id { get; set; }
+        public virtual string Task_name { get; set; }
+        public virtual string Task_cmd { get; set; }
+        public virtual string Task_param { get; set; }
+        public virtual int Task_status { get; set; }
+        public virtual string Task_result_json { get; set; }
+        public virtual long Task_expected_finish_time { get; set; }
+        public virtual DateTime Task_add_time { get; set; }
+        public virtual ICollection<DownloadTaskModel> DownloadTaskModelList { get; set; }
+    }
+}

+ 42 - 0
Dispatcher/TaskDatabase/NHibernateHelper.cs

@@ -0,0 +1,42 @@
+using NHibernate;
+using NHibernate.Cfg;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TaskDatabase
+{
+    public class NHibernateHelper
+    {
+        private static object lockObj = new object();
+        private static ISessionFactory _sessionFactory;
+
+        private static ISessionFactory SessionFactory
+        {
+            get
+            {
+                if (_sessionFactory == null)
+                {
+                    lock (lockObj)
+                    {
+                        if (_sessionFactory == null)
+                        {
+                            var configuration = new Configuration();
+                            configuration.Configure();
+                            //configuration.AddAssembly(typeof(TaskModel).Assembly);
+                            _sessionFactory = configuration.BuildSessionFactory();
+                        }
+                    }
+                }
+                return _sessionFactory;
+            }
+        }
+
+        public static ISession OpenSession()
+        {
+            return SessionFactory.OpenSession();
+        }
+    }
+}

+ 36 - 0
Dispatcher/TaskDatabase/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("TaskDatabase")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("TaskDatabase")]
+[assembly: AssemblyCopyright("Copyright ©  2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("ade36aa5-fca8-4e5b-a27e-2360884404b3")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+//通过使用 "*",如下所示:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 94 - 0
Dispatcher/TaskDatabase/TaskDatabase.csproj

@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{ADE36AA5-FCA8-4E5B-A27E-2360884404B3}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>TaskDatabase</RootNamespace>
+    <AssemblyName>TaskDatabase</AssemblyName>
+    <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\OutputDll\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Antlr3.Runtime, Version=3.5.0.2, Culture=neutral, PublicKeyToken=eb42632606e9261f, processorArchitecture=MSIL">
+      <HintPath>..\packages\Antlr3.Runtime.3.5.1\lib\net40-client\Antlr3.Runtime.dll</HintPath>
+    </Reference>
+    <Reference Include="Google.Protobuf, Version=3.5.0.0, Culture=neutral, PublicKeyToken=a7d26565bac4d604, processorArchitecture=MSIL">
+      <HintPath>..\packages\Google.Protobuf.3.5.0\lib\net45\Google.Protobuf.dll</HintPath>
+    </Reference>
+    <Reference Include="Iesi.Collections, Version=4.0.0.4000, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
+      <HintPath>..\packages\Iesi.Collections.4.0.4\lib\net461\Iesi.Collections.dll</HintPath>
+    </Reference>
+    <Reference Include="MySql.Data, Version=6.10.8.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
+      <HintPath>..\packages\MySql.Data.6.10.8\lib\net452\MySql.Data.dll</HintPath>
+    </Reference>
+    <Reference Include="NHibernate, Version=5.2.0.0, Culture=neutral, PublicKeyToken=aa95f207798dfdb4, processorArchitecture=MSIL">
+      <HintPath>..\packages\NHibernate.5.2.0\lib\net461\NHibernate.dll</HintPath>
+    </Reference>
+    <Reference Include="Remotion.Linq, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
+      <HintPath>..\packages\Remotion.Linq.2.2.0\lib\net45\Remotion.Linq.dll</HintPath>
+    </Reference>
+    <Reference Include="Remotion.Linq.EagerFetching, Version=2.2.0.0, Culture=neutral, PublicKeyToken=fee00910d6e5f53b, processorArchitecture=MSIL">
+      <HintPath>..\packages\Remotion.Linq.EagerFetching.2.2.0\lib\net45\Remotion.Linq.EagerFetching.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.ComponentModel" />
+    <Reference Include="System.ComponentModel.DataAnnotations" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Configuration.Install" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Drawing.Design" />
+    <Reference Include="System.Management" />
+    <Reference Include="System.ServiceModel" />
+    <Reference Include="System.Transactions" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Model\TaskModel.cs" />
+    <Compile Include="NHibernateHelper.cs" />
+    <Compile Include="Model\DownloadTaskModel.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="TaskService.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <EmbeddedResource Include="Mappings\TaskModel.hbm.xml">
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="hibernate.cfg.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 213 - 0
Dispatcher/TaskDatabase/TaskService.cs

@@ -0,0 +1,213 @@
+using NHibernate;
+using NHibernate.Criterion;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using TaskDatabase.Model;
+
+namespace TaskDatabase
+{
+    public class TaskService
+    {
+        public bool AddTask(TaskModel task) {
+            ITransaction transaction = null;
+            try
+            {
+                //如果存在该任务, 则不允许添加
+                if (isContainsTask(task.Id))
+                {
+                    return false;
+                }
+                using (ISession session = NHibernateHelper.OpenSession()) {
+                    using (transaction = session.BeginTransaction()) {
+                        try
+                        {
+                            session.Save(task);
+                            if(task.DownloadTaskModelList != null)
+                            {
+                                foreach(var download in task.DownloadTaskModelList)
+                                {
+                                    session.Save(download);
+                                }
+                            }
+                            transaction.Commit();
+                        }
+                        catch {
+                            if (transaction != null && transaction.IsActive)
+                            {
+                                transaction.Rollback();
+                            }
+                        }
+                    }
+                }
+                return true;
+            }
+            catch {}
+            return false;
+        }
+
+        public bool UpdateTask(TaskModel task)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        session.Update(task);
+                        transaction.Commit();
+                    }
+                }
+
+                return true;
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message+ex.StackTrace);
+            }
+            return false;
+        }
+        public bool UpdateDownload(DownloadTaskModel download)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        session.Update(download);
+                        transaction.Commit();
+                    }
+                }
+                return true;
+            }
+            catch { }
+            return false;
+        }
+        public IList<TaskModel> GetTasksByStatus(int status)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Eq("Task_status", status))
+                                .List<TaskModel>();
+                        return queryResult;
+                    }
+                }
+            }
+            catch (Exception ex){
+                
+                Console.WriteLine(ex.Message);
+            }
+            return null;
+        }
+
+        public TaskModel GetTasksByTid(int tid)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Eq("Tid", tid))
+                                .UniqueResult<TaskModel>();
+                        return queryResult;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+
+                Console.WriteLine(ex.Message);
+            }
+            return null;
+        }
+
+        public IList<TaskModel> GetTasksByTaskId(int taskId)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Eq("Id", taskId))
+                                .List<TaskModel>();
+                        return queryResult;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+            return null;
+        }
+
+        public bool isContainsTask(int taskId)
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Eq("Id", taskId))
+                                .List<TaskModel>();
+                        return queryResult.Count > 0;
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+            return true;
+        }
+
+        public void removeErrorTask()
+        {
+            ITransaction transaction = null;
+            try
+            {
+                using (ISession session = NHibernateHelper.OpenSession())
+                {
+                    using (transaction = session.BeginTransaction())
+                    {
+                        var queryResult = session.CreateCriteria(typeof(TaskModel))
+                                .Add(Restrictions.Le("Task_status", -1))
+                                .List<TaskModel>();
+                        for (int i = 0; i < queryResult.Count; ++i) {
+                            ICollection<DownloadTaskModel> downloadTaskModels = queryResult[i].DownloadTaskModelList;
+                            for (int j = 0; j < downloadTaskModels.Count; ++j) {
+                                session.Delete(downloadTaskModels.ElementAt(j));
+                            }
+                            session.Delete(queryResult[i]);
+                        }
+                        transaction.Commit();
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                Console.WriteLine(ex.Message);
+            }
+        }
+    }
+}

+ 11 - 0
Dispatcher/TaskDatabase/hibernate.cfg.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
+  <session-factory>
+    <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
+    <property name="dialect">NHibernate.Dialect.MySQL5Dialect</property>
+    <property name="connection.driver_class">NHibernate.Driver.MySqlDataDriver</property>
+    <property name="connection.connection_string">Server=localhost;Database=worker;User ID=root;Password=123456</property>
+    <property name="show_sql">false</property>
+    <mapping assembly="TaskDatabase"/>
+  </session-factory>
+</hibernate-configuration>

+ 10 - 0
Dispatcher/TaskDatabase/packages.config

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="Antlr3.Runtime" version="3.5.1" targetFramework="net461" />
+  <package id="Google.Protobuf" version="3.5.0" targetFramework="net461" />
+  <package id="Iesi.Collections" version="4.0.4" targetFramework="net461" />
+  <package id="MySql.Data" version="6.10.8" targetFramework="net461" />
+  <package id="NHibernate" version="5.2.0" targetFramework="net461" />
+  <package id="Remotion.Linq" version="2.2.0" targetFramework="net461" />
+  <package id="Remotion.Linq.EagerFetching" version="2.2.0" targetFramework="net461" />
+</packages>