feat: make service paths and lifecycle Windows-Service safe

Exe-relative paths + graceful timer shutdown / job isolation.
main
SYED MUSTUFA AHMED NAQVI 2026-09-04 12:38:00 +05:00
parent 0773ee3311
commit 9da7d1b003
2 changed files with 214 additions and 74 deletions

67
ApplicationPaths.cs Normal file
View File

@ -0,0 +1,67 @@
using System;
using System.IO;
namespace HanvonF710XAttendanceService
{
internal static class ApplicationPaths
{
public static string BaseDirectory { get; private set; } = AppDomain.CurrentDomain.BaseDirectory ?? "";
public static string InternalLogs => Path.Combine(BaseDirectory, "InternalLogs");
public static string Logs => Path.Combine(BaseDirectory, "Logs");
public static string TemplateRawLogs => Path.Combine(BaseDirectory, "TemplateRawLogs");
public static void Initialize()
{
BaseDirectory = AppDomain.CurrentDomain.BaseDirectory ?? "";
try
{
Environment.CurrentDirectory = BaseDirectory;
}
catch
{
// Best effort; paths below are always rooted to BaseDirectory.
}
EnsureDirectory(InternalLogs);
EnsureDirectory(Logs);
EnsureDirectory(TemplateRawLogs);
EnsureDirectory(Path.Combine(Logs, "Attendance"));
EnsureDirectory(Path.Combine(Logs, "Machine User service"));
EnsureDirectory(Path.Combine(Logs, "SaveFaceTemplate logs"));
EnsureDirectory(Path.Combine(Logs, "FaceTransferLog"));
}
public static string Resolve(string relativeOrAbsolutePath)
{
if (string.IsNullOrWhiteSpace(relativeOrAbsolutePath))
{
return BaseDirectory;
}
string trimmed = relativeOrAbsolutePath.Trim();
return Path.IsPathRooted(trimmed)
? trimmed
: Path.Combine(BaseDirectory, trimmed);
}
public static string DatedFile(string directory, string filePrefix)
{
string datePart = DateTime.Now.Date.ToShortDateString().Replace('/', '_');
return Path.Combine(directory, filePrefix + "_" + datePart + ".txt");
}
private static void EnsureDirectory(string path)
{
if (string.IsNullOrWhiteSpace(path))
{
return;
}
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
}
}

View File

@ -16,48 +16,35 @@ namespace HanvonF710XAttendanceService
{ {
public partial class HanvonF710XWindowsService : ServiceBase public partial class HanvonF710XWindowsService : ServiceBase
{ {
// Separate timers for attendance/users and template sync. private System.Timers.Timer timer = new System.Timers.Timer();
System.Timers.Timer timer = new System.Timers.Timer(); // attendance + users private System.Timers.Timer timer1 = new System.Timers.Timer();
System.Timers.Timer timer1 = new System.Timers.Timer(); // templates
// Independent locks/flags so jobs don't block each other.
private static readonly object _attendanceLock = new object(); private static readonly object _attendanceLock = new object();
private static readonly object _templateLock = new object(); private static readonly object _templateLock = new object();
private static bool _attendanceJobRunning = false; private static volatile bool _attendanceJobRunning;
private static bool _templateJobRunning = false; private static volatile bool _templateJobRunning;
private volatile bool _stopping;
public HanvonF710XWindowsService() public HanvonF710XWindowsService()
{ {
InitializeComponent(); InitializeComponent();
} }
/// <summary>Starts timers and jobs when running outside the Windows Service Control Manager.</summary>
public void StartForConsole(string[] args) public void StartForConsole(string[] args)
{ {
OnStart(args ?? Array.Empty<string>()); OnStart(args ?? Array.Empty<string>());
} }
/// <summary>Stops timers and flushes logs when running in console/debug mode.</summary>
public void StopForConsole() public void StopForConsole()
{ {
OnStop(); OnStop();
} }
protected override void OnStart(string[] args) protected override void OnStart(string[] args)
{ {
// So the service finds HwDevComm.dll (and sibling DLLs) in the EXE folder ApplicationPaths.Initialize();
string exeDir = AppDomain.CurrentDomain.BaseDirectory;
try
{
Environment.CurrentDirectory = exeDir;
}
catch (Exception ex)
{
try { WriteInternalLog("OnStart set CurrentDirectory failed: " + ex.Message); } catch { }
}
// Start buffered, cross-process-safe logging. try { LogService.Start(); } catch (Exception ex) { Program.WriteInternalLog("LogService.Start failed: " + ex.Message); }
try { LogService.Start(); } catch { }
WriteToFile("--Service is started at " + DateTime.Now); WriteToFile("--Service is started at " + DateTime.Now);
WriteInternalLog("--Service is started at " + DateTime.Now); WriteInternalLog("--Service is started at " + DateTime.Now);
@ -72,12 +59,12 @@ namespace HanvonF710XAttendanceService
double attendanceIntervalMs = Math.Max(1, attendanceMinutes) * 60 * 1000; double attendanceIntervalMs = Math.Max(1, attendanceMinutes) * 60 * 1000;
double templateIntervalMs = Math.Max(1, templateMinutes) * 60 * 1000; double templateIntervalMs = Math.Max(1, templateMinutes) * 60 * 1000;
timer.Elapsed += new ElapsedEventHandler(OnAttendanceElapsed); timer.Elapsed += OnAttendanceElapsed;
timer.Interval = attendanceIntervalMs; timer.Interval = attendanceIntervalMs;
timer.AutoReset = true; timer.AutoReset = true;
timer.Enabled = true; timer.Enabled = true;
timer1.Elapsed += new ElapsedEventHandler(OnTemplateElapsed); timer1.Elapsed += OnTemplateElapsed;
timer1.Interval = templateIntervalMs; timer1.Interval = templateIntervalMs;
timer1.AutoReset = true; timer1.AutoReset = true;
timer1.Enabled = true; timer1.Enabled = true;
@ -87,42 +74,117 @@ namespace HanvonF710XAttendanceService
WriteToFile($"Attendance job interval: {attendanceMinutes} minutes"); WriteToFile($"Attendance job interval: {attendanceMinutes} minutes");
WriteToFile($"Template job interval: {templateMinutes} minutes"); WriteToFile($"Template job interval: {templateMinutes} minutes");
// Run both jobs once immediately on startup (non-blocking).
// Uses the same guarded execution path as the timer callbacks.
try try
{ {
WriteInternalLog("--Startup trigger: running attendance job immediately at " + DateTime.Now); WriteInternalLog("--Startup trigger: running attendance job immediately at " + DateTime.Now);
Task.Run(() => RunAttendanceJob()); Task.Run(() => RunStartupAttendanceJob());
} }
catch { } catch (Exception ex)
{
WriteInternalLog("Startup attendance trigger failed: " + ex.Message);
}
try try
{ {
int delaySec = 30; int delaySec = 30;
WriteInternalLog("--Startup trigger: running template job after " + delaySec + "s at " + DateTime.Now); WriteInternalLog("--Startup trigger: running template job after " + delaySec + "s at " + DateTime.Now);
Task.Run(async () => Task.Run(() => RunStartupTemplateJob(delaySec));
}
catch (Exception ex)
{ {
try WriteInternalLog("Startup template trigger failed: " + ex.Message);
{
await Task.Delay(delaySec * 1000).ConfigureAwait(false);
RunTemplateJob();
} }
catch { }
});
}
catch { }
} }
protected override void OnStop() protected override void OnStop()
{ {
WriteToFile("--Service is stopped at " + DateTime.Now); _stopping = true;
WriteToFile("--Service is stopping at " + DateTime.Now);
WriteInternalLog("--Service is stopping at " + DateTime.Now);
try try
{ {
timer.Enabled = false; timer.Enabled = false;
timer1.Enabled = false; timer1.Enabled = false;
timer.Elapsed -= OnAttendanceElapsed;
timer1.Elapsed -= OnTemplateElapsed;
}
catch (Exception ex)
{
WriteInternalLog("OnStop timer shutdown failed: " + ex.Message);
}
WaitForRunningJobs();
try
{
timer.Dispose(); timer.Dispose();
timer1.Dispose(); timer1.Dispose();
} }
catch { } catch (Exception ex)
{
WriteInternalLog("OnStop timer dispose failed: " + ex.Message);
}
try { LogService.StopAndFlush(TimeSpan.FromSeconds(5)); } catch { } try { LogService.StopAndFlush(TimeSpan.FromSeconds(5)); } catch { }
WriteToFile("--Service is stopped at " + DateTime.Now);
WriteInternalLog("--Service is stopped at " + DateTime.Now);
}
private void WaitForRunningJobs()
{
int waitSeconds = GetIntConfig("SERVICE_SHUTDOWN_WAIT_SECONDS", 300);
if (waitSeconds <= 0)
{
return;
}
var deadline = DateTime.UtcNow.AddSeconds(waitSeconds);
while ((_attendanceJobRunning || _templateJobRunning) && DateTime.UtcNow < deadline)
{
Thread.Sleep(500);
}
if (_attendanceJobRunning || _templateJobRunning)
{
WriteInternalLog($"--Service stop: jobs still running after {waitSeconds}s (attendance={_attendanceJobRunning}, template={_templateJobRunning})");
}
}
private void RunStartupAttendanceJob()
{
try
{
if (_stopping)
{
return;
}
RunAttendanceJob();
}
catch (Exception ex)
{
WriteInternalLog("Startup attendance job error: " + ex);
}
}
private async Task RunStartupTemplateJob(int delaySec)
{
try
{
await Task.Delay(Math.Max(0, delaySec) * 1000).ConfigureAwait(false);
if (_stopping)
{
return;
}
RunTemplateJob();
}
catch (Exception ex)
{
WriteInternalLog("Startup template job error: " + ex);
}
} }
private static int GetIntConfig(string key, int defaultValue) private static int GetIntConfig(string key, int defaultValue)
@ -139,7 +201,6 @@ namespace HanvonF710XAttendanceService
} }
} }
// Attendance + machine-user job
private void OnAttendanceElapsed(object source, ElapsedEventArgs e) private void OnAttendanceElapsed(object source, ElapsedEventArgs e)
{ {
RunAttendanceJob(); RunAttendanceJob();
@ -147,11 +208,18 @@ namespace HanvonF710XAttendanceService
private void RunAttendanceJob() private void RunAttendanceJob()
{ {
if (_stopping)
{
WriteInternalLog("--Attendance tick skipped (service stopping) at " + DateTime.Now);
return;
}
if (!Monitor.TryEnter(_attendanceLock)) if (!Monitor.TryEnter(_attendanceLock))
{ {
WriteInternalLog("--Attendance tick skipped (previous attendance job still running) at " + DateTime.Now); WriteInternalLog("--Attendance tick skipped (previous attendance job still running) at " + DateTime.Now);
return; return;
} }
try try
{ {
if (_attendanceJobRunning) if (_attendanceJobRunning)
@ -159,6 +227,7 @@ namespace HanvonF710XAttendanceService
WriteInternalLog("--Attendance tick skipped (previous attendance job still running) at " + DateTime.Now); WriteInternalLog("--Attendance tick skipped (previous attendance job still running) at " + DateTime.Now);
return; return;
} }
_attendanceJobRunning = true; _attendanceJobRunning = true;
WriteSyncCycleHeader(); WriteSyncCycleHeader();
@ -172,32 +241,42 @@ namespace HanvonF710XAttendanceService
} }
catch (Exception ex) catch (Exception ex)
{ {
WriteInternalLog("syncMachineUsers error: " + ex.Message); WriteInternalLog("syncMachineUsers error: " + ex);
WriteMachineUserServiceLog("syncMachineUsers error: " + ex.Message); WriteMachineUserServiceLog("syncMachineUsers error: " + ex.Message);
} }
if (_stopping)
{
WriteInternalLog("--Attendance job interrupted (service stopping) before attendance sync at " + DateTime.Now);
return;
}
try try
{ {
syncAttendance(); syncAttendance();
} }
catch (Exception ex) catch (Exception ex)
{ {
WriteInternalLog("syncAttendance error: " + ex.Message); WriteInternalLog("syncAttendance error: " + ex);
WriteAttendanceServiceLog("syncAttendance error: " + ex.Message); WriteAttendanceServiceLog("syncAttendance error: " + ex.Message);
} }
WriteInternalLog("--Attendance job finished at " + DateTime.Now); WriteInternalLog("--Attendance job finished at " + DateTime.Now);
WriteAttendanceServiceLog("--Attendance job finished at " + DateTime.Now); WriteAttendanceServiceLog("--Attendance job finished at " + DateTime.Now);
} }
catch (Exception ex)
{
WriteInternalLog("--Attendance job failed: " + ex);
WriteAttendanceServiceLog("--Attendance job failed: " + ex.Message);
}
finally finally
{ {
try { Program.EndSyncCycle(); } catch { } try { Program.EndSyncCycle(); } catch (Exception ex) { WriteInternalLog("EndSyncCycle error: " + ex.Message); }
_attendanceJobRunning = false; _attendanceJobRunning = false;
Monitor.Exit(_attendanceLock); Monitor.Exit(_attendanceLock);
} }
} }
// Template job
private void OnTemplateElapsed(object source, ElapsedEventArgs e) private void OnTemplateElapsed(object source, ElapsedEventArgs e)
{ {
RunTemplateJob(); RunTemplateJob();
@ -205,11 +284,18 @@ namespace HanvonF710XAttendanceService
private void RunTemplateJob() private void RunTemplateJob()
{ {
if (_stopping)
{
WriteInternalLog("--Template tick skipped (service stopping) at " + DateTime.Now);
return;
}
if (!Monitor.TryEnter(_templateLock)) if (!Monitor.TryEnter(_templateLock))
{ {
WriteInternalLog("--Template tick skipped (previous template job still running) at " + DateTime.Now); WriteInternalLog("--Template tick skipped (previous template job still running) at " + DateTime.Now);
return; return;
} }
try try
{ {
if (_templateJobRunning) if (_templateJobRunning)
@ -217,6 +303,7 @@ namespace HanvonF710XAttendanceService
WriteInternalLog("--Template tick skipped (previous template job still running) at " + DateTime.Now); WriteInternalLog("--Template tick skipped (previous template job still running) at " + DateTime.Now);
return; return;
} }
_templateJobRunning = true; _templateJobRunning = true;
WriteJobHeaderToSimpleLogs("TEMPLATE"); WriteJobHeaderToSimpleLogs("TEMPLATE");
@ -229,14 +316,21 @@ namespace HanvonF710XAttendanceService
} }
catch (Exception ex) catch (Exception ex)
{ {
WriteInternalLog("syncTemplatesIfEnabled error: " + ex.ToString()); WriteInternalLog("syncTemplatesIfEnabled error: " + ex);
WriteFaceTemplateTransferLog("syncTemplatesIfEnabled error: " + ex.ToString()); WriteFaceTemplateTransferLog("syncTemplatesIfEnabled error: " + ex);
WriteSaveFaceTemplateLog("syncTemplatesIfEnabled error: " + ex.ToString()); WriteSaveFaceTemplateLog("syncTemplatesIfEnabled error: " + ex);
} }
WriteInternalLog("--Template job finished at " + DateTime.Now); WriteInternalLog("--Template job finished at " + DateTime.Now);
WriteSaveFaceTemplateLog("--Template job finished at " + DateTime.Now); WriteSaveFaceTemplateLog("--Template job finished at " + DateTime.Now);
WriteFaceTemplateTransferLog("--Template job finished at " + DateTime.Now); WriteFaceTemplateTransferLog("--Template job finished at " + DateTime.Now);
} }
catch (Exception ex)
{
WriteInternalLog("--Template job failed: " + ex);
WriteFaceTemplateTransferLog("--Template job failed: " + ex.Message);
WriteSaveFaceTemplateLog("--Template job failed: " + ex.Message);
}
finally finally
{ {
_templateJobRunning = false; _templateJobRunning = false;
@ -244,11 +338,8 @@ namespace HanvonF710XAttendanceService
} }
} }
public void syncAttendance() public void syncAttendance()
{ {
WriteToFile("--Sync Attendance is recall at " + DateTime.Now); WriteToFile("--Sync Attendance is recall at " + DateTime.Now);
WriteInternalLog("--Sync Attendance is recall at " + DateTime.Now); WriteInternalLog("--Sync Attendance is recall at " + DateTime.Now);
WriteAttendanceServiceLog("--Sync Attendance is recall at " + DateTime.Now); WriteAttendanceServiceLog("--Sync Attendance is recall at " + DateTime.Now);
@ -258,17 +349,15 @@ namespace HanvonF710XAttendanceService
WriteToFile(response); WriteToFile(response);
WriteInternalLog(response); WriteInternalLog(response);
// Attendance simple log: only machine-level results and connectivity.
if (IsAttendanceSimpleLine(response)) if (IsAttendanceSimpleLine(response))
{ {
WriteAttendanceServiceLog(response); WriteAttendanceServiceLog(response);
} }
} }
} }
public void syncMachineUsers() public void syncMachineUsers()
{ {
WriteToFile("--Sync Machine users is recall at " + DateTime.Now); WriteToFile("--Sync Machine users is recall at " + DateTime.Now);
WriteInternalLog("--Sync Machine users is recall at " + DateTime.Now); WriteInternalLog("--Sync Machine users is recall at " + DateTime.Now);
WriteMachineUserServiceLog("--Sync Machine users is recall at " + DateTime.Now); WriteMachineUserServiceLog("--Sync Machine users is recall at " + DateTime.Now);
@ -278,43 +367,38 @@ namespace HanvonF710XAttendanceService
WriteToFile(response); WriteToFile(response);
WriteInternalLog(response); WriteInternalLog(response);
// Machine user simple log: only machine totals and connectivity.
if (IsMachineUserSimpleLine(response)) if (IsMachineUserSimpleLine(response))
{ {
WriteMachineUserServiceLog(response); WriteMachineUserServiceLog(response);
} }
} }
} }
public void syncTemplatesIfEnabled() public void syncTemplatesIfEnabled()
{ {
WriteToFile("--Template sync is recall at " + DateTime.Now); WriteToFile("--Template sync is recall at " + DateTime.Now);
WriteInternalLog("--Template sync is recall at " + DateTime.Now); WriteInternalLog("--Template sync is recall at " + DateTime.Now);
// We'll route template logs into either SaveFaceTemplate or FaceTransfer logs based on TRANSFER_MODE.
List<string> responses = Program.syncTemplates(); List<string> responses = Program.syncTemplates();
foreach (var response in responses) foreach (var response in responses)
{ {
WriteToFile(response); WriteToFile(response);
WriteInternalLog(response); WriteInternalLog(response);
// SaveFaceTemplate logs: DEVICE_TO_DB and any "Serial number--" lines.
if (IsSaveFaceTemplateLine(response)) if (IsSaveFaceTemplateLine(response))
{ {
WriteSaveFaceTemplateLog(response); WriteSaveFaceTemplateLog(response);
} }
// FaceTransfer logs: DB_TO_DEVICE / DEVICE_TO_DEVICE and connectivity issues.
if (IsFaceTransferLine(response)) if (IsFaceTransferLine(response))
{ {
WriteFaceTemplateTransferLog(response); WriteFaceTemplateTransferLog(response);
} }
} }
} }
public void WriteToFile(string Message) public void WriteToFile(string Message)
{ {
string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\Logs\\ServiceLog_" + string filepath = ApplicationPaths.DatedFile(ApplicationPaths.Logs, "ServiceLog");
DateTime.Now.Date.ToShortDateString().Replace('/', '_') + ".txt";
LogService.EnqueueLine(filepath, Message); LogService.EnqueueLine(filepath, Message);
} }
@ -336,7 +420,6 @@ namespace HanvonF710XAttendanceService
WriteInternalLog(line3); WriteInternalLog(line3);
WriteInternalLog(line4); WriteInternalLog(line4);
// Simple per-feature logs (keep InternalLogs unchanged).
WriteAttendanceServiceLog(line1); WriteAttendanceServiceLog(line1);
WriteAttendanceServiceLog(line2); WriteAttendanceServiceLog(line2);
WriteAttendanceServiceLog(line3); WriteAttendanceServiceLog(line3);
@ -348,8 +431,6 @@ namespace HanvonF710XAttendanceService
WriteMachineUserServiceLog(line4); WriteMachineUserServiceLog(line4);
} }
// Ensures per-feature simple logs have a header even when a job doesn't call WriteSyncCycleHeader.
// Used by template job.
private void WriteJobHeaderToSimpleLogs(string jobName) private void WriteJobHeaderToSimpleLogs(string jobName)
{ {
string time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); string time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
@ -375,7 +456,6 @@ namespace HanvonF710XAttendanceService
private static bool IsAttendanceSimpleLine(string line) private static bool IsAttendanceSimpleLine(string line)
{ {
if (string.IsNullOrWhiteSpace(line)) return false; if (string.IsNullOrWhiteSpace(line)) return false;
// Keep only the machine summary lines.
if (line.IndexOf(" has ", StringComparison.OrdinalIgnoreCase) >= 0 && if (line.IndexOf(" has ", StringComparison.OrdinalIgnoreCase) >= 0 &&
line.IndexOf(" records", StringComparison.OrdinalIgnoreCase) >= 0) return true; line.IndexOf(" records", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (line.IndexOf(" is not connected", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf(" is not connected", StringComparison.OrdinalIgnoreCase) >= 0) return true;
@ -385,7 +465,6 @@ namespace HanvonF710XAttendanceService
private static bool IsMachineUserSimpleLine(string line) private static bool IsMachineUserSimpleLine(string line)
{ {
if (string.IsNullOrWhiteSpace(line)) return false; if (string.IsNullOrWhiteSpace(line)) return false;
// Keep only "MACHINE X -> N", "X removed from MACHINE Y", and connectivity lines.
if (line.IndexOf(" -> ", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf(" -> ", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (line.IndexOf(" removed from ", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf(" removed from ", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (line.IndexOf(" is not connected", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf(" is not connected", StringComparison.OrdinalIgnoreCase) >= 0) return true;
@ -404,13 +483,11 @@ namespace HanvonF710XAttendanceService
private static bool IsFaceTransferLine(string line) private static bool IsFaceTransferLine(string line)
{ {
if (string.IsNullOrWhiteSpace(line)) return false; if (string.IsNullOrWhiteSpace(line)) return false;
// Any transfer mode other than DEVICE_TO_DB and connectivity issues.
if (line.IndexOf("DB_TO_DEVICE", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf("DB_TO_DEVICE", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (line.IndexOf("DEVICE_TO_DEVICE", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf("DEVICE_TO_DEVICE", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (line.IndexOf("[DB_TO_DEVICE]", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf("[DB_TO_DEVICE]", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (line.IndexOf("TemplateDistribution", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf("TemplateDistribution", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (line.IndexOf("TemplateRegistrationTargets", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf("TemplateRegistrationTargets", StringComparison.OrdinalIgnoreCase) >= 0) return true;
// Peer distribution uses job id "TemplateDist:<ip>" in [TemplateJob ...] lines from GetEmployeeID on targets.
if (line.IndexOf("TemplateDist:", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf("TemplateDist:", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (line.IndexOf("SetEmployee", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf("SetEmployee", StringComparison.OrdinalIgnoreCase) >= 0) return true;
if (line.IndexOf(" is not connected", StringComparison.OrdinalIgnoreCase) >= 0) return true; if (line.IndexOf(" is not connected", StringComparison.OrdinalIgnoreCase) >= 0) return true;
@ -419,10 +496,7 @@ namespace HanvonF710XAttendanceService
private static void AppendLineToDatedLog(string folderName, string filePrefix, string message) private static void AppendLineToDatedLog(string folderName, string filePrefix, string message)
{ {
string baseDir = AppDomain.CurrentDomain.BaseDirectory; string folderPath = Path.Combine(ApplicationPaths.Logs, folderName);
string logsRoot = Path.Combine(baseDir, "Logs");
string folderPath = Path.Combine(logsRoot, folderName);
string datePart = DateTime.Now.ToString("yyyy-MM-dd"); string datePart = DateTime.Now.ToString("yyyy-MM-dd");
string filePath = Path.Combine(folderPath, filePrefix + "_" + datePart + ".txt"); string filePath = Path.Combine(folderPath, filePrefix + "_" + datePart + ".txt");
LogService.EnqueueLine(filePath, message); LogService.EnqueueLine(filePath, message);
@ -447,11 +521,10 @@ namespace HanvonF710XAttendanceService
{ {
AppendLineToDatedLog("FaceTransferLog", "FaceTransferLogs", message); AppendLineToDatedLog("FaceTransferLog", "FaceTransferLogs", message);
} }
public void WriteInternalLog(string Message) public void WriteInternalLog(string Message)
{ {
string filepath = AppDomain.CurrentDomain.BaseDirectory + "\\InternalLogs\\InternalLog_" + Program.WriteInternalLog(Message);
DateTime.Now.Date.ToShortDateString().Replace('/', '_') + ".txt";
LogService.EnqueueLine(filepath, Message);
} }
} }
} }