Update to actix-web 1.0 and use handlebars

This commit is contained in:
Fabian Freyer 2019-09-29 04:00:19 +02:00
parent d71b42665f
commit e74a974d51
7 changed files with 609 additions and 779 deletions

1260
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -16,10 +16,13 @@ travis-ci = { repository = "fubarnetes/webterm", branch = "master" }
maintenance = { status = "actively-developed" }
[dependencies]
actix-files = "0.1.4"
actix-service = "0.4.2"
actix-web-actors = "1.0.2"
actix-web= "1.0.8"
actix= "0.8.3"
askama = { version = "0.8.0", features= ["with-actix-web"] }
futures = "0.1.29"
handlebars = "2.0.2"
lazy_static = "1.3.0"
libc = "0.2.62"
log = "0.4.8"

View File

@ -1,5 +1,4 @@
use actix::Message;
use actix_web::Binary;
use futures::{Future, Poll};
use libc::c_ushort;
use tokio_pty_process::PtyMaster;
@ -37,8 +36,8 @@ impl Message for IO {
type Result = ();
}
impl Into<Binary> for IO {
fn into(self) -> Binary {
impl Into<actix_web::web::Bytes> for IO {
fn into(self) -> actix_web::web::Bytes {
self.0.into()
}
}
@ -49,8 +48,8 @@ impl AsRef<[u8]> for IO {
}
}
impl From<Binary> for IO {
fn from(b: Binary) -> Self {
impl From<actix_web::web::Bytes> for IO {
fn from(b: actix_web::web::Bytes) -> Self {
Self(b.as_ref().into())
}
}

View File

@ -29,10 +29,11 @@
extern crate actix;
extern crate actix_web;
extern crate askama;
extern crate futures;
extern crate handlebars;
extern crate libc;
extern crate serde;
#[macro_use]
extern crate serde_json;
extern crate tokio;
extern crate tokio_codec;
@ -41,12 +42,11 @@ extern crate tokio_pty_process;
#[macro_use]
extern crate log;
extern crate pretty_env_logger;
use askama::actix_web::TemplateIntoResponse;
use actix::*;
use actix_web::{ws, App};
use futures::prelude::*;
use actix::prelude::*;
use actix::{Actor, StreamHandler};
use actix_web::{web, App, HttpRequest, HttpResponse};
use actix_web_actors::ws;
use std::io::Write;
use std::process::Command;
@ -55,11 +55,12 @@ use std::time::{Duration, Instant};
use tokio_codec::{BytesCodec, Decoder, FramedRead};
use tokio_pty_process::{AsyncPtyMaster, AsyncPtyMasterWriteHalf, Child, CommandExt};
use handlebars::Handlebars;
const HEARTBEAT_INTERVAL: Duration = Duration::from_secs(5);
const CLIENT_TIMEOUT: Duration = Duration::from_secs(10);
mod event;
pub mod templates;
mod terminado;
/// Actix WebSocket actor
@ -175,6 +176,7 @@ impl StreamHandler<ws::Message, ws::ProtocolError> for Websocket {
}
ws::Message::Binary(b) => cons.do_send(event::IO::from(b)),
ws::Message::Close(_) => ctx.stop(),
ws::Message::Nop => {}
};
}
}
@ -341,7 +343,7 @@ pub trait WebTermExt {
/// Serve the websocket for the webterm
fn webterm_socket<F>(self: Self, endpoint: &str, handler: F) -> Self
where
F: Fn(&actix_web::Request) -> Command + 'static;
F: Clone + Fn(&actix_web::HttpRequest) -> Command + 'static;
fn webterm_ui(
self: Self,
@ -351,14 +353,27 @@ pub trait WebTermExt {
) -> Self;
}
impl WebTermExt for App<()> {
impl<T, B> WebTermExt for App<T, B>
where
B: actix_web::body::MessageBody,
T: actix_service::NewService<
Config = (),
Request = actix_web::dev::ServiceRequest,
Response = actix_web::dev::ServiceResponse<B>,
Error = actix_web::Error,
InitError = (),
>,
{
fn webterm_socket<F>(self: Self, endpoint: &str, handler: F) -> Self
where
F: Fn(&actix_web::Request) -> Command + 'static,
F: Clone + Fn(&actix_web::HttpRequest) -> Command + 'static,
{
self.resource(endpoint, move |r| {
r.f(move |req| ws::start(req, Websocket::new(handler(req))))
})
self.route(
endpoint,
web::get().to(move |req: HttpRequest, stream: web::Payload| {
ws::start(Websocket::new(handler(&req)), &req, stream)
}),
)
}
fn webterm_ui(
@ -367,9 +382,23 @@ impl WebTermExt for App<()> {
webterm_socket_endpoint: &str,
static_path: &str,
) -> Self {
let template = templates::WebTerm::new(webterm_socket_endpoint, static_path);
self.resource(endpoint, move |r| {
r.get().f(move |_| template.into_response())
})
let mut handlebars = Handlebars::new();
handlebars
.register_templates_directory(".html", "./templates")
.unwrap();
let handlebars_ref = web::Data::new(handlebars);
let static_path = static_path.to_owned();
let webterm_socket_endpoint = webterm_socket_endpoint.to_owned();
self.register_data(handlebars_ref.clone()).route(
endpoint,
web::get().to(move |hb: web::Data<Handlebars>| {
let data = json!({
"websocket_path": webterm_socket_endpoint,
"static_path": static_path,
});
let body = hb.render("term", &data).unwrap();
HttpResponse::Ok().body(body)
}),
)
}
}

View File

@ -1,11 +1,11 @@
extern crate actix;
extern crate actix_web;
extern crate webterm;
extern crate structopt;
extern crate webterm;
#[macro_use]
extern crate lazy_static;
use actix_web::{fs::StaticFiles, server, App};
use actix_web::{App, HttpServer};
use structopt::StructOpt;
use webterm::WebTermExt;
@ -31,18 +31,12 @@ lazy_static! {
static ref OPT: Opt = Opt::from_args();
}
fn main() {
pretty_env_logger::init();
server::new(|| {
HttpServer::new(|| {
App::new()
.handler(
"/static",
StaticFiles::new("node_modules")
.unwrap()
.show_files_listing(),
)
.service(actix_files::Files::new("/static", "./node_modules"))
.webterm_socket("/websocket", |_req| {
let mut cmd = Command::new(OPT.command.clone());
cmd.env("TERM", "xterm");
@ -52,5 +46,6 @@ fn main() {
})
.bind(format!("{}:{}", OPT.host, OPT.port))
.unwrap()
.run();
.run()
.unwrap();
}

View File

@ -1,20 +0,0 @@
use askama::Template;
#[derive(Template)]
#[template(path = "term.html")]
pub struct WebTerm {
websocket_path: String,
static_path: String,
}
impl WebTerm {
pub fn new<S>(websocket_path: S, static_path: S) -> Self
where
S: Into<String>,
{
Self {
websocket_path: websocket_path.into(),
static_path: static_path.into(),
}
}
}

View File

@ -7,12 +7,12 @@ SPDX-License-Identifier: BSD-3-Clause
<html>
<head>
<meta charset="UTF-8" />
<link rel="stylesheet" href="{{ static_path|safe }}/xterm/dist/xterm.css" />
<script src="{{ static_path|safe }}/xterm/dist/xterm.js"></script>
<script src="{{ static_path|safe }}/xterm/dist/addons/attach/attach.js"></script>
<script src="{{ static_path|safe }}/xterm/dist/addons/terminado/terminado.js"></script>
<script src="{{ static_path|safe }}/xterm/dist/addons/fit/fit.js"></script>
<script src="{{ static_path|safe }}/xterm/dist/addons/search/search.js"></script>
<link rel="stylesheet" href="{{ static_path }}/xterm/dist/xterm.css" />
<script src="{{ static_path }}/xterm/dist/xterm.js"></script>
<script src="{{ static_path }}/xterm/dist/addons/attach/attach.js"></script>
<script src="{{ static_path }}/xterm/dist/addons/terminado/terminado.js"></script>
<script src="{{ static_path }}/xterm/dist/addons/fit/fit.js"></script>
<script src="{{ static_path }}/xterm/dist/addons/search/search.js"></script>
<style>
body {
margin: 0;
@ -32,7 +32,7 @@ SPDX-License-Identifier: BSD-3-Clause
var term = new Terminal();
var protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
var socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + "{{ websocket_path|safe }}";
var socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + "{{ websocket_path }}";
var sock = new WebSocket(socketURL);
sock.addEventListener('open', function() {