Files
Fileinterface_Cron_Job/FileinterfaceCronScheduler/Scheduler/WatcherJobExecutor.cs
2026-08-19 19:27:41 +02:00

150 lines
6.2 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
namespace FileInterface.Scheduler
{
public sealed class WatcherJobExecutor
{
private readonly ICustomFunctionInvoker _invoker;
private readonly JobLog _log;
public WatcherJobExecutor(ICustomFunctionInvoker invoker, JobLog log)
{
_invoker = invoker;
_log = log;
}
public void ExecuteFile(WatcherJobConfig job, string file, string reason)
{
if (job == null) throw new ArgumentNullException("job");
if (String.IsNullOrWhiteSpace(file)) return;
if (!WaitUntilReadable(file, job.FileReadyRetries, job.FileReadyDelayMilliseconds))
{
_log.Error(job, "File is not readable after retries: " + file);
return;
}
string rawContent;
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
using (var reader = new StreamReader(stream, Encoding.UTF8, true))
rawContent = reader.ReadToEnd();
string processedContent = ProcessContent(rawContent, job.RemoveEmptyLines, job.JoinSeparator);
string[] inArgs = (job.InArgs ?? new List<string>())
.Select(arg => Expand(arg, job, file, rawContent, processedContent, reason))
.ToArray();
_log.Info(job, "Calling CustomFunction '" + job.CustomFunction + "' with " + inArgs.Length + " inArg(s) for " + Path.GetFileName(file) + " (" + reason + ").");
CustomFunctionCallResult result = _invoker.Invoke(job.CustomFunction, inArgs);
if (result == null) result = CustomFunctionCallResult.Fail("Invoker returned null.");
if (!result.Success)
{
_log.Error(job, "CustomFunction failed: " + result.Message);
return;
}
_log.Info(job, "CustomFunction succeeded: " + result.Message);
if (job.MoveFileAfterSuccess && File.Exists(file))
{
string movedTo = MoveProcessedFile(file, job.MoveTargetDirectory, job.OverwriteTargetFile);
_log.Info(job, "Moved file to: " + movedTo);
}
}
private static bool WaitUntilReadable(string file, int retries, int delayMs)
{
retries = Math.Max(2, retries);
delayMs = Math.Max(10, delayMs);
long previousLength = -1;
DateTime previousWrite = DateTime.MinValue;
int stableChecks = 0;
for (int i = 0; i < retries; i++)
{
if (!File.Exists(file)) return false;
try
{
var info = new FileInfo(file);
long length = info.Length;
DateTime lastWrite = info.LastWriteTimeUtc;
using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
if (stream.Length != length) length = stream.Length;
}
if (length == previousLength && lastWrite == previousWrite)
{
stableChecks++;
if (stableChecks >= 1) return true;
}
else
{
stableChecks = 0;
previousLength = length;
previousWrite = lastWrite;
}
}
catch (IOException) { stableChecks = 0; }
catch (UnauthorizedAccessException) { stableChecks = 0; }
Thread.Sleep(delayMs);
}
return false;
}
private static string ProcessContent(string text, bool removeEmptyLines, string separator)
{
if (!removeEmptyLines) return text ?? "";
string[] lines = (text ?? "").Replace("\r\n", "\n").Replace('\r', '\n').Split('\n');
return String.Join(separator ?? ";", lines.Where(l => !String.IsNullOrWhiteSpace(l)).Select(l => l.Trim()));
}
private static string Expand(string template, WatcherJobConfig job, string file, string rawContent, string processedContent, string reason)
{
string value = template ?? "";
string fileName = Path.GetFileName(file) ?? "";
string extension = Path.GetExtension(file) ?? "";
string directory = Path.GetDirectoryName(file) ?? "";
return value
.Replace("{{CONTENT}}", processedContent ?? "")
.Replace("{{RAW_CONTENT}}", rawContent ?? "")
.Replace("{{FILE_NAME}}", fileName)
.Replace("{{FILE_PATH}}", file ?? "")
.Replace("{{FILE_DIR}}", directory)
.Replace("{{FILE_EXT}}", extension)
.Replace("{{JOB_NAME}}", job.Name ?? "")
.Replace("{{EVENT}}", reason ?? "")
.Replace("{{NOW}}", DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffK"));
}
private static string MoveProcessedFile(string source, string targetDirectory, bool overwrite)
{
Directory.CreateDirectory(targetDirectory);
string target = Path.Combine(targetDirectory, Path.GetFileName(source));
if (File.Exists(target))
{
if (overwrite) File.Delete(target);
else
{
string name = Path.GetFileNameWithoutExtension(source);
string ext = Path.GetExtension(source);
target = Path.Combine(targetDirectory, name + "_" + DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ext);
int i = 1;
while (File.Exists(target))
{
target = Path.Combine(targetDirectory, name + "_" + DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + "_" + i + ext);
i++;
}
}
}
File.Move(source, target);
return target;
}
}
}