|
|
|
|
@ -1,5 +1,6 @@
|
|
|
|
|
using System;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.ServiceProcess;
|
|
|
|
|
using CncCollector.Config;
|
|
|
|
|
using CncCollector.Core;
|
|
|
|
|
using CncCollector.Api;
|
|
|
|
|
@ -9,7 +10,10 @@ namespace CncCollector
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// CNC机床数据采集服务主入口。
|
|
|
|
|
/// 支持控制台模式运行和Windows Service部署。
|
|
|
|
|
/// 支持三种运行模式:
|
|
|
|
|
/// 1. Windows Service 模式(由 SCM 启动,无参数)
|
|
|
|
|
/// 2. 控制台交互模式(带 --console 参数)
|
|
|
|
|
/// 3. 服务安装/卸载(带 --install / --uninstall 参数)
|
|
|
|
|
/// </summary>
|
|
|
|
|
class Program
|
|
|
|
|
{
|
|
|
|
|
@ -18,20 +22,69 @@ namespace CncCollector
|
|
|
|
|
static void Main(string[] args)
|
|
|
|
|
{
|
|
|
|
|
// 初始化log4net
|
|
|
|
|
InitLog4Net();
|
|
|
|
|
|
|
|
|
|
// 解析命令行参数
|
|
|
|
|
bool runAsConsole = false;
|
|
|
|
|
bool installService = false;
|
|
|
|
|
bool uninstallService = false;
|
|
|
|
|
|
|
|
|
|
foreach (var arg in args)
|
|
|
|
|
{
|
|
|
|
|
var lower = arg.ToLower().TrimStart('-', '/');
|
|
|
|
|
if (lower == "console") runAsConsole = true;
|
|
|
|
|
else if (lower == "install") installService = true;
|
|
|
|
|
else if (lower == "uninstall") uninstallService = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 模式1:服务安装
|
|
|
|
|
if (installService)
|
|
|
|
|
{
|
|
|
|
|
InstallService();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 模式2:服务卸载
|
|
|
|
|
if (uninstallService)
|
|
|
|
|
{
|
|
|
|
|
UninstallService();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 模式3:控制台交互模式
|
|
|
|
|
if (runAsConsole || Environment.UserInteractive)
|
|
|
|
|
{
|
|
|
|
|
RunConsole();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 模式4:Windows Service 模式(由 SCM 调用)
|
|
|
|
|
RunAsService();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 初始化log4net日志
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void InitLog4Net()
|
|
|
|
|
{
|
|
|
|
|
var logConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "log4net.config");
|
|
|
|
|
if (File.Exists(logConfig))
|
|
|
|
|
{
|
|
|
|
|
log4net.Config.XmlConfigurator.Configure(new FileInfo(logConfig));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// 开发模式:从项目根目录读取
|
|
|
|
|
logConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "..", "..", "..", "log4net.config");
|
|
|
|
|
if (File.Exists(logConfig))
|
|
|
|
|
log4net.Config.XmlConfigurator.Configure(new FileInfo(logConfig));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("CNC 机床数据采集服务 v1.0");
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 控制台交互模式:手动启停,按任意键退出
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void RunConsole()
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("CNC 机床数据采集服务 v1.0(控制台模式)");
|
|
|
|
|
Console.WriteLine("================================================");
|
|
|
|
|
|
|
|
|
|
// 加载配置
|
|
|
|
|
@ -65,15 +118,23 @@ namespace CncCollector
|
|
|
|
|
var engine = new CollectorEngine(config);
|
|
|
|
|
var apiServer = new CollectorApiServer(engine, config.ApiKey, config.ApiPort);
|
|
|
|
|
|
|
|
|
|
// 启动引擎
|
|
|
|
|
// 启动
|
|
|
|
|
engine.Start();
|
|
|
|
|
|
|
|
|
|
// 启动管理API
|
|
|
|
|
apiServer.Start();
|
|
|
|
|
|
|
|
|
|
Console.WriteLine($"\n管理API: http://localhost:{config.ApiPort}/api/collector/status");
|
|
|
|
|
Console.WriteLine($"API Key: {config.ApiKey}");
|
|
|
|
|
Console.WriteLine($"\n按任意键退出...");
|
|
|
|
|
|
|
|
|
|
// 注册 Ctrl+C 优雅退出
|
|
|
|
|
Console.CancelKeyPress += (sender, e) =>
|
|
|
|
|
{
|
|
|
|
|
e.Cancel = true;
|
|
|
|
|
Console.WriteLine("\n正在停止...");
|
|
|
|
|
apiServer.Stop();
|
|
|
|
|
engine.Stop();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Console.ReadKey();
|
|
|
|
|
|
|
|
|
|
// 退出
|
|
|
|
|
@ -83,5 +144,226 @@ namespace CncCollector
|
|
|
|
|
_log.Info("采集服务已退出");
|
|
|
|
|
Console.WriteLine("已退出。");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Windows Service 模式:交给 ServiceBase.Run 管理
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void RunAsService()
|
|
|
|
|
{
|
|
|
|
|
_log.Info("以 Windows Service 模式启动");
|
|
|
|
|
ServiceBase[] servicesToRun = new ServiceBase[]
|
|
|
|
|
{
|
|
|
|
|
new CncCollectorService()
|
|
|
|
|
};
|
|
|
|
|
ServiceBase.Run(servicesToRun);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用 InstallUtil 安装服务
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void InstallService()
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("正在安装 CNC 采集服务...");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
|
|
|
|
var installUtilPath = FindInstallUtil();
|
|
|
|
|
if (installUtilPath == null)
|
|
|
|
|
{
|
|
|
|
|
// 降级到 sc.exe
|
|
|
|
|
Console.WriteLine("未找到 InstallUtil,使用 sc.exe 安装...");
|
|
|
|
|
InstallWithSc(exePath);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var psi = new System.Diagnostics.ProcessStartInfo
|
|
|
|
|
{
|
|
|
|
|
FileName = installUtilPath,
|
|
|
|
|
Arguments = $"\"{exePath}\"",
|
|
|
|
|
Verb = "runas",
|
|
|
|
|
UseShellExecute = false,
|
|
|
|
|
RedirectStandardOutput = true,
|
|
|
|
|
RedirectStandardError = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using (var proc = System.Diagnostics.Process.Start(psi))
|
|
|
|
|
{
|
|
|
|
|
proc.WaitForExit();
|
|
|
|
|
Console.WriteLine(proc.StandardOutput.ReadToEnd());
|
|
|
|
|
if (proc.ExitCode != 0)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("安装失败!");
|
|
|
|
|
Console.WriteLine(proc.StandardError.ReadToEnd());
|
|
|
|
|
Environment.Exit(proc.ExitCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("服务安装成功!使用 Start-Service CncCollector 启动。");
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"安装失败: {ex.Message}");
|
|
|
|
|
Environment.Exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用 InstallUtil 卸载服务
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void UninstallService()
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("正在卸载 CNC 采集服务...");
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 先尝试停止服务
|
|
|
|
|
var svc = ServiceController.GetServices();
|
|
|
|
|
foreach (var s in svc)
|
|
|
|
|
{
|
|
|
|
|
if (s.ServiceName == CncCollectorService.ServiceNameConst)
|
|
|
|
|
{
|
|
|
|
|
if (s.Status == ServiceControllerStatus.Running)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("正在停止服务...");
|
|
|
|
|
s.Stop();
|
|
|
|
|
s.WaitForStatus(ServiceControllerStatus.Stopped, TimeSpan.FromSeconds(30));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var exePath = System.Reflection.Assembly.GetExecutingAssembly().Location;
|
|
|
|
|
var installUtilPath = FindInstallUtil();
|
|
|
|
|
if (installUtilPath == null)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("未找到 InstallUtil,使用 sc.exe 卸载...");
|
|
|
|
|
UninstallWithSc();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var psi = new System.Diagnostics.ProcessStartInfo
|
|
|
|
|
{
|
|
|
|
|
FileName = installUtilPath,
|
|
|
|
|
Arguments = $"/u \"{exePath}\"",
|
|
|
|
|
Verb = "runas",
|
|
|
|
|
UseShellExecute = false,
|
|
|
|
|
RedirectStandardOutput = true,
|
|
|
|
|
RedirectStandardError = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using (var proc = System.Diagnostics.Process.Start(psi))
|
|
|
|
|
{
|
|
|
|
|
proc.WaitForExit();
|
|
|
|
|
Console.WriteLine(proc.StandardOutput.ReadToEnd());
|
|
|
|
|
if (proc.ExitCode != 0)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("卸载失败!");
|
|
|
|
|
Console.WriteLine(proc.StandardError.ReadToEnd());
|
|
|
|
|
Environment.Exit(proc.ExitCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("服务卸载成功。");
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"卸载失败: {ex.Message}");
|
|
|
|
|
Environment.Exit(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 查找 InstallUtil.exe 路径
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static string FindInstallUtil()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var runtimeDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory();
|
|
|
|
|
var path = Path.Combine(runtimeDir, "InstallUtil.exe");
|
|
|
|
|
if (File.Exists(path)) return path;
|
|
|
|
|
}
|
|
|
|
|
catch { }
|
|
|
|
|
|
|
|
|
|
// 尝试 .NET Framework 4 目录
|
|
|
|
|
var frameworkPath = Path.Combine(
|
|
|
|
|
Environment.GetFolderPath(Environment.SpecialFolder.Windows),
|
|
|
|
|
@"Microsoft.NET\Framework64\v4.0.30319\InstallUtil.exe");
|
|
|
|
|
if (File.Exists(frameworkPath)) return frameworkPath;
|
|
|
|
|
|
|
|
|
|
frameworkPath = Path.Combine(
|
|
|
|
|
Environment.GetFolderPath(Environment.SpecialFolder.Windows),
|
|
|
|
|
@"Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe");
|
|
|
|
|
if (File.Exists(frameworkPath)) return frameworkPath;
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用 sc.exe 安装服务(InstallUtil 不可用时的降级方案)
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void InstallWithSc(string exePath)
|
|
|
|
|
{
|
|
|
|
|
var psi = new System.Diagnostics.ProcessStartInfo
|
|
|
|
|
{
|
|
|
|
|
FileName = "sc.exe",
|
|
|
|
|
Arguments = $"create {CncCollectorService.ServiceNameConst} binPath= \"{exePath}\" start= auto DisplayName= \"CNC 机床数据采集服务\"",
|
|
|
|
|
UseShellExecute = false,
|
|
|
|
|
RedirectStandardOutput = true,
|
|
|
|
|
RedirectStandardError = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using (var proc = System.Diagnostics.Process.Start(psi))
|
|
|
|
|
{
|
|
|
|
|
proc.WaitForExit();
|
|
|
|
|
Console.WriteLine(proc.StandardOutput.ReadToEnd());
|
|
|
|
|
if (proc.ExitCode != 0)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("sc.exe 安装失败!");
|
|
|
|
|
Environment.Exit(proc.ExitCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置描述
|
|
|
|
|
var descPsi = new System.Diagnostics.ProcessStartInfo
|
|
|
|
|
{
|
|
|
|
|
FileName = "sc.exe",
|
|
|
|
|
Arguments = $"description {CncCollectorService.ServiceNameConst} \"CNC机床HTTP采集、数据解析、产量跟踪和日终汇总\"",
|
|
|
|
|
UseShellExecute = false
|
|
|
|
|
};
|
|
|
|
|
using (var proc = System.Diagnostics.Process.Start(descPsi))
|
|
|
|
|
{
|
|
|
|
|
proc.WaitForExit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("服务安装成功(sc.exe)!使用 Start-Service CncCollector 启动。");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// 使用 sc.exe 卸载服务(InstallUtil 不可用时的降级方案)
|
|
|
|
|
/// </summary>
|
|
|
|
|
private static void UninstallWithSc()
|
|
|
|
|
{
|
|
|
|
|
var psi = new System.Diagnostics.ProcessStartInfo
|
|
|
|
|
{
|
|
|
|
|
FileName = "sc.exe",
|
|
|
|
|
Arguments = $"delete {CncCollectorService.ServiceNameConst}",
|
|
|
|
|
UseShellExecute = false,
|
|
|
|
|
RedirectStandardOutput = true,
|
|
|
|
|
RedirectStandardError = true
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
using (var proc = System.Diagnostics.Process.Start(psi))
|
|
|
|
|
{
|
|
|
|
|
proc.WaitForExit();
|
|
|
|
|
Console.WriteLine(proc.StandardOutput.ReadToEnd());
|
|
|
|
|
if (proc.ExitCode != 0)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("sc.exe 卸载失败!");
|
|
|
|
|
Environment.Exit(proc.ExitCode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine("服务卸载成功(sc.exe)。");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|