Make command configurable per-request

This commit is contained in:
Fabian Freyer 2019-03-29 11:32:35 -04:00
parent c9c85aacab
commit 093e87fad9
2 changed files with 30 additions and 8 deletions

View File

@ -63,6 +63,7 @@ mod terminado;
pub struct Websocket { pub struct Websocket {
cons: Option<Addr<Terminal>>, cons: Option<Addr<Terminal>>,
hb: Instant, hb: Instant,
command: Option<Command>,
} }
impl Actor for Websocket { impl Actor for Websocket {
@ -72,8 +73,13 @@ impl Actor for Websocket {
// Start heartbeat // Start heartbeat
self.hb(ctx); self.hb(ctx);
let command = self
.command
.take()
.expect("command was None at start of WebSocket.");
// Start PTY // Start PTY
self.cons = Some(Terminal::new(ctx.address()).start()); self.cons = Some(Terminal::new(ctx.address(), command).start());
trace!("Started WebSocket"); trace!("Started WebSocket");
} }
@ -117,10 +123,11 @@ impl Handler<event::TerminadoMessage> for Websocket {
} }
impl Websocket { impl Websocket {
pub fn new() -> Self { pub fn new(command: Command) -> Self {
Self { Self {
hb: Instant::now(), hb: Instant::now(),
cons: None, cons: None,
command: Some(command),
} }
} }
@ -184,14 +191,16 @@ pub struct Terminal {
pty_write: Option<AsyncPtyMasterWriteHalf>, pty_write: Option<AsyncPtyMasterWriteHalf>,
child: Option<Child>, child: Option<Child>,
ws: Addr<Websocket>, ws: Addr<Websocket>,
command: Command,
} }
impl Terminal { impl Terminal {
pub fn new(ws: Addr<Websocket>) -> Self { pub fn new(ws: Addr<Websocket>, command: Command) -> Self {
Self { Self {
pty_write: None, pty_write: None,
child: None, child: None,
ws, ws,
command,
} }
} }
} }
@ -217,7 +226,7 @@ impl Actor for Terminal {
Ok(pty) => pty, Ok(pty) => pty,
}; };
let child = match Command::new("/bin/sh").spawn_pty_async(&pty) { let child = match self.command.spawn_pty_async(&pty) {
Err(e) => { Err(e) => {
error!("Unable to spawn child: {:?}", e); error!("Unable to spawn child: {:?}", e);
ctx.stop(); ctx.stop();
@ -327,11 +336,18 @@ impl Handler<event::TerminadoMessage> for Terminal {
/// Trait to extend an [actix_web::App] by serving a web terminal. /// Trait to extend an [actix_web::App] by serving a web terminal.
pub trait WebTermExt { pub trait WebTermExt {
/// Serve the websocket for the webterm /// Serve the websocket for the webterm
fn webterm_socket(self: Self, endpoint: &str) -> Self; fn webterm_socket<F>(self: Self, endpoint: &str, handler: F) -> Self
where
F: Fn(&actix_web::Request) -> Command + 'static;
} }
impl WebTermExt for App<()> { impl WebTermExt for App<()> {
fn webterm_socket(self: Self, endpoint: &str) -> Self { fn webterm_socket<F>(self: Self, endpoint: &str, handler: F) -> Self
self.resource(endpoint, |r| r.f(|req| ws::start(req, Websocket::new()))) where
F: Fn(&actix_web::Request) -> Command + 'static,
{
self.resource(endpoint, move |r| {
r.f(move |req| ws::start(req, Websocket::new(handler(req))))
})
} }
} }

View File

@ -5,6 +5,8 @@ extern crate webterm;
use actix_web::{fs::NamedFile, fs::StaticFiles, server, App, HttpRequest, Result}; use actix_web::{fs::NamedFile, fs::StaticFiles, server, App, HttpRequest, Result};
use webterm::WebTermExt; use webterm::WebTermExt;
use std::process::Command;
fn index(_req: &HttpRequest) -> Result<NamedFile> { fn index(_req: &HttpRequest) -> Result<NamedFile> {
Ok(NamedFile::open("static/term.html")?) Ok(NamedFile::open("static/term.html")?)
} }
@ -20,7 +22,11 @@ fn main() {
.unwrap() .unwrap()
.show_files_listing(), .show_files_listing(),
) )
.webterm_socket("/websocket") .webterm_socket("/websocket", |_req| {
let mut cmd = Command::new("/bin/sh");
cmd.env("TERM", "xterm");
cmd
})
.resource("/", |r| r.f(index)) .resource("/", |r| r.f(index))
}) })
.bind("127.0.0.1:8080") .bind("127.0.0.1:8080")