ceviche/lib.rs
1//! ceviche is a wrapper to write a service/daemon.
2//!
3//! At the moment only Windows services are supported. The Service macro is inspired
4//! from the [winservice](https://crates.io/crates/winservice) crate.
5//!
6//! A service implements a service main function and is generated by invoking
7//! the `Service!` macro. The events are sent to the service over the `rx` channel.
8//!
9//! ```rust,ignore
10//! enum CustomServiceEvent {}
11//!
12//! fn my_service_main(
13//! rx: mpsc::Receiver<ServiceEvent<CustomServiceEvent>>,
14//! _tx: mpsc::Sender<ServiceEvent<CustomServiceEvent>>,
15//! args: Vec<String>,
16//! standalone_mode: bool) -> u32 {
17//! loop {
18//! if let Ok(control_code) = rx.recv() {
19//! match control_code {
20//! ServiceEvent::Stop => break,
21//! _ => (),
22//! }
23//! }
24//! }
25//! 0
26//! }
27//!
28//! Service!("Foobar", my_service_main);
29//! ```
30//!
31//! The Controller is a helper to create, remove, start or stop the service
32//! on the system. ceviche also supports a standalone mode were the service
33//! code runs as a normal executable which can be useful for development and
34//! debugging.
35//!
36//! ```rust,ignore
37//! static SERVICE_NAME: &'static str = "foobar";
38//! static DISPLAY_NAME: &'static str = "FooBar Service";
39//! static DESCRIPTION: &'static str = "This is the FooBar service";
40//!
41//! fn main() {
42//! let yaml = load_yaml!("cli.yml");
43//! let app = App::from_yaml(yaml);
44//! let matches = app.version(crate_version!()).get_matches();
45//! let cmd = matches.value_of("cmd").unwrap_or("").to_string();
46//!
47//! let mut controller = Controller::new(SERVICE_NAME, DISPLAY_NAME, DESCRIPTION);
48//!
49//! match cmd.as_str() {
50//! "create" => controller.create(),
51//! "delete" => controller.delete(),
52//! "start" => controller.start(),
53//! "stop" => controller.stop(),
54//! "standalone" => {
55//! let (tx, rx) = mpsc::channel();
56//!
57//! ctrlc::set_handler(move || {
58//! let _ = tx.send(ServiceEvent::Stop);
59//! }).expect("Failed to register Ctrl-C handler");
60//!
61//! my_service_main(rx, vec![], true);
62//! }
63//! _ => {
64//! let _result = controller.register(service_main_wrapper);
65//! }
66//! }
67//! }
68//!
69//! ```
70
71#[macro_use]
72extern crate cfg_if;
73
74/// Manages the service on the system.
75pub mod controller;
76pub mod session;
77
78#[cfg(windows)]
79pub use windows_sys;
80
81use self::controller::Session;
82use std::fmt;
83
84/// Service errors
85#[derive(Debug)]
86pub struct Error {
87 pub message: String,
88}
89
90impl From<&str> for Error {
91 fn from(message: &str) -> Self {
92 Error {
93 message: message.to_string(),
94 }
95 }
96}
97
98impl fmt::Display for Error {
99 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
100 write!(f, "{}", self.message,)
101 }
102}
103
104impl std::error::Error for Error {
105 fn description(&self) -> &str {
106 &self.message
107 }
108}
109
110impl Error {
111 pub fn new(message: &str) -> Error {
112 Error {
113 message: String::from(message),
114 }
115 }
116}
117
118/// Events that are sent to the service.
119pub enum ServiceEvent<T> {
120 Continue,
121 Pause,
122 Stop,
123 SessionConnect(Session),
124 SessionDisconnect(Session),
125 SessionRemoteConnect(Session),
126 SessionRemoteDisconnect(Session),
127 SessionLogon(Session),
128 SessionLogoff(Session),
129 SessionLock(Session),
130 SessionUnlock(Session),
131 Custom(T),
132}
133
134impl<T> fmt::Display for ServiceEvent<T> {
135 fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
136 match self {
137 ServiceEvent::Continue => write!(f, "Continue"),
138 ServiceEvent::Pause => write!(f, "Pause"),
139 ServiceEvent::Stop => write!(f, "Stop"),
140 ServiceEvent::SessionConnect(id) => write!(f, "SessionConnect({})", id),
141 ServiceEvent::SessionDisconnect(id) => write!(f, "SessionDisconnect({})", id),
142 ServiceEvent::SessionRemoteConnect(id) => write!(f, "SessionRemoteConnect({})", id),
143 ServiceEvent::SessionRemoteDisconnect(id) => {
144 write!(f, "SessionRemoteDisconnect({})", id)
145 }
146 ServiceEvent::SessionLogon(id) => write!(f, "SessionLogon({})", id),
147 ServiceEvent::SessionLogoff(id) => write!(f, "SessionLogoff({})", id),
148 ServiceEvent::SessionLock(id) => write!(f, "SessionLock({})", id),
149 ServiceEvent::SessionUnlock(id) => write!(f, "SessionUnlock({})", id),
150 ServiceEvent::Custom(_) => write!(f, "Custom"),
151 }
152 }
153}