tuwunel_service/admin/
execute.rs1use ruma::events::room::message::RoomMessageEventContent;
2use tokio::task::yield_now;
3use tuwunel_core::{Err, Result, debug, debug_info, error, implement, info};
4
5pub(super) const SIGNAL: &str = "SIGUSR2";
6
7#[implement(super::Service)]
9#[cfg_attr(not(feature = "console"), expect(clippy::unused_async))]
10pub(super) async fn console_auto_start(&self) {
11 #[cfg(feature = "console")]
12 if self
13 .services
14 .server
15 .config
16 .admin_console_automatic
17 {
18 yield_now().await;
20 self.console.start();
21 }
22}
23
24#[implement(super::Service)]
26#[cfg_attr(not(feature = "console"), expect(clippy::unused_async))]
27pub(super) async fn console_auto_stop(&self) {
28 #[cfg(feature = "console")]
29 self.console.close().await;
30}
31
32#[implement(super::Service)]
34pub async fn startup_execute(&self) -> Result {
35 let commands = &self.services.server.config.admin_execute;
37
38 let smoketest = self.services.server.config.test.contains("smoke");
40
41 let errors = !smoketest
43 && self
44 .services
45 .server
46 .config
47 .admin_execute_errors_ignore;
48
49 for (i, command) in commands.iter().enumerate() {
50 if let Err(e) = self.execute_command(i, command.clone()).await
51 && !errors
52 {
53 return Err(e);
54 }
55
56 yield_now().await;
57 }
58
59 if smoketest {
62 debug_info!("Smoketest mode. All commands complete. Shutting down now...");
63 self.services
64 .server
65 .shutdown()
66 .inspect_err(error::inspect_log)
67 .expect("Error shutting down from smoketest");
68 }
69
70 Ok(())
71}
72
73#[implement(super::Service)]
75pub(super) async fn signal_execute(&self) -> Result {
76 let commands = self
78 .services
79 .server
80 .config
81 .admin_signal_execute
82 .clone();
83
84 let ignore_errors = self
86 .services
87 .server
88 .config
89 .admin_execute_errors_ignore;
90
91 for (i, command) in commands.iter().enumerate() {
92 if let Err(e) = self.execute_command(i, command.clone()).await
93 && !ignore_errors
94 {
95 return Err(e);
96 }
97
98 yield_now().await;
99 }
100
101 Ok(())
102}
103
104#[implement(super::Service)]
106async fn execute_command(&self, i: usize, command: String) -> Result {
107 debug!("Execute command #{i}: executing {command:?}");
108
109 match self.command_in_place(command, None).await {
110 | Ok(Some(output)) => Self::execute_command_output(i, &output),
111 | Err(output) => Self::execute_command_error(i, &output),
112 | Ok(None) => {
113 info!("Execute command #{i} completed (no output).");
114 Ok(())
115 },
116 }
117}
118
119#[cfg(feature = "console")]
120#[implement(super::Service)]
121fn execute_command_output(i: usize, content: &RoomMessageEventContent) -> Result {
122 debug_info!("Execute command #{i} completed:");
123 super::console::print(content.body());
124 Ok(())
125}
126
127#[cfg(feature = "console")]
128#[implement(super::Service)]
129fn execute_command_error(i: usize, content: &RoomMessageEventContent) -> Result {
130 super::console::print_err(content.body());
131 Err!(debug_error!("Execute command #{i} failed."))
132}
133
134#[cfg(not(feature = "console"))]
135#[implement(super::Service)]
136fn execute_command_output(i: usize, content: &RoomMessageEventContent) -> Result {
137 info!("Execute command #{i} completed:\n{:#}", content.body());
138 Ok(())
139}
140
141#[cfg(not(feature = "console"))]
142#[implement(super::Service)]
143fn execute_command_error(i: usize, content: &RoomMessageEventContent) -> Result {
144 Err!(error!("Execute command #{i} failed:\n{:#}", content.body()))
145}