using System.IO.Pipes; using System.Text; using System.Text.Json; namespace PrintServiceCLI; class Program { private const string PipeName = "PrintServicePipe"; private const int TimeoutMs = 5000; static async Task Main(string[] args) { try { // Handle special --install-service flag (called by elevated process) if (args.Contains("--install-service")) { return ServiceManager.EnsureServiceRunning(silent: false) ? 0 : 1; } // Check for skip-service-check flag bool skipServiceCheck = args.Contains("--skip-service-check"); // Parse arguments var command = ParseArguments(args, out bool showHelp); if (showHelp || command == null) { ShowUsage(); return command == null ? 1 : 0; } // Ensure service is running (unless testing) if (!skipServiceCheck) { if (!ServiceManager.EnsureServiceRunning()) { Console.Error.WriteLine("ERROR: Service is not available. Cannot process print request."); return 1; } } var result = await SendCommandToService(command); if (result.Success) { Console.WriteLine($"SUCCESS: {result.Message}"); return 0; } else { Console.Error.WriteLine($"ERROR: {result.Message}"); return 1; } } catch (Exception ex) { Console.Error.WriteLine($"FATAL ERROR: {ex.Message}"); return 1; } } /// /// Parse command line arguments /// static PrintCommand? ParseArguments(string[] args, out bool showHelp) { showHelp = false; string? filePath = null; string? documentType = null; string? orderNumber = null; for (int i = 0; i < args.Length; i++) { switch (args[i].ToLower()) { case "-f": case "--file": if (i + 1 < args.Length) { filePath = args[++i]; } break; case "-t": case "--type": if (i + 1 < args.Length) { documentType = args[++i]; } break; case "-o": case "--order": if (i + 1 < args.Length) { orderNumber = args[++i]; } break; case "-h": case "--help": case "?": showHelp = true; return null; case "--skip-service-check": case "--install-service": // These flags are handled in Main, skip here break; } } // Validate required arguments if (string.IsNullOrEmpty(filePath)) { Console.Error.WriteLine("Error: File path is required (-f)"); return null; } if (string.IsNullOrEmpty(documentType)) { Console.Error.WriteLine("Error: Document type is required (-t)"); return null; } if (!File.Exists(filePath)) { Console.Error.WriteLine($"Error: File not found: {filePath}"); return null; } return new PrintCommand { FilePath = Path.GetFullPath(filePath), DocumentType = documentType, OrderNumber = orderNumber }; } /// /// Send command to service via named pipe /// static async Task SendCommandToService(PrintCommand command) { using var pipeClient = new NamedPipeClientStream( ".", PipeName, PipeDirection.InOut, PipeOptions.Asynchronous); try { await pipeClient.ConnectAsync(TimeoutMs); } catch (TimeoutException) { return new PrintResponse { Success = false, Message = "Service not responding. Is the LAAPC Print Service running?" }; } catch (IOException ex) { return new PrintResponse { Success = false, Message = $"Cannot connect to service: {ex.Message}" }; } // Send command var json = JsonSerializer.Serialize(command); var bytes = Encoding.UTF8.GetBytes(json); await pipeClient.WriteAsync(bytes, 0, bytes.Length); await pipeClient.FlushAsync(); // Read response var buffer = new byte[4096]; var bytesRead = await pipeClient.ReadAsync(buffer, 0, buffer.Length); var responseJson = Encoding.UTF8.GetString(buffer, 0, bytesRead); var response = JsonSerializer.Deserialize(responseJson); return response ?? new PrintResponse { Success = false, Message = "Invalid response from service" }; } /// /// Show usage information /// static void ShowUsage() { Console.WriteLine("LAAPC Print Service CLI"); Console.WriteLine(); Console.WriteLine("Usage: PrintServiceCLI -f -t [-o ]"); Console.WriteLine(); Console.WriteLine("Options:"); Console.WriteLine(" -f, --file Path to the capture file to print (required)"); Console.WriteLine(" -t, --type Document type (required)"); Console.WriteLine(" Examples: invoice, order, delivery"); Console.WriteLine(" -o, --order Optional order number"); Console.WriteLine(" -h, --help Show this help message"); Console.WriteLine(" --skip-service-check Skip service availability check (for testing)"); Console.WriteLine(); Console.WriteLine("Examples:"); Console.WriteLine(" PrintServiceCLI -f \"C:\\Captures\\file.txt\" -t invoice"); Console.WriteLine(" PrintServiceCLI -f \"C:\\Captures\\file.txt\" -t order -o 12345"); Console.WriteLine(); Console.WriteLine("For Development/Testing:"); Console.WriteLine(" PrintServiceCLI -f \"file.txt\" -t test --skip-service-check"); } } /// /// Command to send to service /// class PrintCommand { public string FilePath { get; set; } = string.Empty; public string DocumentType { get; set; } = string.Empty; public string? OrderNumber { get; set; } } /// /// Response from service /// class PrintResponse { public bool Success { get; set; } public string Message { get; set; } = string.Empty; }