using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; namespace FileInterface.Scheduler { public sealed class CronJobExecutor { private readonly ICustomFunctionInvoker _invoker; private readonly JobLog _log; public CronJobExecutor(ICustomFunctionInvoker invoker, JobLog log) { _invoker = invoker; _log = log; } public void Execute(CronJobConfig job) { if (job.CallOnceWithoutFile) { ExecuteSingle(job, null); return; } if (!Directory.Exists(job.SourceDirectory)) { _log.Error(job, "Source directory does not exist: " + job.SourceDirectory); return; } SearchOption option = job.IncludeSubdirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly; string[] files; try { files = Directory.GetFiles(job.SourceDirectory, String.IsNullOrWhiteSpace(job.SearchPattern) ? "*.*" : job.SearchPattern, option) .OrderBy(f => f, StringComparer.OrdinalIgnoreCase) .ToArray(); } catch (Exception ex) { _log.Error(job, "Cannot enumerate source files: " + ex.Message); return; } _log.Info(job, "Found " + files.Length + " file(s)."); foreach (string file in files) { try { ExecuteSingle(job, file); } catch (Exception ex) { _log.Error(job, "File failed: " + file + " - " + ex.Message); } } } private void ExecuteSingle(CronJobConfig job, string file) { string rawContent = ""; string processedContent = ""; if (file != null) { // Opening with FileShare.ReadWrite prevents common producer/consumer lock issues. using (var stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) using (var reader = new StreamReader(stream, Encoding.UTF8, true)) rawContent = reader.ReadToEnd(); processedContent = ProcessContent(rawContent, job.RemoveEmptyLines, job.JoinSeparator); } string[] inArgs = (job.InArgs ?? new List()) .Select(arg => Expand(arg, job, file, rawContent, processedContent)) .ToArray(); _log.Info(job, "Calling CustomFunction '" + job.CustomFunction + "' with " + inArgs.Length + " inArg(s)" + (file == null ? "." : " for " + Path.GetFileName(file) + ".")); 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 (file != null && job.MoveFileAfterSuccess) { string movedTo = MoveProcessedFile(file, job.MoveTargetDirectory, job.OverwriteTargetFile); _log.Info(job, "Moved file to: " + movedTo); } } 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, CronJobConfig job, string file, string rawContent, string processedContent) { string value = template ?? ""; string fullPath = file ?? ""; string fileName = file == null ? "" : Path.GetFileName(file); string extension = file == null ? "" : Path.GetExtension(file); string directory = file == null ? "" : Path.GetDirectoryName(file); return value .Replace("{{CONTENT}}", processedContent ?? "") .Replace("{{RAW_CONTENT}}", rawContent ?? "") .Replace("{{FILE_NAME}}", fileName ?? "") .Replace("{{FILE_PATH}}", fullPath) .Replace("{{FILE_DIR}}", directory ?? "") .Replace("{{FILE_EXT}}", extension ?? "") .Replace("{{JOB_NAME}}", job.Name ?? "") .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; } } }