2019-01-03 17:15:07 +00:00
|
|
|
use actix::Message;
|
|
|
|
|
|
|
|
|
|
use libc::c_ushort;
|
|
|
|
|
|
|
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
|
|
|
|
|
use serde::ser::SerializeSeq;
|
|
|
|
|
use serde::{Serialize, Serializer};
|
|
|
|
|
use serde_json;
|
|
|
|
|
|
|
|
|
|
use crate::IO;
|
|
|
|
|
|
|
|
|
|
impl Message for TerminadoMessage {
|
|
|
|
|
type Result = ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Eq, PartialEq, Clone)]
|
|
|
|
|
pub enum TerminadoMessage {
|
|
|
|
|
Resize { rows: c_ushort, cols: c_ushort },
|
|
|
|
|
Stdin(IO),
|
|
|
|
|
Stdout(IO),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TerminadoMessage {
|
|
|
|
|
pub fn from_json(json: &str) -> Result<Self, ()> {
|
|
|
|
|
let value: serde_json::Value = serde_json::from_str(json).map_err(|_| {
|
|
|
|
|
error!("Invalid Terminado message: Invalid JSON");
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
let list: &Vec<serde_json::Value> = value.as_array().ok_or_else(|| {
|
|
|
|
|
error!("Invalid Terminado message: Needs to be an array!");
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
match list
|
|
|
|
|
.first()
|
|
|
|
|
.ok_or_else(|| {
|
|
|
|
|
error!("Invalid Terminado message: Empty array!");
|
|
|
|
|
})?
|
|
|
|
|
.as_str()
|
|
|
|
|
.ok_or_else(|| {
|
|
|
|
|
error!("Invalid Terminado message: Type field not a string!");
|
|
|
|
|
})? {
|
|
|
|
|
"stdin" => {
|
|
|
|
|
if list.len() != 2 {
|
|
|
|
|
error!(r#"Invalid Terminado message: "stdin" length != 2"#);
|
|
|
|
|
return Err(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(TerminadoMessage::Stdin(IO::from(
|
|
|
|
|
list[1].as_str().ok_or_else(|| {
|
|
|
|
|
error!(r#"Invalid Terminado message: "stdin" needs to be a String"#);
|
|
|
|
|
})?,
|
|
|
|
|
)))
|
|
|
|
|
}
|
|
|
|
|
"stdout" => {
|
|
|
|
|
if list.len() != 2 {
|
|
|
|
|
error!(r#"Invalid Terminado message: "stdout" length != 2"#);
|
|
|
|
|
return Err(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(TerminadoMessage::Stdout(IO::from(
|
|
|
|
|
list[1].as_str().ok_or_else(|| {
|
|
|
|
|
error!(r#"Invalid Terminado message: "stdout" needs to be a String"#);
|
|
|
|
|
})?,
|
|
|
|
|
)))
|
|
|
|
|
}
|
|
|
|
|
"set_size" => {
|
|
|
|
|
if list.len() != 3 {
|
|
|
|
|
error!(r#"Invalid Terminado message: "set_size" length != 2"#);
|
|
|
|
|
return Err(());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let rows: u16 = u16::try_from(list[1].as_u64().ok_or_else(|| {
|
|
|
|
|
error!(
|
|
|
|
|
r#"Invalid Terminado message: "set_size" element 1 needs to be an integer"#
|
|
|
|
|
);
|
|
|
|
|
})?)
|
|
|
|
|
.map_err(|_| {
|
|
|
|
|
error!(r#"Invalid Terminado message. "set_size" rows out of range."#);
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
let cols: u16 = u16::try_from(list[2].as_u64().ok_or_else(|| {
|
|
|
|
|
error!(
|
|
|
|
|
r#"Invalid Terminado message: "set_size" element 2 needs to be an integer"#
|
|
|
|
|
);
|
|
|
|
|
})?)
|
|
|
|
|
.map_err(|_| {
|
|
|
|
|
error!(r#"Invalid Terminado message. "set_size" cols out of range."#);
|
|
|
|
|
})?;
|
|
|
|
|
|
|
|
|
|
Ok(TerminadoMessage::Resize { rows, cols })
|
|
|
|
|
}
|
|
|
|
|
v => {
|
|
|
|
|
error!("Invalid Terminado message: Unknown type {:?}", v);
|
|
|
|
|
Err(())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Serialize for TerminadoMessage {
|
|
|
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
|
|
|
where
|
|
|
|
|
S: Serializer,
|
|
|
|
|
{
|
|
|
|
|
match self {
|
|
|
|
|
TerminadoMessage::Resize { rows, cols } => {
|
|
|
|
|
let mut seq = serializer.serialize_seq(Some(3))?;
|
|
|
|
|
seq.serialize_element("set_size")?;
|
|
|
|
|
seq.serialize_element(rows)?;
|
|
|
|
|
seq.serialize_element(cols)?;
|
|
|
|
|
seq.end()
|
|
|
|
|
}
|
|
|
|
|
TerminadoMessage::Stdin(stdin) => {
|
|
|
|
|
let mut seq = serializer.serialize_seq(Some(2))?;
|
|
|
|
|
seq.serialize_element("stdin")?;
|
|
|
|
|
seq.serialize_element(&String::from_utf8_lossy(stdin.0.as_ref()))?;
|
|
|
|
|
seq.end()
|
|
|
|
|
}
|
|
|
|
|
TerminadoMessage::Stdout(stdin) => {
|
|
|
|
|
let mut seq = serializer.serialize_seq(Some(2))?;
|
|
|
|
|
seq.serialize_element("stdout")?;
|
|
|
|
|
seq.serialize_element(&String::from_utf8_lossy(stdin.0.as_ref()))?;
|
|
|
|
|
seq.end()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_serialize_resize() {
|
|
|
|
|
let res = TerminadoMessage::Resize { rows: 25, cols: 80 };
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
serde_json::to_string(&res).unwrap(),
|
|
|
|
|
r#"["set_size",25,80]"#
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_serialize_stdin() {
|
|
|
|
|
let res = TerminadoMessage::Stdin(IO::from("hello world"));
|
|
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
serde_json::to_string(&res).unwrap(),
|
|
|
|
|
r#"["stdin","hello world"]"#
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_serialize_stdout() {
|
2019-03-22 14:11:50 +00:00
|
|
|
let res = TerminadoMessage::Stdout(IO::from("hello world"));
|
2019-01-03 17:15:07 +00:00
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
|
serde_json::to_string(&res).unwrap(),
|
|
|
|
|
r#"["stdout","hello world"]"#
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_deserialize_resize() {
|
|
|
|
|
let json = r#"["set_size", 25, 80]"#;
|
|
|
|
|
|
|
|
|
|
let value = TerminadoMessage::from_json(json).expect("Could not parse TerminadoMessage");
|
|
|
|
|
|
|
|
|
|
assert_eq!(value, TerminadoMessage::Resize { rows: 25, cols: 80 });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_deserialize_stdin() {
|
|
|
|
|
let json = r#"["stdin", "hello world"]"#;
|
|
|
|
|
|
|
|
|
|
let value = TerminadoMessage::from_json(json).expect("Could not parse TerminadoMessage");
|
|
|
|
|
|
|
|
|
|
assert_eq!(value, TerminadoMessage::Stdin("hello world".into()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_deserialize_stdout() {
|
|
|
|
|
let json = r#"["stdout", "hello world"]"#;
|
|
|
|
|
|
|
|
|
|
let value = TerminadoMessage::from_json(json).expect("Could not parse TerminadoMessage");
|
|
|
|
|
|
2019-03-22 14:11:50 +00:00
|
|
|
assert_eq!(value, TerminadoMessage::Stdout("hello world".into()));
|
2019-01-03 17:15:07 +00:00
|
|
|
}
|
|
|
|
|
}
|