using System.Diagnostics; namespace LiquidCode.Tester.Worker.Services; public class KotlinExecutionService : IExecutionService { private readonly ILogger _logger; public KotlinExecutionService(ILogger logger) { _logger = logger; } public async Task ExecuteAsync(string executablePath, string inputFilePath, int timeLimitMs, int memoryLimitMb) { _logger.LogInformation("Executing Kotlin JAR {Executable} with input {Input}, time limit {TimeLimit}ms, memory limit {MemoryLimit}MB", executablePath, inputFilePath, timeLimitMs, memoryLimitMb); var result = new ExecutionResult(); var stopwatch = Stopwatch.StartNew(); try { using var inputStream = File.OpenRead(inputFilePath); var process = new Process { StartInfo = new ProcessStartInfo { FileName = "java", Arguments = $"-jar \"{executablePath}\"", WorkingDirectory = Path.GetDirectoryName(executablePath), RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true, UseShellExecute = false, CreateNoWindow = true } }; process.Start(); await inputStream.CopyToAsync(process.StandardInput.BaseStream); process.StandardInput.Close(); var outputTask = process.StandardOutput.ReadToEndAsync(); var errorTask = process.StandardError.ReadToEndAsync(); var completedInTime = await Task.Run(() => process.WaitForExit(timeLimitMs)); stopwatch.Stop(); result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds; if (!completedInTime) { try { process.Kill(entireProcessTree: true); } catch { } result.TimeLimitExceeded = true; result.ErrorMessage = "Time limit exceeded"; _logger.LogWarning("Execution exceeded time limit"); return result; } result.Output = await outputTask; result.ErrorOutput = await errorTask; result.ExitCode = process.ExitCode; if (process.ExitCode != 0) { result.RuntimeError = true; result.ErrorMessage = $"Runtime error (exit code {process.ExitCode})"; _logger.LogWarning("Runtime error with exit code {ExitCode}", process.ExitCode); return result; } try { result.MemoryUsedMb = process.PeakWorkingSet64 / (1024 * 1024); if (result.MemoryUsedMb > memoryLimitMb) { result.MemoryLimitExceeded = true; result.ErrorMessage = "Memory limit exceeded"; _logger.LogWarning("Memory limit exceeded: {Used}MB > {Limit}MB", result.MemoryUsedMb, memoryLimitMb); return result; } } catch (Exception ex) { _logger.LogWarning(ex, "Could not measure memory usage"); } result.Success = true; _logger.LogInformation("Execution completed successfully in {Time}ms", result.ExecutionTimeMs); } catch (Exception ex) { stopwatch.Stop(); result.ExecutionTimeMs = stopwatch.ElapsedMilliseconds; result.RuntimeError = true; result.ErrorMessage = $"Execution error: {ex.Message}"; _logger.LogError(ex, "Error during execution"); } return result; } }