Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Difference From qsu-0.0.3 To qsu-0.0.4
2023-11-03
| ||
09:10 | Use Rocket 0.5.0-rc.4. check-in: 074300f463 user: jan tags: qsu-0.0.5, trunk | |
2023-10-29
| ||
14:14 | Fix doc ref. check-in: fb71171304 user: jan tags: qsu-0.0.4, trunk | |
14:11 | Prepare 0.0.4. check-in: b7eb7c0490 user: jan tags: trunk | |
2023-10-25
| ||
14:27 | Remove CbOrigin. Use AppErr for argp errors. check-in: 2190365c01 user: jan tags: trunk | |
2023-10-23
| ||
12:29 | Update index.md. check-in: 0d49c4abb4 user: jan tags: qsu-0.0.3, trunk | |
12:20 | Release maintenance. check-in: ef926ac904 user: jan tags: trunk | |
Changes to Cargo.toml.
1 2 | [package] name = "qsu" | | | 1 2 3 4 5 6 7 8 9 10 | [package] name = "qsu" version = "0.0.4" edition = "2021" license = "0BSD" categories = [ "asynchronous" ] keywords = [ "service", "systemd", "winsvc" ] repository = "https://repos.qrnch.tech/pub/qsu" description = "Service subsystem wrapper." rust-version = "1.56" |
︙ | ︙ | |||
28 29 30 31 32 33 34 | rt = [] tokio = ["rt", "tokio/macros", "tokio/rt-multi-thread", "tokio/signal"] wait-for-debugger = ["dep:dbgtools-win"] [dependencies] async-trait = { version = "0.1.74" } chrono = { version = "0.4.24" } | | | | 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | rt = [] tokio = ["rt", "tokio/macros", "tokio/rt-multi-thread", "tokio/signal"] wait-for-debugger = ["dep:dbgtools-win"] [dependencies] async-trait = { version = "0.1.74" } chrono = { version = "0.4.24" } clap = { version = "4.4.7", optional = true, features = [ "derive", "env", "string", "wrap_help" ] } env_logger = { version = "0.10.0" } futures = { version = "0.3.29" } itertools = { version = "0.11.0", optional = true } killswitch = { version = "0.4.2" } log = { version = "0.4.20" } parking_lot = { version = "0.12.1" } rocket = { version = "0.5.0-rc.3", optional = true } sidoc = { version = "0.1.0", optional = true } tokio = { version = "1.33.0", features = ["sync"] } |
︙ | ︙ |
Changes to examples/argp/mod.rs.
1 2 | use clap::ArgMatches; | | > > | > > | | > > > > > > > > > > > > > > | | | | | | | | | | | | | | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | use clap::ArgMatches; use qsu::{installer::RegSvc, rt::SrvAppRt, AppErr}; use crate::err::Error; pub(crate) struct AppArgsProc { pub(crate) bldr: Box<dyn Fn() -> SrvAppRt> } impl qsu::argp::ArgsProc for AppArgsProc { /// Process an `register-service` subcommand. fn proc_inst( &mut self, _sub_m: &ArgMatches, regsvc: RegSvc ) -> Result<RegSvc, qsu::AppErr> { // This is split out into its own function because the orphan rule wouldn't // allow the application to implement a std::io::Error -> qsu::AppErr // conversion in one go, so we do it in two steps instead. // proc_inst_inner()'s '?' converts "all" errors into 'Error`. // The proc_inst() method's `?` converts from `Error` to `qsu::AppError` Ok(proc_inst_inner(regsvc)?) } fn build_apprt(&mut self) -> Result<SrvAppRt, AppErr> { Ok((self.bldr)()) } } fn proc_inst_inner(regsvc: RegSvc) -> Result<RegSvc, Error> { // Use current working directory as the service's workdir let cwd = std::env::current_dir()?.to_str().unwrap().to_string(); let regsvc = regsvc .workdir(cwd) .env("HOLY", "COW") .env("Private", "Public") .env("General", "Specific"); // Add a callback that will increase log and trace levels by deafault. #[cfg(windows)] let regsvc = regsvc.regconf(|_svcname, params| { params.set_value("AppArgParser", &"SaysHello")?; Ok(()) }); Ok(regsvc) } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to examples/err/mod.rs.
︙ | ︙ | |||
30 31 32 33 34 35 36 | impl From<qsu::Error> for Error { fn from(err: qsu::Error) -> Self { Error::Qsu(err.to_string()) } } /* | | | > > | 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | impl From<qsu::Error> for Error { fn from(err: qsu::Error) -> Self { Error::Qsu(err.to_string()) } } /* /// Convenience converter used to pass application-defined errors from the /// inner callback back out from the qsu runtime. impl From<Error> for qsu::Error { fn from(err: Error) -> qsu::Error { qsu::Error::app(err) } } */ /// Convenience converter for mapping application-specific errors to /// `qsu::AppErr`. impl From<Error> for qsu::AppErr { fn from(err: Error) -> qsu::AppErr { qsu::AppErr::new(err) } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to examples/hellosvc-rocket.rs.
︙ | ︙ | |||
92 93 94 95 96 97 98 | // In the future we'll be able to use Try to implement support for implicit // conversion to ProcRes from a Result using `?`, but for now use this hack. ProcRes::into(main2().into()) } fn main2() -> Result<(), Error> { // Derive default service name from executable name. | < > > > > > | > > | < < < | 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 | // In the future we'll be able to use Try to implement support for implicit // conversion to ProcRes from a Result using `?`, but for now use this hack. ProcRes::into(main2().into()) } fn main2() -> Result<(), Error> { // Derive default service name from executable name. let svcname = qsu::default_service_name() .expect("Unable to determine default service name"); let creator = || { let handler = Box::new(MyService {}); SrvAppRt::Rocket(handler) }; // Parse, and process, command line arguments. let mut argsproc = argp::AppArgsProc { bldr: Box::new(creator) }; let ap = ArgParser::new(&svcname, &mut argsproc); ap.proc()?; Ok(()) } #[get("/")] fn index() -> &'static str { log::error!("error"); |
︙ | ︙ |
Changes to examples/hellosvc-tokio.rs.
︙ | ︙ | |||
86 87 88 89 90 91 92 | // In the future we'll be able to use Try to implement support for implicit // conversion to ProcRes from a Result using `?`, but for now use this hack. ProcRes::into(main2().into()) } fn main2() -> Result<(), Error> { // Derive default service name from executable name. | < > > > > > | > > | < < < | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | // In the future we'll be able to use Try to implement support for implicit // conversion to ProcRes from a Result using `?`, but for now use this hack. ProcRes::into(main2().into()) } fn main2() -> Result<(), Error> { // Derive default service name from executable name. let svcname = qsu::default_service_name() .expect("Unable to determine default service name"); let creator = || { let handler = Box::new(MyService {}); SrvAppRt::Tokio(None, handler) }; // Parse, and process, command line arguments. let mut argsproc = argp::AppArgsProc { bldr: Box::new(creator) }; let ap = ArgParser::new(&svcname, &mut argsproc); ap.proc()?; Ok(()) } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to examples/hellosvc.rs.
︙ | ︙ | |||
89 90 91 92 93 94 95 | // In the future we'll be able to use Try to implement support for implicit // conversion to ProcRes from a Result using `?`, but for now use this hack. ProcRes::into(main2().into()) } fn main2() -> Result<(), Error> { // Derive default service name from executable name. | < > > > > > | > > | < < < | 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | // In the future we'll be able to use Try to implement support for implicit // conversion to ProcRes from a Result using `?`, but for now use this hack. ProcRes::into(main2().into()) } fn main2() -> Result<(), Error> { // Derive default service name from executable name. let svcname = qsu::default_service_name() .expect("Unable to determine default service name"); let creator = || { let handler = Box::new(MyService {}); SrvAppRt::Sync(handler) }; // Parse, and process, command line arguments. let mut argsproc = argp::AppArgsProc { bldr: Box::new(creator) }; let ap = ArgParser::new(&svcname, &mut argsproc); ap.proc()?; Ok(()) } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/argp.rs.
1 2 3 4 5 6 7 | //! Helpers for integrating clap into an application using _qsu_. use clap::{builder::Str, Arg, ArgAction, ArgMatches, Args, Command}; use crate::{ installer::{self, RegSvc}, lumberjack::LogLevel, | > | < | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | //! Helpers for integrating clap into an application using _qsu_. use clap::{builder::Str, Arg, ArgAction, ArgMatches, Args, Command}; use crate::{ err::{AppErr, Error}, installer::{self, RegSvc}, lumberjack::LogLevel, rt::{RunCtx, SrvAppRt} }; /// Modify a `clap` [`Command`] instance to accept common service management /// subcommands. /// /// If `inst_subcmd` is `Some()`, it should be the name of the subcommand used |
︙ | ︙ | |||
100 101 102 103 104 105 106 | .short('n') .long("name") .action(ArgAction::Set) .value_name("SVCNAME") .default_value(Str::from(svcname.to_string())) .help("Set service name"); | < < < < < < < < | 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | .short('n') .long("name") .action(ArgAction::Set) .value_name("SVCNAME") .default_value(Str::from(svcname.to_string())) .help("Set service name"); //Command::new(cmd).arg(namearg).arg(autostartarg) let cli = Command::new(cmd.to_string()).arg(namearg); RegSvcArgs::augment_args(cli) } |
︙ | ︙ | |||
178 179 180 181 182 183 184 | let cli = Command::new(cmd.to_string()).arg(namearg); RunSvcArgs::augment_args(cli) } | | | > > > > > > > | > | > | < < | > | > | < | | < | | | > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > | 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 | let cli = Command::new(cmd.to_string()).arg(namearg); RunSvcArgs::augment_args(cli) } pub(crate) enum ArgpRes<'cb> { /// Run server application. RunApp(RunCtx, &'cb mut dyn ArgsProc), /// Nothing to do (service was probably registered/deregistred). Quit } /// Parsed service running arguments. pub struct RunSvc { pub svcname: String } impl RunSvc { pub fn from_cmd_match(matches: &ArgMatches) -> Self { let svcname = matches.get_one::<String>("svcname").unwrap().to_owned(); Self { svcname } } } pub enum Cmd { Root, Inst, Rm, Run } /// Allow application to customise behavior of an [`ArgParser`] instance. pub trait ArgsProc { /// Give the application an opportunity to modify the root and subcommand /// `Command`s. /// /// `cmdtype` indicates whether `cmd` is the root `Command` or one of the /// subcommand `Command`s. #[allow(unused_variables)] fn conf_cmd( &mut self, cmdtype: Cmd, cmd: Command ) -> Result<Command, AppErr> { Ok(cmd) } /// Callback allowing application to configure the service registration /// context just before the service is registered. /// /// This trait method can, among other things, be used by an application to: /// - Configure a service work directory. /// - Add environment variables. /// - Add command like arguments to the run command. /// /// The `sub_m` argument represents `clap`'s parsed subcommand context for /// the service registration subcommand. Applications that want to add /// custom arguments to the parser should implement the /// [`ArgsProc::conf_cmd()`] trait method and perform the subcommand /// augmentation there. /// /// The default implementation does nothing but return `regsvc` unmodified. #[allow(unused_variables)] fn proc_inst( &mut self, sub_m: &ArgMatches, regsvc: RegSvc ) -> Result<RegSvc, AppErr> { Ok(regsvc) } #[allow(unused_variables)] fn proc_rm( &mut self, sub_m: &ArgMatches, deregsvc: DeregSvc ) -> Result<DeregSvc, AppErr> { Ok(deregsvc) } /// Callback allowing application to configure the run context before /// launching the server application. /// /// qsu will have performed all its own initialization of the [`RunCtx`] /// before calling this function. /// /// The application can differentiate between running in a service mode and /// running as a foreground by calling [`RunCtx::is_service()`]. #[allow(unused_variables)] fn proc_run( &mut self, matches: &ArgMatches, runctx: RunCtx ) -> Result<RunCtx, AppErr> { Ok(runctx) } /// Called when a subcommand is encountered that is not one of the three /// subcommands regognized by qsu. #[allow(unused_variables)] fn proc_other( &mut self, subcmd: &str, sub_m: &ArgMatches ) -> Result<(), AppErr> { Ok(()) } /// Construct an server application runtime. fn build_apprt(&mut self) -> Result<SrvAppRt, AppErr>; } /// High-level argument parser. /// /// This is suitable for applications that follow a specific pattern: /// - It has subcommands for: |
︙ | ︙ | |||
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 | dereg_subcmd: String, run_subcmd: String, cli: Command, cb: &'cb mut dyn ArgsProc } impl<'cb> ArgParser<'cb> { pub fn new(svcname: &str, cb: &'cb mut dyn ArgsProc) -> Self { let cli = Command::new(""); Self { svcname: svcname.to_string(), reg_subcmd: "register-service".into(), dereg_subcmd: "deregister-service".into(), run_subcmd: "run-service".into(), cli, cb } } pub fn with_cmd( svcname: &str, cli: Command, cb: &'cb mut dyn ArgsProc ) -> Self { Self { svcname: svcname.to_string(), reg_subcmd: "register-service".into(), dereg_subcmd: "deregister-service".into(), run_subcmd: "run-service".into(), cli, cb } } pub fn reg_subcmd(mut self, nm: &str) -> Self { self.reg_subcmd = nm.to_string(); self } pub fn dereg_subcmd(mut self, nm: &str) -> Self { self.dereg_subcmd = nm.to_string(); self } pub fn run_subcmd(mut self, nm: &str) -> Self { self.run_subcmd = nm.to_string(); self } | > > > > > > > > > > > > > | | 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 | dereg_subcmd: String, run_subcmd: String, cli: Command, cb: &'cb mut dyn ArgsProc } impl<'cb> ArgParser<'cb> { /// Create a new argument parser. /// /// `svcname` is the _default_ service name. It may be overridden using /// command line arguments. pub fn new(svcname: &str, cb: &'cb mut dyn ArgsProc) -> Self { let cli = Command::new(""); Self { svcname: svcname.to_string(), reg_subcmd: "register-service".into(), dereg_subcmd: "deregister-service".into(), run_subcmd: "run-service".into(), cli, cb } } /// Create a new argument parser, basing the root command parser on an /// application-supplied `Command`. /// /// `svcname` is the _default_ service name. It may be overridden using /// command line arguments. pub fn with_cmd( svcname: &str, cli: Command, cb: &'cb mut dyn ArgsProc ) -> Self { Self { svcname: svcname.to_string(), reg_subcmd: "register-service".into(), dereg_subcmd: "deregister-service".into(), run_subcmd: "run-service".into(), cli, cb } } /// Rename the service registration subcommand. pub fn reg_subcmd(mut self, nm: &str) -> Self { self.reg_subcmd = nm.to_string(); self } /// Rename the service deregistration subcommand. pub fn dereg_subcmd(mut self, nm: &str) -> Self { self.dereg_subcmd = nm.to_string(); self } /// Rename the subcommand for running the service. pub fn run_subcmd(mut self, nm: &str) -> Self { self.run_subcmd = nm.to_string(); self } fn inner_proc(self) -> Result<ArgpRes<'cb>, Error> { let matches = match self.cli.try_get_matches() { Ok(m) => m, Err(e) => match e.kind() { clap::error::ErrorKind::DisplayHelp => { e.exit(); //return Ok(ArgpRes::Quit); } |
︙ | ︙ | |||
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 | Ok(ArgpRes::Quit) } Some((subcmd, sub_m)) if subcmd == self.dereg_subcmd => { // Get arguments relating to service deregistration. let args = DeregSvc::from_cmd_match(sub_m); installer::uninstall(&args.svcname)?; Ok(ArgpRes::Quit) } Some((subcmd, sub_m)) if subcmd == self.run_subcmd => { // Get arguments relating to running the service. let args = RunSvc::from_cmd_match(sub_m); // Return a run context for a background service process. | > > > > > > > | > > > > > | | 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 | Ok(ArgpRes::Quit) } Some((subcmd, sub_m)) if subcmd == self.dereg_subcmd => { // Get arguments relating to service deregistration. let args = DeregSvc::from_cmd_match(sub_m); let args = self.cb.proc_rm(sub_m, args)?; installer::uninstall(&args.svcname)?; Ok(ArgpRes::Quit) } Some((subcmd, sub_m)) if subcmd == self.run_subcmd => { // Get arguments relating to running the service. let args = RunSvc::from_cmd_match(sub_m); // Create a RunCtx, mark it as a service, and allow application the // opportunity to modify it based on the parsed command line. let rctx = RunCtx::new(&args.svcname).service(); let rctx = self.cb.proc_run(sub_m, rctx)?; // Return a run context for a background service process. Ok(ArgpRes::RunApp(rctx, self.cb)) } Some((subcmd, sub_m)) => { // Call application callback for processing "other" subcmd self.cb.proc_other(subcmd, sub_m)?; // Return a run context for a background service process. Ok(ArgpRes::Quit) } _ => { // Create a RunCtx, mark it as a service, and allow application the // opportunity to modify it based on the parsed command line. let rctx = RunCtx::new(&self.svcname); let rctx = self.cb.proc_run(&matches, rctx)?; // Return a run context for a foreground process. Ok(ArgpRes::RunApp(rctx, self.cb)) } } } /// Process command line arguments. /// /// Calling this method will initialize the command line parser, parse the |
︙ | ︙ | |||
410 411 412 413 414 415 416 | /// - If an application-defined subcommand was called, then process it using /// [`ArgsProc::proc_other()`] and then exit. /// - If none of the above subcommands where issued, then run the server /// application as a foreground process. /// /// The `bldr` is a closure that will be called to yield the `SrvAppRt` in /// case the service was requested to run. | > > > > > > > > > > > | < < > > | | > > > > | | > > > | 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 | /// - If an application-defined subcommand was called, then process it using /// [`ArgsProc::proc_other()`] and then exit. /// - If none of the above subcommands where issued, then run the server /// application as a foreground process. /// /// The `bldr` is a closure that will be called to yield the `SrvAppRt` in /// case the service was requested to run. /// /// # Service registration behavior /// The default service registration behavior in qsu will: /// - Assume that the executable being used to register the service is the /// same one that will run the service. /// - Add the "run service" subcommand to the service's command line /// arguments. /// - If the specified service name is different than the default service /// name (determined by /// [`default_service_name()`](crate::default_service_name), then the /// aguments `--name <service name>` will be added. pub fn proc(mut self) -> Result<(), Error> { // Give application the opportunity to modify root Command self.cli = self.cb.conf_cmd(Cmd::Root, self.cli)?; // Create registration subcommand and give application the opportunity to // modify the subcommand's Command let sub = mk_inst_cmd(&self.reg_subcmd, &self.svcname); let sub = self.cb.conf_cmd(Cmd::Inst, sub)?; self.cli = self.cli.subcommand(sub); // Create deregistration subcommand let sub = mk_rm_cmd(&self.dereg_subcmd, &self.svcname); let sub = self.cb.conf_cmd(Cmd::Rm, sub)?; self.cli = self.cli.subcommand(sub); // Create run subcommand let sub = mk_run_cmd(&self.run_subcmd, &self.svcname); let sub = self.cb.conf_cmd(Cmd::Run, sub)?; self.cli = self.cli.subcommand(sub); // Parse command line arguments. Run the service application if requiested // to do so. if let ArgpRes::RunApp(runctx, cb) = self.inner_proc()? { // Argument parser asked us to run, so call the application to ask it to // create the service handler, and then kick off the service runtime. //let st = bldr(ctx)?; let st = cb.build_apprt()?; runctx.run(st)?; } Ok(()) } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/err.rs.
︙ | ︙ | |||
24 25 26 27 28 29 30 | pub fn run_failed(&self) -> bool { self.run.is_some() } pub fn shutdown_failed(&self) -> bool { self.shutdown.is_some() } | < < < < < < < < < < < < < | | 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | pub fn run_failed(&self) -> bool { self.run.is_some() } pub fn shutdown_failed(&self) -> bool { self.shutdown.is_some() } } /// Errors that qsu will return to application. #[derive(Debug)] pub enum Error { /// Application-defined error. /// /// Applications can use this variant to pass application-specific errors /// through the runtime back to itself. App(AppErr), ArgP(ArgsError), BadFormat(String), Internal(String), IO(String), /// An error related to logging occurred. |
︙ | ︙ | |||
83 84 85 86 87 88 89 | Unsupported } impl Error { pub fn is_apperr(&self) -> bool { | | | | | | | | < < | < < < < | 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | Unsupported } impl Error { pub fn is_apperr(&self) -> bool { matches!(self, Error::App(_)) } /// Attempt to convert [`Error`] into application-specific error. /// /// If it's not an `Error::App()` nor can be downcast to type `E`, the error /// will be returned back as an `Err()`. pub fn try_into_apperr<E: 'static>(self) -> Result<E, Error> { match self { Error::App(e) => match e.try_into_inner::<E>() { Ok(e) => Ok(e), Err(e) => Err(Error::App(AppErr::new(e))) }, e => Err(e) } } /// Unwrap application-specific error from an [`Error`]. /// /// # Panic /// Panics if `Error` variant is not `Error::App()`. pub fn unwrap_apperr<E: 'static>(self) -> E { let Ok(e) = self.try_into_apperr::<E>() else { panic!("Unable to unwrap error E"); }; e } pub fn bad_format<S: ToString>(s: S) -> Self { Error::BadFormat(s.to_string()) } pub fn internal<S: ToString>(s: S) -> Self { Error::Internal(s.to_string()) |
︙ | ︙ | |||
143 144 145 146 147 148 149 | } impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { | | | 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | } impl std::error::Error for Error {} impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Error::App(_e) => { write!(f, "Application-defined error") } Error::ArgP(s) => { // ToDo: Handle the ArgsError::Clap and ArgsError::Msg differently write!(f, "Argument parser; {:?}", s) } Error::BadFormat(s) => { |
︙ | ︙ | |||
269 270 271 272 273 274 275 276 277 278 279 280 281 282 | impl AppErr { pub fn new<E>(e: E) -> Self where E: Send + 'static { Self(Box::new(e)) } /// Attempt to unpack and cast the inner error type. /// /// If it can't be downcast to `E`, `AppErr` will be returned in the `Err()` /// case. /// /// ``` | > > > > > > > > | 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 | impl AppErr { pub fn new<E>(e: E) -> Self where E: Send + 'static { Self(Box::new(e)) } /// Inspect error type wrapped by the `AppErr`. pub fn is<T>(&self) -> bool where T: Any { self.0.is::<T>() } /// Attempt to unpack and cast the inner error type. /// /// If it can't be downcast to `E`, `AppErr` will be returned in the `Err()` /// case. /// /// ``` |
︙ | ︙ | |||
320 321 322 323 324 325 326 | let Ok(e) = self.0.downcast::<E>() else { panic!("Unable to downcast to error type E"); }; *e } } | | < < < | < | | < < | < < < | 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 | let Ok(e) = self.0.downcast::<E>() else { panic!("Unable to downcast to error type E"); }; *e } } impl From<AppErr> for Error { /// Wrap an [`AppErr`] in an [`Error`]. fn from(err: AppErr) -> Self { Error::App(err) } } // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : |
Changes to src/installer/winsvc.rs.
︙ | ︙ | |||
12 13 14 15 16 17 18 19 20 21 22 23 24 25 | err::Error, rt::winsvc::{ create_service_params, get_service_params_subkey, write_service_subkey } }; pub fn install(ctx: super::RegSvc) -> Result<(), Error> { let svcname = &ctx.svcname; // Create a refrence cell used to keep track of whether to keep system // motifications (or not) when leaving function. let status = RefCell::new(false); | > > > > > | 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | err::Error, rt::winsvc::{ create_service_params, get_service_params_subkey, write_service_subkey } }; /// Register a service in the system service's subsystem. // ToDo: Make notes about Windows-specific semantics: // - Uses registry // - Installer // - Windows Event Log pub fn install(ctx: super::RegSvc) -> Result<(), Error> { let svcname = &ctx.svcname; // Create a refrence cell used to keep track of whether to keep system // motifications (or not) when leaving function. let status = RefCell::new(false); |
︙ | ︙ |
Changes to src/lib.rs.
︙ | ︙ | |||
52 53 54 55 56 57 58 | use std::{ffi::OsStr, path::Path}; pub use async_trait::async_trait; pub use lumberjack::LumberJack; | | | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | use std::{ffi::OsStr, path::Path}; pub use async_trait::async_trait; pub use lumberjack::LumberJack; pub use err::{AppErr, Error}; #[cfg(feature = "tokio")] pub use tokio; #[cfg(feature = "rocket")] pub use rocket; |
︙ | ︙ |
Changes to src/rt.rs.
︙ | ︙ | |||
475 476 477 478 479 480 481 482 483 484 485 486 487 488 | /// Mark this run context to run under the operating system's subservice, if /// one is available on this platform. pub fn service_ref(&mut self) -> &mut Self { self.service = true; self } /// Launch the application. /// /// If this `RunCtx` has been marked as a _service_ then it will perform the /// appropriate service subsystem integration before running the actual /// server application code. /// | > > > > | 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | /// Mark this run context to run under the operating system's subservice, if /// one is available on this platform. pub fn service_ref(&mut self) -> &mut Self { self.service = true; self } pub fn is_service(&self) -> bool { self.service } /// Launch the application. /// /// If this `RunCtx` has been marked as a _service_ then it will perform the /// appropriate service subsystem integration before running the actual /// server application code. /// |
︙ | ︙ |
Changes to www/changelog.md.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # Change log ## [Unreleased] ### Added ### Changed ### Removed --- ## [0.0.3] - 2023-10-23 ### Added - Introduce an `AppErr` type that can wrap application-specific errors that | > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | # Change log ## [Unreleased] ### Added ### Changed ### Removed --- ## [0.0.4] - 2023-10-29 ### Added - Add the remaining `ArgsProc` callbacks in `ArgParser`. ### Changed - Rather than pass a creation closure to the `ArgParser::proc()` for the run case, add a `ArgsProc::build_apprt()` that'll be invoked to create the runtime instead. - More consistently use `AppErr` for callbacks. ### Removed - Removed `err::CbOrigin`. --- ## [0.0.3] - 2023-10-23 ### Added - Introduce an `AppErr` type that can wrap application-specific errors that |
︙ | ︙ |
Changes to www/index.md.
︙ | ︙ | |||
86 87 88 89 90 91 92 93 94 95 96 97 98 99 | _qsu_ is negligible (or it might even be wasteful to pull in _qsu_). The benefits of using _qsu_ will be noticed mostly when targeting the Windows Services subsystem. But mostly the benefits become apparent when targetting multiple service subsystems in the same project, and wanting to have a similar API when developing non-async and async services. ## Feature labels in documentation The crate's documentation uses automatically generated feature labels, which currently requires nightly featuers. To build the documentation locally use: ``` RUSTFLAGS="--cfg docsrs" RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features | > > > > > > > > | 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 | _qsu_ is negligible (or it might even be wasteful to pull in _qsu_). The benefits of using _qsu_ will be noticed mostly when targeting the Windows Services subsystem. But mostly the benefits become apparent when targetting multiple service subsystems in the same project, and wanting to have a similar API when developing non-async and async services. ## General tips - The logging/tracing facilities aren't initialized until the server application's runtime has been initialized, because the runtime type may affect the logging/tracing backends. As an implication of this, services that use the `ArgParser` should defer operations that need logging/tracking until the service handler's `init()` trait method is called. ## Feature labels in documentation The crate's documentation uses automatically generated feature labels, which currently requires nightly featuers. To build the documentation locally use: ``` RUSTFLAGS="--cfg docsrs" RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features |
︙ | ︙ | |||
126 127 128 129 130 131 132 | The details of changes can always be found in the timeline, but for a high-level view of changes between released versions there's a manually maintained [Change Log](./changelog.md). ## Project status | | | > | > > | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | The details of changes can always be found in the timeline, but for a high-level view of changes between released versions there's a manually maintained [Change Log](./changelog.md). ## Project status This crate is a work-in-progress -- still in early prototyping stage. This means potentially significant API instability between versions and incomplete, or even incorrect, documentation. It is recommended that projects wanting to use _qsu_ at this point use the tests and examples for up-to-date information on how to use the crate. |