webmetro/src/commands/relay.rs

140 lines
3.6 KiB
Rust
Raw Normal View History

2018-04-11 19:45:02 -04:00
use std::error::Error;
use std::net::ToSocketAddrs;
use std::sync::{
Arc,
Mutex
};
2018-04-11 01:39:28 -04:00
use clap::{App, Arg, ArgMatches, SubCommand};
use futures::{
Future,
Stream,
Sink,
future::{
FutureResult,
ok
},
stream::empty
};
use hyper::{
Error as HyperError,
Get,
Head,
Post,
2018-04-11 01:43:40 -04:00
Put,
StatusCode,
header::ContentType,
server::{Http, Request, Response, Service}
};
2018-04-10 01:53:58 -04:00
use webmetro::{
channel::{
Channel,
Listener,
Transmitter
},
2018-04-13 19:16:34 -04:00
chunk::{Chunk, WebmStream},
error::WebmetroError,
2018-04-10 01:53:58 -04:00
fixers::ChunkStream,
stream_parser::StreamEbml
};
2018-04-15 22:06:42 -04:00
use super::to_hyper_error;
2018-04-16 00:59:53 -04:00
const BUFFER_LIMIT: usize = 2 * 1024 * 1024;
type BodyStream = Box<Stream<Item = Chunk, Error = HyperError>>;
struct RelayServer(Arc<Mutex<Channel>>);
impl RelayServer {
fn get_channel(&self) -> Arc<Mutex<Channel>> {
self.0.clone()
}
fn get_stream(&self) -> BodyStream {
Box::new(
Listener::new(self.get_channel())
.fix_timecodes()
.find_starting_point()
.map_err(|err| match err {})
)
}
fn post_stream<I: AsRef<[u8]>, S: Stream<Item = I> + 'static>(&self, stream: S) -> BodyStream
where S::Error: Error + Send {
let source = stream
2018-04-15 22:06:42 -04:00
.map_err(WebmetroError::from_err)
2018-04-16 00:59:53 -04:00
.parse_ebml().with_buffer_limit(BUFFER_LIMIT).chunk_webm();
let sink = Transmitter::new(self.get_channel());
Box::new(
2018-04-13 19:16:34 -04:00
source.forward(sink.sink_map_err(|err| -> WebmetroError {match err {}}))
.into_stream()
.map(|_| empty())
.map_err(|err| {
2018-04-15 23:43:15 -04:00
//TODO: log something somewhere
2018-04-15 22:06:42 -04:00
to_hyper_error(err)
})
.flatten()
)
}
}
impl Service for RelayServer {
type Request = Request;
type Response = Response<BodyStream>;
type Error = HyperError;
type Future = FutureResult<Self::Response, HyperError>;
fn call(&self, request: Request) -> Self::Future {
let (method, uri, _http_version, _headers, request_body) = request.deconstruct();
2018-04-15 23:43:15 -04:00
//TODO: log equiv to: eprintln!("New {} Request: {}", method, uri.path());
ok(match (method, uri.path()) {
(Head, "/live") => {
Response::new()
.with_header(ContentType("video/webm".parse().unwrap()))
},
(Get, "/live") => {
Response::new()
.with_header(ContentType("video/webm".parse().unwrap()))
.with_body(self.get_stream())
},
2018-04-11 01:43:40 -04:00
(Post, "/live") | (Put, "/live") => {
Response::new()
.with_body(self.post_stream(request_body))
},
_ => {
Response::new()
.with_status(StatusCode::NotFound)
}
})
}
}
2018-04-11 01:50:18 -04:00
pub fn options() -> App<'static, 'static> {
2018-04-11 01:39:28 -04:00
SubCommand::with_name("relay")
.about("Hosts an HTTP-based relay server")
.arg(Arg::with_name("listen")
.help("The address:port to listen to")
.required(true))
}
pub fn run(args: &ArgMatches) -> Result<(), WebmetroError> {
let single_channel = Channel::new();
2018-04-11 01:39:28 -04:00
2018-04-11 19:45:02 -04:00
let addr_str = args.value_of("listen").ok_or("Listen address wasn't provided")?;
let addr = addr_str.to_socket_addrs()?.next().ok_or("Listen address didn't resolve")?;
2018-04-11 01:39:28 -04:00
Http::new()
.bind(&addr, move || {
Ok(RelayServer(single_channel.clone()))
})
.map_err(|err| WebmetroError::Unknown(Box::new(err)))?
.run()
.map_err(|err| WebmetroError::Unknown(Box::new(err)))?;
2018-04-11 19:45:02 -04:00
Ok(())
}