reap the exit statuses from 'onevent' child processes

This commit is contained in:
William R. Fraser 2018-10-16 00:24:33 -07:00
parent a4e0f582a8
commit eaac599ce3
3 changed files with 39 additions and 6 deletions

21
src/child_wait_future.rs Normal file
View file

@ -0,0 +1,21 @@
use futures::{Async, Future};
use std::io;
use std::process::{Child, ExitStatus};
/// A future that resolves to a child process's exit status once it exits.
pub struct ChildWaitFuture {
pub child: Child,
}
impl Future for ChildWaitFuture {
type Item = ExitStatus;
type Error = io::Error;
fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
match self.child.try_wait() {
Ok(Some(status)) => Ok(Async::Ready(status)),
Ok(None) => Ok(Async::NotReady),
Err(e) => Err(e),
}
}
}

View file

@ -39,6 +39,9 @@ use librespot::playback::config::{Bitrate, PlayerConfig};
use librespot::playback::mixer::{self, Mixer}; use librespot::playback::mixer::{self, Mixer};
use librespot::playback::player::{Player, PlayerEvent}; use librespot::playback::player::{Player, PlayerEvent};
mod child_wait_future;
use child_wait_future::ChildWaitFuture;
mod player_event_handler; mod player_event_handler;
use player_event_handler::run_program_on_events; use player_event_handler::run_program_on_events;
@ -466,7 +469,16 @@ impl Future for Main {
if let Some(ref mut player_event_channel) = self.player_event_channel { if let Some(ref mut player_event_channel) = self.player_event_channel {
if let Async::Ready(Some(event)) = player_event_channel.poll().unwrap() { if let Async::Ready(Some(event)) = player_event_channel.poll().unwrap() {
if let Some(ref program) = self.player_event_program { if let Some(ref program) = self.player_event_program {
run_program_on_events(event, program); let child = run_program_on_events(event, program)
.expect("program failed to start");
let wait_future = ChildWaitFuture { child }
.map(|status| if !status.success() {
error!("child exited with status {:?}", status.code());
})
.map_err(|e| error!("failed to wait on child process: {}", e));
self.handle.spawn(wait_future);
} }
} }
} }

View file

@ -1,18 +1,18 @@
use librespot::playback::player::PlayerEvent; use librespot::playback::player::PlayerEvent;
use std::collections::HashMap; use std::collections::HashMap;
use std::process::Command; use std::io;
use std::process::{Child, Command};
fn run_program(program: &str, env_vars: HashMap<&str, String>) { fn run_program(program: &str, env_vars: HashMap<&str, String>) -> io::Result<Child> {
let mut v: Vec<&str> = program.split_whitespace().collect(); let mut v: Vec<&str> = program.split_whitespace().collect();
info!("Running {:?} with environment variables {:?}", v, env_vars); info!("Running {:?} with environment variables {:?}", v, env_vars);
Command::new(&v.remove(0)) Command::new(&v.remove(0))
.args(&v) .args(&v)
.envs(env_vars.iter()) .envs(env_vars.iter())
.spawn() .spawn()
.expect("program failed to start");
} }
pub fn run_program_on_events(event: PlayerEvent, onevent: &str) { pub fn run_program_on_events(event: PlayerEvent, onevent: &str) -> io::Result<Child> {
let mut env_vars = HashMap::new(); let mut env_vars = HashMap::new();
match event { match event {
PlayerEvent::Changed { PlayerEvent::Changed {
@ -32,5 +32,5 @@ pub fn run_program_on_events(event: PlayerEvent, onevent: &str) {
env_vars.insert("TRACK_ID", track_id.to_base16()); env_vars.insert("TRACK_ID", track_id.to_base16());
} }
} }
run_program(onevent, env_vars); run_program(onevent, env_vars)
} }