123 lines
4.1 KiB
C#
123 lines
4.1 KiB
C#
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.ServiceProcess;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace HikvisionAttendanceService;
|
|
|
|
internal static class Program
|
|
{
|
|
[DllImport("kernel32.dll", SetLastError = true)]
|
|
private static extern bool AllocConsole();
|
|
|
|
private static bool ArgsContainFlag(string[] args, string flag) =>
|
|
args.Any(a => string.Equals(a, flag, StringComparison.OrdinalIgnoreCase));
|
|
|
|
private static bool ArgsContainTestFlag(string[] args) =>
|
|
ArgsContainFlag(args, "--test");
|
|
|
|
private static bool ShouldRunAsConsole(string[] args)
|
|
{
|
|
if (ArgsContainFlag(args, "--console") || ArgsContainFlag(args, "--debug"))
|
|
return true;
|
|
|
|
// F5 / Debug from Visual Studio / Cursor: run interactively instead of ServiceBase.
|
|
if (Debugger.IsAttached)
|
|
return true;
|
|
|
|
// Double-click / direct run of exe outside SCM.
|
|
if (Environment.UserInteractive)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
private static async Task Main(string[] args)
|
|
{
|
|
if (ArgsContainTestFlag(args))
|
|
{
|
|
Console.WriteLine("Program entry (test): rawArgCount=" + args.Length + " rawArgs=" + string.Join(" ", args));
|
|
await AttendanceTestMode.RunAsync(args).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
if (ShouldRunAsConsole(args))
|
|
{
|
|
await RunConsoleHostAsync(args).ConfigureAwait(false);
|
|
return;
|
|
}
|
|
|
|
ServiceBase.Run(new ServiceBase[]
|
|
{
|
|
new HikvisionAttendanceWindowsService()
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// Same runtime path as the Windows Service OnStart/OnStop, but runnable under debugger (F5).
|
|
/// Press Ctrl+C (or Stop Debugging) to shut down cleanly.
|
|
/// </summary>
|
|
private static async Task RunConsoleHostAsync(string[] args)
|
|
{
|
|
try
|
|
{
|
|
// Make console output visible when debugging a WinExe project.
|
|
if (Environment.UserInteractive)
|
|
AllocConsole();
|
|
}
|
|
catch
|
|
{
|
|
// ignore: console may already exist
|
|
}
|
|
|
|
Environment.CurrentDirectory = AppContext.BaseDirectory;
|
|
var baseDir = AppContext.BaseDirectory;
|
|
var configPath = Path.Combine(baseDir, "serviceconfig.json");
|
|
if (!File.Exists(configPath))
|
|
configPath = Path.Combine(baseDir, "appsettings.json");
|
|
|
|
var config = HikvisionAttendanceWindowsService.HikvisionServiceConfig.Load(configPath);
|
|
var logger = new HikvisionAttendanceWindowsService.FileLogger(config.LogDirectory);
|
|
|
|
Console.WriteLine("HikvisionAttendanceService console/debug host starting...");
|
|
Console.WriteLine("Config: " + configPath);
|
|
Console.WriteLine("LogDirectory: " + config.LogDirectory);
|
|
Console.WriteLine("Press Ctrl+C to stop.");
|
|
logger.Ops(OpsMarkers.Service, "CONSOLE HOST START time=" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") +
|
|
" config=\"" + configPath + "\" debuggerAttached=" + Debugger.IsAttached);
|
|
|
|
using var cts = new CancellationTokenSource();
|
|
Console.CancelKeyPress += (_, e) =>
|
|
{
|
|
e.Cancel = true;
|
|
Console.WriteLine("Shutdown requested...");
|
|
logger.Ops(OpsMarkers.Service, "STOP REQUESTED reason=\"Ctrl+C\"");
|
|
cts.Cancel();
|
|
};
|
|
|
|
using var manager = new HikvisionAttendanceManager(config, logger);
|
|
try
|
|
{
|
|
await manager.RunAsync(cts.Token).ConfigureAwait(false);
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// expected on stop
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error("Console/debug host failed", ex);
|
|
logger.OpsError(OpsMarkers.Service, "CONSOLE HOST FAILED reason=\"" + ex.Message + "\"");
|
|
Console.WriteLine("FATAL: " + ex.Message);
|
|
throw;
|
|
}
|
|
|
|
logger.Ops(OpsMarkers.Service, "CONSOLE HOST END");
|
|
Console.WriteLine("HikvisionAttendanceService stopped.");
|
|
}
|
|
}
|