PageRenderTime 23ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/Core/comms/src/server_process/server.rs

https://gitlab.com/Artefaritaj/Sparkbench
Rust | 251 lines | 160 code | 43 blank | 48 comment | 20 complexity | 54ff156f0784969d8a70f9a2a75ccea5 MD5 | raw file
  1. // @Author: Lashermes Ronan <ronan>
  2. // @Date: 24-03-2017
  3. // @Email: ronan.lashermes@inria.fr
  4. // @Last modified by: ronan
  5. // @Last modified time: 24-03-2017
  6. // @License: MIT
  7. use hconfig::store::{StoreNode, StoreKey, Data, DataType, CompoundDataType};
  8. use config_keys::*;
  9. use std::process::Command;
  10. use std::sync::mpsc::*;
  11. use std::thread;
  12. use std::time::Duration;
  13. use std::process::Stdio;
  14. use std::io::Read;
  15. // use std::str::FromStr;
  16. // use dimval::{DimVal};
  17. use failure::Error;
  18. pub enum ServerMessage {
  19. Kill
  20. }
  21. pub fn pop_server(name: &str, conn_config: &StoreNode) -> Result<Sender<ServerMessage>, Error> {
  22. let config = try!(conn_config.get_node(&StoreKey::from(name)) .map_err(|e|format_err!("{}", e)));
  23. let pre_commands = extract_string_array(config, PRE_COMMANDS);
  24. execute_commands(&pre_commands);
  25. let args = extract_string_array(config, ARGS);
  26. let launch = try!(extract_string(config, LAUNCH_COMMAND));
  27. let wait_dimval = config.get_value(&StoreKey::from(WAIT))
  28. .and_then(|d|d.convert( &CompoundDataType::Singleton(DataType::Dim(0, format!("s"))) ))
  29. .unwrap_or(Data::create_dim_str("3s")?)
  30. .to_atomic_data()?
  31. .to_dim()?;
  32. let wait = wait_dimval.to_i64_prefix(-3)? as u64;//get wait time as milliseconds
  33. // let wait = extract_i64(config, WAIT) as u64;
  34. let end_commands = extract_string_array(config, END_COMMANDS);
  35. let res = launch_server(launch, args, wait, end_commands);
  36. let post_commands = extract_string_array(config, POST_COMMANDS);
  37. execute_commands(&post_commands);
  38. Ok(res)
  39. }
  40. /// Launch a server, i.e. a shell process that can be kept alive for the whole duration
  41. fn launch_server(prog: String, args: Vec<String>, wait: u64, end_commands: Vec<String>) -> Sender<ServerMessage> {
  42. let (tx,rx): (Sender<ServerMessage>, Receiver<ServerMessage>) = channel();
  43. info!("Launching server '{}' with args '{:?}'", prog, args);
  44. thread::spawn(move|| {
  45. let mut quit = false;
  46. //split on " " to separate process from args
  47. let cmd_words: Vec<_> = prog.split(" ").collect();
  48. if cmd_words.len() > 0 {
  49. //first word is process
  50. let mut server_cmd = Command::new(cmd_words[0]);
  51. //add other words as args
  52. for i in 1..cmd_words.len() {
  53. server_cmd.arg(cmd_words[i]);
  54. }
  55. //args can also be filled with the dedicated argument
  56. for a in args.iter() {
  57. let words = a.split(" ");
  58. for w in words {
  59. server_cmd.arg(w);
  60. }
  61. }
  62. let mut handle = server_cmd .stdin(Stdio::null())
  63. .stdout(Stdio::piped())
  64. .stderr(Stdio::piped())
  65. .spawn();
  66. if handle.is_err() {
  67. warn!("Failed to start server: {:?}", server_cmd);
  68. quit = true;
  69. }
  70. //while alive
  71. while !quit {
  72. // read stdout and stderr
  73. if let Ok(ref mut child) = handle {
  74. if let Some(ref mut stdo) = child.stdout {
  75. let mut stdo_str = String::new();
  76. while let Ok(_) = stdo.read_to_string(&mut stdo_str) {
  77. if stdo_str != "" {
  78. trace!("{}: STDOUT, {}", prog, stdo_str);
  79. }
  80. }
  81. }
  82. if let Some(ref mut stdo) = child.stderr {
  83. let mut stdo_str = String::new();
  84. while let Ok(_) = stdo.read_to_string(&mut stdo_str) {
  85. if stdo_str != "" {
  86. warn!("{}: STDERR, {}", prog, stdo_str);
  87. }
  88. }
  89. }
  90. }
  91. //watch for a kill messages
  92. match rx.try_recv() {
  93. Ok(message) => {
  94. match message {
  95. ServerMessage::Kill => {
  96. quit = true;
  97. }
  98. }
  99. },
  100. Err(_) => {
  101. // thread::sleep(Duration::from_millis(200));
  102. // warn!("Unexpected error in server ({:?}) thread: {}", server_cmd, e);
  103. // quit = true;
  104. }
  105. }
  106. }
  107. //kill order has been received, out of the event loop
  108. match handle {
  109. Ok(ref mut child) => {
  110. // let child_id = child.id();
  111. let res = child.kill();
  112. info!("Server killed: {:?} (={:?}).", server_cmd, res);
  113. // unsafe {
  114. // kill(child_id as i32, SIGTERM);
  115. // }
  116. }
  117. _ => {}
  118. }
  119. //exeuce after-kill commands
  120. execute_commands(&end_commands);
  121. }
  122. });
  123. thread::sleep(Duration::from_millis(wait));
  124. tx
  125. }
  126. /// Execute a list of shell commands (1 String = 1 shell command)
  127. fn execute_commands(cmds: &Vec<String>) {
  128. for cmd in cmds.iter() {
  129. let cmd_words: Vec<_> = cmd.split(" ").collect();
  130. if cmd_words.len() > 0 {
  131. let mut cmd_to_call = Command::new(cmd_words[0]);
  132. for i in 1..cmd_words.len() {
  133. cmd_to_call.arg(cmd_words[i]);
  134. }
  135. match cmd_to_call.output() {
  136. Ok(_) => info!("Command '{}' successfully executed", cmd),
  137. Err(e) => info!("Command '{}' failed to execute with error: {}", cmd, e.to_string())
  138. }
  139. }
  140. }
  141. }
  142. fn extract_string(config: &StoreNode, key: &str) -> Result<String, Error> {
  143. config.get_value(&StoreKey::from(key))?.to_string_result()
  144. // match config.get_value(&StoreKey::from(key)) {
  145. // Ok(Data::String(s)) => Ok(s),
  146. // Ok(d) => {return Err(format_err!("{} does not contain a string ({:?})", key, d));},
  147. // Err(e) => Err(e.into())
  148. // }
  149. }
  150. //default is 3000
  151. // fn extract_i64(config: &StoreNode, key: &str) -> i64 {
  152. // match config.get_value(&StoreKey::from(key)) {
  153. // Ok(Data::I64(i)) => i,
  154. // Ok(Data::String(s)) => {
  155. // match s.parse::<DimVal>()
  156. // .and_then(|x|x.to_f64_prefix(Prefix::Milli)) {
  157. // Ok(f) => f as i64,
  158. // Err(_) => 3000
  159. // }
  160. // },
  161. // Ok(Data::F64(f)) => (f*1000f64) as i64,
  162. // _ => 3000
  163. // }
  164. // }
  165. fn extract_string_array(config: &StoreNode, key: &str) -> Vec<String> {
  166. let mut args: Vec<String> = Vec::new();
  167. let node = match config.get_node(&StoreKey::from(key)) {
  168. Ok(n) => n,
  169. Err(_) => {return args;}
  170. };
  171. match node.get_node_value() {
  172. &Data::Singleton(ref ad) => {
  173. match ad.to_string_result() {
  174. Ok(ref s) => args.push(s.clone()),
  175. _ => {}
  176. }
  177. },
  178. &Data::Array(ref v) => {
  179. for d in v.iter() {
  180. // trace!("New data for {}: {:?}", key, d);
  181. match d.to_string_result() {
  182. Ok(ref s) => {
  183. args.push(s.to_string());
  184. },
  185. _ => {}
  186. }
  187. }
  188. },
  189. _ => {}
  190. }
  191. for c in node.get_node_value_array() {
  192. match c.to_string_result() {
  193. Ok(ref s) => {
  194. args.push(s.clone());
  195. },
  196. _ => {}
  197. }
  198. }
  199. args
  200. }
  201. #[test]
  202. fn test_convert_milli() {
  203. use dimval::DimVal;
  204. use std::str::FromStr;
  205. let wait_dimval = DimVal::from_str("3s").unwrap();
  206. let wait = wait_dimval.to_i64_prefix(-3).unwrap() as u64;
  207. assert_eq!(wait, 3000);
  208. }