using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Text; using Livia.Utility; using Microsoft.Extensions.Logging; namespace Livia.Models.Data; public class LocalCommandLineServerHandler(ILogger logger) : IServerHandler { public event PropertyChangedEventHandler? PropertyChanged; public event PropertyChangingEventHandler? PropertyChanging; public bool Processing { get; set; } public bool IsLoggedIn => true; public string Quota => "0"; private const int FilePrintCount = 10; public async Task<(bool success, string messageIndex)> ProcessData(DataBlock dataBlock, CancellationToken token) { string outputPath = Path.Combine(ServiceConfigurations.TempFolder, dataBlock.Key); string prevWorkingDirectory = Environment.CurrentDirectory; if (dataBlock.ArgsDict == null) { return (false, "ServerErrorUnknown"); } try { string inputDir = dataBlock.ArgsDict["input_dir"]; logger.LogInformation("Input dir: {path}", inputDir); DirectoryInfo dirInfo = new(inputDir); if (!dirInfo.Exists) { return (false, "InvalidInputDirectoryError"); } logger.LogInformation("Printing first {num} files", FilePrintCount); LogDirInfo(dirInfo, FilePrintCount); string exePath = Path.Join(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "cereflow_command_line"); logger.LogInformation("Attempting to find exe in {path}", exePath); Environment.CurrentDirectory = exePath; string args = $"--input_dir \"{inputDir}\" --tmp_dir \"{outputPath}\" --output_dicom_dir \"{dataBlock.ArgsDict["output_dir"]}\" --language \"{LiviaUtility.GetLanguageOnlyString()}\""; logger.LogInformation("Args is :{args}", args); Process process = new(); process.StartInfo.FileName = "cmd"; process.StartInfo.Arguments = args; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardError = true; process.StartInfo.RedirectStandardInput = true; process.StartInfo.StandardOutputEncoding = Encoding.UTF8; process.StartInfo.StandardErrorEncoding = Encoding.UTF8; process.StartInfo.StandardInputEncoding = Encoding.UTF8; process.OutputDataReceived += OutputDataReceived; process.ErrorDataReceived += ErrorDataReceived; process.Start(); await using StreamWriter streamWriter = process.StandardInput; //set everything to utf-8 // ReSharper disable once StringLiteralTypo await streamWriter.WriteLineAsync(@"C:\Windows\System32\chcp.com 65001"); // ReSharper disable once StringLiteralTypo await streamWriter.WriteLineAsync("set PYTHONIOENCODING=utf-8"); // ReSharper disable once StringLiteralTypo await streamWriter.WriteLineAsync("set PYTHONUTF8=1"); await streamWriter.WriteLineAsync($"command_line.exe {args}"); await streamWriter.WriteLineAsync("exit"); process.BeginOutputReadLine(); process.BeginErrorReadLine(); await process.WaitForExitAsync(token); logger.LogInformation("Process exited with code {code}", process.ExitCode); if (process.ExitCode != 0) { return (false, $"ServerError{process.ExitCode}"); } process.Close(); dataBlock.ResultPath = Path.Join(outputPath, "result"); File.Create(Path.Join(outputPath, "complete")); } catch (Exception e) { logger.LogError(e, "Error in ProcessData:"); return (false, "ServerErrorUnknown"); } finally { Environment.CurrentDirectory = prevWorkingDirectory; } return (true, ""); } private void LogDirInfo(DirectoryInfo dirInfo, int count) { foreach (FileInfo fileInfo in dirInfo.GetFiles()) { logger.LogInformation(fileInfo.FullName); count--; if (count <= 0) return; } foreach (DirectoryInfo directoryInfo in dirInfo.GetDirectories()) { LogDirInfo(directoryInfo, count); if (count <= 0) return; } } private void OutputDataReceived(object sendingProcess, DataReceivedEventArgs outLine) { logger.LogInformation(outLine.Data); } private void ErrorDataReceived(object sendingProcess, DataReceivedEventArgs outLine) { logger.LogError(outLine.Data); } public Task<(bool success, string messageIndex)> DownloadData(DataBlock dataBlock) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task<(bool success, string messageIndex)> DownloadReport(string key, int id, string savePath, CancellationToken token) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task<(bool success, string messageIndex)> EditPassword(string oldPassword, string newPassword) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task<(List list, int count)> CheckServerJobList(int limit, int offset) { return Task.FromResult((new List(), 0)); } public Task<(List list, int count)> SearchData(SearchQueryJson json) { return Task.FromResult((new List(), 0)); } public Task> GetReportList(string key) { return Task.FromResult(new List()); } public Task Login(string username, string password) { return Task.FromResult("ServerErrorUnknown"); } public Task Cancel(string key) { return Task.CompletedTask; } public Task DeleteReport(string key, int id) { return Task.CompletedTask; } public Task<(bool success, string messageIndex)> DownloadArchive(string? key, string savePath, CancellationToken token) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task<(bool success, string messageIndex)> DownloadSorted(string? key, string savePath, CancellationToken none) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task<(bool success, string messageIndex)> DeleteData(int? dataKey, CancellationToken cancellationToken) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task<(bool success, string messageIndex)> DeleteHistory(string? key, CancellationToken cancellationToken) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task UpdateDongleInfo() { return Task.CompletedTask; } public Task GetNotice() { return Task.FromResult(null); } public Task> GetSeriesGroupList(string key) { return Task.FromResult(new List()); } public Task<(bool success, string messageIndex)> SelectSeries(string key, List series) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task<(bool success, string messageIndex)> SelectReportModule(string fileName, SelectReportModuleJson json, CancellationToken token) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task<(bool success, string messageIndex)> PushToPacs(string key, int id) { return Task.FromResult((false, "ServerErrorUnknown")); } public Task GetDicomNodeInfo() { return Task.FromResult(null); } public static (string msgIndex, string arg, Dictionary? argsDictionary) ParseArgs(IEnumerable requiredArgList) { Dictionary? argsDictionary; try { argsDictionary = LiviaUtility.ParseArgs(Environment.GetCommandLineArgs()); foreach (string arg in requiredArgList) { if (argsDictionary.ContainsKey(arg)) continue; //set argsDictionary to null is important here because otherwise commandline will run. return ("ArgumentNotFoundError", arg, null); } } catch (ArgumentException e) { return ("InvalidArgumentError", e.Message, null); } catch (Exception e) { return ("ParsingArgumentError", e.Message, null); } return ("", "", argsDictionary); } }