diff --git a/Cargo.lock b/Cargo.lock index 343f695..317792b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,6 +5,7 @@ dependencies = [ "conch-parser 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "conch-runtime 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "vt6 0.0.1", ] [[package]] @@ -713,6 +714,10 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "vt6" +version = "0.0.1" + [[package]] name = "winapi" version = "0.2.8" diff --git a/Cargo.toml b/Cargo.toml index d7ccf4e..adc61de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ authors = ["lærling "] conch-parser = "^0.1.0" conch-runtime = "^0.1.4" tokio-core = "^0.1.17" +vt6 = { path = "../vt6.rs" } \ No newline at end of file diff --git a/src/connection.rs b/src/connection.rs new file mode 100644 index 0000000..1135956 --- /dev/null +++ b/src/connection.rs @@ -0,0 +1,115 @@ +/******************************************************************************* + * + * Copyright 2018 lærling + * + * This program is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + *******************************************************************************/ + +use std::env::vars; +use std::io::Write; +use std::io; +use std::os::unix::net::UnixStream; +use std::path::PathBuf; +use std::process::exit; +use std::vec::Vec; + +/// All input/output that is directed at the terminal has to go via this object. +/// It abstracts over the kind of connection (normal or multiplexed) and in +/// multiplexed mode joins message stream and I/O stream appropriately. In +/// normal mode it just forwards to stdout and the message stream. +pub struct IO { + mode: ConnectionMode, +} + +/// The mode the client is operating in and, if operating in normal mode, +/// the (connected) VT6 message stream +pub enum ConnectionMode { + Normal(UnixStream), + Multiplexed, +} + +impl IO { + + /// Determines the connection mode and returns a new IO object + pub fn new() -> Result { + + // use normal mode if VT6 environment variable is present + if let Some(vt6_socket_var) = vars().find(|var| var.0 == "VT6") { + return Ok(Connection { mode: ConnectionMode::Normal( + // FIXME: Use SOCK_SEQPACKET to connect + UnixStream::connect(PathBuf::from(vt6_socket_var.1))? + )}); + } + + // use multiplexed mode if TERM environment variable is "vt6" + if let Some(_) = vars().find(|var| *var == ("TERM".to_string(), "vt6".to_string())) { + return Ok(Connection { mode: ConnectionMode::Multiplexed }); + } + + // else server is absent + // for now this means exiting + eprintln!("No VT6 server found. Exiting"); + exit(1); + } + + pub fn is_multiplexed(&self) -> bool { + self.mode == ConnectionMode::Multiplexed + } + + /// Print to I/O stream + pub fn print(&self, &str) { + match self.mode { + ConnectionMode::Normal(_) => print!(&str); + } + } + + /// Print to message stream. For the time being, this is a synchronous + /// function, meaning that after sending it waits until a complete answer + /// message is received. + pub fn send_message(&mut self, msg: Vec) -> String { + + // send to the server + match self.mode { + + // in normal mode write to message stream + ConnectionMode::Normal(ref mut stream) => { + stream.write_all(msg.as_slice()).unwrap(); + }, + + // in multiplexed mode merge in I/O stream + ConnectionMode::Multiplexed => { + // TODO + panic!("not yet implemented"); + }, + }; + + // receive from the server + match self.mode { + + // in normal mode read from message stream + ConnectionMode::Normal(ref mut stream) => { + use std::io::Read; + let mut answer = String::with_capacity(24); + let _bytes_read = stream.read_to_string(&mut answer).unwrap(); + return answer; + }, + + // in multiplexed mode parse from I/O stream + ConnectionMode::Multiplexed => { + // TODO + panic!("not yet implemented"); + } + }; + } +} diff --git a/src/main.rs b/src/main.rs index 9b05c30..a6fa4ce 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,18 +19,22 @@ extern crate conch_parser; extern crate conch_runtime; extern crate tokio_core; +extern crate vt6; + +mod connection; use conch_parser::lexer::Lexer; use conch_parser::parse::DefaultParser; use conch_runtime::env::DefaultEnv; use conch_runtime::future::EnvFuture; use conch_runtime::spawn::sequence; +use connection::Connection; use std::env; use std::fs::File; use std::io; use std::option::Option; -use tokio_core::reactor::Core; use std::process::exit; +use tokio_core::reactor::Core; fn repl(script: &mut T) -> io::Result<()> { @@ -79,6 +83,19 @@ fn repl(script: &mut T) -> io::Result<()> { fn main() { + use vt6::core::msg::MessageFormatter; + let mut buf = vec![0; 22]; // 22 is the exact length + { + let mut mf = MessageFormatter::new(&mut buf, "want", 2); + mf.add_argument("core"); + mf.add_argument(&1); + let _length = mf.finalize().unwrap(); + } // end borrow of buf by MessageFormatter + let mut con = Connection::new().unwrap(); + println!("Received: {}", con.send_and_receive(buf)); + + std::process::exit(0); + // evaluate command line argument let eval_result = match env::args().nth(1) {