Resolve merge conflicts - keep production-ready service manager implementation
- Resolved conflicts in service_manager/src/lib.rs - Resolved conflicts in service_manager/src/launchctl.rs - Resolved conflicts in service_manager/src/zinit.rs - Resolved conflicts in service_manager/README.md - Kept our production-ready synchronous API design - Maintained comprehensive service lifecycle management - Preserved cross-platform compatibility (macOS/Linux) - All tests passing and ready for production use
This commit is contained in:
		
							
								
								
									
										47
									
								
								service_manager/examples/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								service_manager/examples/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| # Service Manager Examples | ||||
|  | ||||
| This directory contains examples demonstrating the usage of the `sal-service-manager` crate. | ||||
|  | ||||
| ## Running Examples | ||||
|  | ||||
| To run any example, use the following command structure from the `service_manager` crate's root directory: | ||||
|  | ||||
| ```sh | ||||
| cargo run --example <EXAMPLE_NAME> | ||||
| ``` | ||||
|  | ||||
| --- | ||||
|  | ||||
| ### 1. `simple_service` | ||||
|  | ||||
| This example demonstrates the ideal, clean lifecycle of a service using the separated `create` and `start` steps. | ||||
|  | ||||
| **Behavior:** | ||||
| 1.  Creates a new service definition. | ||||
| 2.  Starts the newly created service. | ||||
| 3.  Checks its status to confirm it's running. | ||||
| 4.  Stops the service. | ||||
| 5.  Checks its status again to confirm it's stopped. | ||||
| 6.  Removes the service definition. | ||||
|  | ||||
| **Run it:** | ||||
| ```sh | ||||
| cargo run --example simple_service | ||||
| ``` | ||||
|  | ||||
| ### 2. `service_spaghetti` | ||||
|  | ||||
| This example demonstrates how the service manager handles "messy" or improper sequences of operations, showcasing its error handling and robustness. | ||||
|  | ||||
| **Behavior:** | ||||
| 1.  Creates a service. | ||||
| 2.  Starts the service. | ||||
| 3.  Tries to start the **same service again** (which should fail as it's already running). | ||||
| 4.  Removes the service **without stopping it first** (the manager should handle this gracefully). | ||||
| 5.  Tries to stop the **already removed** service (which should fail). | ||||
| 6.  Tries to remove the service **again** (which should also fail). | ||||
|  | ||||
| **Run it:** | ||||
| ```sh | ||||
| cargo run --example service_spaghetti | ||||
| ``` | ||||
							
								
								
									
										95
									
								
								service_manager/examples/service_spaghetti.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								service_manager/examples/service_spaghetti.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| //! service_spaghetti - An example of messy service management. | ||||
| //! | ||||
| //! This example demonstrates how the service manager behaves when commands | ||||
| //! are issued in a less-than-ideal order, such as starting a service that's | ||||
| //! already running or removing a service that hasn't been stopped. | ||||
|  | ||||
| use sal_service_manager::{create_service_manager, ServiceConfig}; | ||||
| use std::collections::HashMap; | ||||
| use std::thread; | ||||
| use std::time::Duration; | ||||
|  | ||||
| fn main() { | ||||
|     let manager = create_service_manager(None).expect("Failed to create service manager"); | ||||
|     let service_name = "com.herocode.examples.spaghetti"; | ||||
|  | ||||
|     let service_config = ServiceConfig { | ||||
|         name: service_name.to_string(), | ||||
|         binary_path: "/bin/sh".to_string(), | ||||
|         args: vec![ | ||||
|             "-c".to_string(), | ||||
|             "while true; do echo 'Spaghetti service is running...'; sleep 5; done".to_string(), | ||||
|         ], | ||||
|         working_directory: None, | ||||
|         environment: HashMap::new(), | ||||
|         auto_restart: false, | ||||
|     }; | ||||
|  | ||||
|     println!("--- Service Spaghetti Example ---"); | ||||
|     println!("This example demonstrates messy, error-prone service management."); | ||||
|  | ||||
|     // Cleanup from previous runs to ensure a clean slate | ||||
|     if let Ok(true) = manager.exists(service_name) { | ||||
|         println!("\nService '{}' found from a previous run. Cleaning up first.", service_name); | ||||
|         let _ = manager.stop(service_name); | ||||
|         let _ = manager.remove(service_name); | ||||
|         println!("Cleanup complete."); | ||||
|     } | ||||
|  | ||||
|     // 1. Create the service | ||||
|     println!("\n1. Creating the service..."); | ||||
|     match manager.create(&service_config) { | ||||
|         Ok(()) => println!("   -> Success: Service '{}' created.", service_name), | ||||
|         Err(e) => { | ||||
|             eprintln!("   -> Error: Failed to create service: {}. Halting example.", e); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 2. Start the service | ||||
|     println!("\n2. Starting the service for the first time..."); | ||||
|     match manager.start(service_name) { | ||||
|         Ok(()) => println!("   -> Success: Service '{}' started.", service_name), | ||||
|         Err(e) => { | ||||
|             eprintln!("   -> Error: Failed to start service: {}. Halting example.", e); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     thread::sleep(Duration::from_secs(2)); | ||||
|  | ||||
|     // 3. Try to start the service again while it's already running | ||||
|     println!("\n3. Trying to start the *same service* again..."); | ||||
|     match manager.start(service_name) { | ||||
|         Ok(()) => println!("   -> Unexpected Success: Service started again."), | ||||
|         Err(e) => eprintln!("   -> Expected Error: {}. The manager should detect it is already running.", e), | ||||
|     } | ||||
|  | ||||
|     // 3. Let it run for a bit | ||||
|     println!("\n3. Letting the service run for 5 seconds..."); | ||||
|     thread::sleep(Duration::from_secs(5)); | ||||
|  | ||||
|     // 4. Remove the service without stopping it first | ||||
|     // The `remove` function is designed to stop the service if it's running. | ||||
|     println!("\n4. Removing the service without explicitly stopping it first..."); | ||||
|     match manager.remove(service_name) { | ||||
|         Ok(()) => println!("   -> Success: Service was stopped and removed."), | ||||
|         Err(e) => eprintln!("   -> Error: Failed to remove service: {}", e), | ||||
|     } | ||||
|  | ||||
|     // 5. Try to stop the service after it has been removed | ||||
|     println!("\n5. Trying to stop the service that was just removed..."); | ||||
|     match manager.stop(service_name) { | ||||
|         Ok(()) => println!("   -> Unexpected Success: Stopped a removed service."), | ||||
|         Err(e) => eprintln!("   -> Expected Error: {}. The manager knows the service is gone.", e), | ||||
|     } | ||||
|  | ||||
|     // 6. Try to remove the service again | ||||
|     println!("\n6. Trying to remove the service again..."); | ||||
|     match manager.remove(service_name) { | ||||
|         Ok(()) => println!("   -> Unexpected Success: Removed a non-existent service."), | ||||
|         Err(e) => eprintln!("   -> Expected Error: {}. The manager correctly reports it's not found.", e), | ||||
|     } | ||||
|  | ||||
|     println!("\n--- Spaghetti Example Finished ---"); | ||||
| } | ||||
							
								
								
									
										105
									
								
								service_manager/examples/simple_service.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										105
									
								
								service_manager/examples/simple_service.rs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,105 @@ | ||||
| use sal_service_manager::{create_service_manager, ServiceConfig}; | ||||
| use std::collections::HashMap; | ||||
| use std::thread; | ||||
| use std::time::Duration; | ||||
|  | ||||
| fn main() { | ||||
|     // 1. Create a service manager for the current platform | ||||
|     let manager = match create_service_manager(None) { | ||||
|         Ok(manager) => manager, | ||||
|         Err(e) => { | ||||
|             eprintln!("Error: Failed to create service manager: {}", e); | ||||
|             return; | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     // 2. Define the configuration for our new service | ||||
|     let service_name = "com.herocode.examples.simpleservice"; | ||||
|     let service_config = ServiceConfig { | ||||
|         name: service_name.to_string(), | ||||
|         // A simple command that runs in a loop | ||||
|         binary_path: "/bin/sh".to_string(), | ||||
|         args: vec![ | ||||
|             "-c".to_string(), | ||||
|             "while true; do echo 'Simple service is running...'; date; sleep 5; done".to_string(), | ||||
|         ], | ||||
|         working_directory: None, | ||||
|         environment: HashMap::new(), | ||||
|         auto_restart: false, | ||||
|     }; | ||||
|  | ||||
|     println!("--- Service Manager Example ---"); | ||||
|  | ||||
|     // Cleanup from previous runs, if necessary | ||||
|     if let Ok(true) = manager.exists(service_name) { | ||||
|         println!("Service '{}' already exists. Cleaning up before starting.", service_name); | ||||
|         if let Err(e) = manager.stop(service_name) { | ||||
|             println!("Note: could not stop existing service (it might not be running): {}", e); | ||||
|         } | ||||
|         if let Err(e) = manager.remove(service_name) { | ||||
|             eprintln!("Error: failed to remove existing service: {}", e); | ||||
|             return; | ||||
|         } | ||||
|         println!("Cleanup complete."); | ||||
|     } | ||||
|  | ||||
|     // 3. Create the service | ||||
|     println!("\n1. Creating service: '{}'", service_name); | ||||
|     match manager.create(&service_config) { | ||||
|         Ok(()) => println!("Service '{}' created successfully.", service_name), | ||||
|         Err(e) => { | ||||
|             eprintln!("Error: Failed to create service '{}': {}", service_name, e); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 4. Start the service | ||||
|     println!("\n2. Starting service: '{}'", service_name); | ||||
|     match manager.start(service_name) { | ||||
|         Ok(()) => println!("Service '{}' started successfully.", service_name), | ||||
|         Err(e) => { | ||||
|             eprintln!("Error: Failed to start service '{}': {}", service_name, e); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Give it a moment to run | ||||
|     println!("\nWaiting for 2 seconds for the service to initialize..."); | ||||
|     thread::sleep(Duration::from_secs(2)); | ||||
|  | ||||
|     // 4. Check the status of the service | ||||
|     println!("\n2. Checking service status..."); | ||||
|     match manager.status(service_name) { | ||||
|         Ok(status) => println!("Service status: {:?}", status), | ||||
|         Err(e) => eprintln!("Error: Failed to get status for service '{}': {}", service_name, e), | ||||
|     } | ||||
|  | ||||
|     println!("\nLetting the service run for 10 seconds. Check logs if you can."); | ||||
|     thread::sleep(Duration::from_secs(10)); | ||||
|  | ||||
|     // 5. Stop the service | ||||
|     println!("\n3. Stopping service: '{}'", service_name); | ||||
|     match manager.stop(service_name) { | ||||
|         Ok(()) => println!("Service '{}' stopped successfully.", service_name), | ||||
|         Err(e) => eprintln!("Error: Failed to stop service '{}': {}", service_name, e), | ||||
|     } | ||||
|  | ||||
|     println!("\nWaiting for 2 seconds for the service to stop..."); | ||||
|     thread::sleep(Duration::from_secs(2)); | ||||
|  | ||||
|     // Check status again | ||||
|     println!("\n4. Checking status after stopping..."); | ||||
|     match manager.status(service_name) { | ||||
|         Ok(status) => println!("Service status: {:?}", status), | ||||
|         Err(e) => eprintln!("Error: Failed to get status for service '{}': {}", service_name, e), | ||||
|     } | ||||
|  | ||||
|     // 6. Remove the service | ||||
|     println!("\n5. Removing service: '{}'", service_name); | ||||
|     match manager.remove(service_name) { | ||||
|         Ok(()) => println!("Service '{}' removed successfully.", service_name), | ||||
|         Err(e) => eprintln!("Error: Failed to remove service '{}': {}", service_name, e), | ||||
|     } | ||||
|  | ||||
|     println!("\n--- Example Finished ---"); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user