diff options
author | denis <denismaximov98@gmail.com> | 2021-03-18 12:20:23 +0200 |
---|---|---|
committer | Kunal Mohan <kunalmohan99@gmail.com> | 2021-04-14 01:41:29 +0530 |
commit | 1f0e2ea29ed31008e4c4fa2e259d4fd7e415a483 (patch) | |
tree | 31cd569f325275eb772b69ebe8c519184dc8a9e9 | |
parent | 2df0585430e551b422145621bc52936f8a5230bc (diff) |
wip: here goes the os_thread and OsContext
-rw-r--r-- | src/common/errors.rs | 41 | ||||
-rw-r--r-- | src/server/mod.rs | 407 |
2 files changed, 270 insertions, 178 deletions
diff --git a/src/common/errors.rs b/src/common/errors.rs index d30af844a..4fd8b2aa7 100644 --- a/src/common/errors.rs +++ b/src/common/errors.rs @@ -1,7 +1,7 @@ //! Error context system based on a thread-local representation of the call stack, itself based on //! the instructions that are sent between threads. -use super::{AppInstruction, ASYNCOPENCALLS, OPENCALLS}; +use super::{os_input_output::OsApiInstruction, AppInstruction, OPENCALLS}; use crate::pty_bus::PtyInstruction; use crate::screen::ScreenInstruction; use serde::{Deserialize, Serialize}; @@ -138,6 +138,8 @@ pub enum ContextType { Screen(ScreenContext), /// A PTY-related call. Pty(PtyContext), + /// An OS-related call. + Os(OsContext), /// A plugin-related call. Plugin(PluginContext), /// An app-related call. @@ -158,7 +160,7 @@ impl Display for ContextType { match *self { ContextType::Screen(c) => write!(f, "{}screen_thread: {}{:?}", purple, green, c), ContextType::Pty(c) => write!(f, "{}pty_thread: {}{:?}", purple, green, c), - + ContextType::Os(c) => write!(f, "{}os_thread: {}{:?}", purple, green, c), ContextType::Plugin(c) => write!(f, "{}plugin_thread: {}{:?}", purple, green, c), ContextType::App(c) => write!(f, "{}main_thread: {}{:?}", purple, green, c), ContextType::IpcServer => write!(f, "{}ipc_server: {}AcceptInput", purple, green), @@ -287,6 +289,41 @@ impl From<&PtyInstruction> for PtyContext { } } +#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] +pub enum OsContext { + SpawnTerminal, + GetTerminalSizeUsingFd, + SetTerminalSizeUsingFd, + SetRawMode, + UnsetRawMode, + ReadFromTtyStdout, + WriteToTtyStdin, + TcDrain, + Kill, + ReadFromStdin, + GetStdoutWriter, + BoxClone, +} + +impl From<&OsApiInstruction> for OsContext { + fn from(os_instruction: &OsApiInstruction) -> Self { + match *os_instruction { + OsApiInstruction::SpawnTerminal(_) => OsContext::SpawnTerminal, + OsApiInstruction::GetTerminalSizeUsingFd(_) => OsContext::GetTerminalSizeUsingFd, + OsApiInstruction::SetTerminalSizeUsingFd(_, _, _) => OsContext::SetTerminalSizeUsingFd, + OsApiInstruction::SetRawMode(_) => OsContext::SetRawMode, + OsApiInstruction::UnsetRawMode(_) => OsContext::UnsetRawMode, + OsApiInstruction::ReadFromTtyStdout(_, _) => OsContext::ReadFromTtyStdout, + OsApiInstruction::WriteToTtyStdin(_, _) => OsContext::WriteToTtyStdin, + OsApiInstruction::TcDrain(_) => OsContext::TcDrain, + OsApiInstruction::Kill(_) => OsContext::Kill, + OsApiInstruction::ReadFromStdin => OsContext::ReadFromStdin, + OsApiInstruction::GetStdoutWriter => OsContext::GetStdoutWriter, + OsApiInstruction::BoxClone => OsContext::BoxClone + } + } +} + // FIXME: This whole pattern *needs* a macro eventually, it's soul-crushing to write use crate::wasm_vm::PluginInstruction; diff --git a/src/server/mod.rs b/src/server/mod.rs index 794066b05..3ca9e0043 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,9 +1,9 @@ use crate::cli::CliArgs; use crate::common::{ - ChannelWithContext, ClientInstruction, IpcSenderWithContext, SenderType, SenderWithContext, - ServerInstruction, + ChannelWithContext, ClientInstruction, IpcSenderWithContext, SenderType, SenderWithContext, + ServerInstruction, }; -use crate::errors::{ContextType, ErrorContext, PtyContext}; +use crate::errors::{ContextType, ErrorContext, OsContext, PtyContext}; use crate::os_input_output::{OsApi, OsApiInstruction}; use crate::panes::PaneId; use crate::pty_bus::{PtyBus, PtyInstruction}; @@ -15,185 +15,240 @@ use std::sync::mpsc::channel; use std::thread; pub fn start_server(os_input: Box<dyn OsApi>, opts: CliArgs) -> (thread::JoinHandle<()>, String) { - let (send_pty_instructions, receive_pty_instructions): ChannelWithContext<PtyInstruction> = - channel(); - let mut send_pty_instructions = SenderWithContext::new( - ErrorContext::new(), - SenderType::Sender(send_pty_instructions), - ); + let (send_pty_instructions, receive_pty_instructions): ChannelWithContext<PtyInstruction> = + channel(); + let mut send_pty_instructions = SenderWithContext::new( + ErrorContext::new(), + SenderType::Sender(send_pty_instructions), + ); - #[cfg(not(test))] - let (server_name, server_buffer) = ( - String::from(ZELLIJ_IPC_PIPE), - SharedRingBuffer::create(ZELLIJ_IPC_PIPE, 8192).unwrap(), - ); - #[cfg(test)] - let (server_name, server_buffer) = SharedRingBuffer::create_temp(8192).unwrap(); + #[cfg(not(test))] + let (server_name, server_buffer) = ( + String::from(ZELLIJ_IPC_PIPE), + SharedRingBuffer::create(ZELLIJ_IPC_PIPE, 8192).unwrap(), + ); + #[cfg(test)] + let (server_name, server_buffer) = SharedRingBuffer::create_temp(8192).unwrap(); - let (send_os_instructions, receive_os_instructions): ChannelWithContext<OsApiInstruction> = channel(); - let mut send_os_instructions = SenderWithContext::new( - ErrorContext::new(), - SenderType::Sender(send_os_instructions), - ); + let (send_os_instructions, receive_os_instructions): ChannelWithContext<OsApiInstruction> = + channel(); + let mut send_os_instructions = SenderWithContext::new( + ErrorContext::new(), + SenderType::Sender(send_os_instructions), + ); - // Don't use default layouts in tests, but do everywhere else - #[cfg(not(test))] - let default_layout = Some(PathBuf::from("default")); - #[cfg(test)] - let default_layout = None; - let maybe_layout = opts.layout.or(default_layout); + // Don't use default layouts in tests, but do everywhere else + #[cfg(not(test))] + let default_layout = Some(PathBuf::from("default")); + #[cfg(test)] + let default_layout = None; + let maybe_layout = opts.layout.or(default_layout); - let send_server_instructions = IpcSenderWithContext::new(server_buffer.clone()); + let send_server_instructions = IpcSenderWithContext::new(server_buffer.clone()); - let mut pty_bus = PtyBus::new( - receive_pty_instructions, - os_input.clone(), - send_server_instructions, - opts.debug, - ); + let mut pty_bus = PtyBus::new( + receive_pty_instructions, + os_input.clone(), + send_server_instructions, + opts.debug, + ); - let pty_thread = thread::Builder::new() - .name("pty".to_string()) - .spawn(move || loop { - let (event, mut err_ctx) = pty_bus - .receive_pty_instructions - .recv() - .expect("failed to receive event on channel"); - err_ctx.add_call(ContextType::Pty(PtyContext::from(&event))); - match event { - PtyInstruction::SpawnTerminal(file_to_open) => { - let pid = pty_bus.spawn_terminal(file_to_open); - pty_bus - .send_server_instructions - .send(ServerInstruction::ToScreen(ScreenInstruction::NewPane( - PaneId::Terminal(pid), - ))) - .unwrap(); - } - PtyInstruction::SpawnTerminalVertically(file_to_open) => { - let pid = pty_bus.spawn_terminal(file_to_open); - pty_bus - .send_server_instructions - .send(ServerInstruction::ToScreen( - ScreenInstruction::VerticalSplit(PaneId::Terminal(pid)), - )) - .unwrap(); - } - PtyInstruction::SpawnTerminalHorizontally(file_to_open) => { - let pid = pty_bus.spawn_terminal(file_to_open); - pty_bus - .send_server_instructions - .send(ServerInstruction::ToScreen( - ScreenInstruction::HorizontalSplit(PaneId::Terminal(pid)), - )) - .unwrap(); - } - PtyInstruction::NewTab => { - if let Some(layout) = maybe_layout.clone() { - pty_bus.spawn_terminals_for_layout(layout); - } else { - let pid = pty_bus.spawn_terminal(None); - pty_bus - .send_server_instructions - .send(ServerInstruction::ToScreen(ScreenInstruction::NewTab(pid))) - .unwrap(); - } - } - PtyInstruction::ClosePane(id) => { - pty_bus.close_pane(id); - pty_bus - .send_server_instructions - .send(ServerInstruction::DoneClosingPane) - .unwrap(); - } - PtyInstruction::CloseTab(ids) => { - pty_bus.close_tab(ids); - pty_bus - .send_server_instructions - .send(ServerInstruction::DoneClosingPane) - .unwrap(); - } - PtyInstruction::Exit => { - break; - } - } - }) - .unwrap(); + let pty_thread = thread::Builder::new() + .name("pty".to_string()) + .spawn(move || loop { + let (event, mut err_ctx) = pty_bus + .receive_pty_instructions + .recv() + .expect("failed to receive event on channel"); + err_ctx.add_call(ContextType::Pty(PtyContext::from(&event))); + match event { + PtyInstruction::SpawnTerminal(file_to_open) => { + let pid = pty_bus.spawn_terminal(file_to_open); + pty_bus + .send_server_instructions + .send(ServerInstruction::ToScreen(ScreenInstruction::NewPane( + PaneId::Terminal(pid), + ))) + .unwrap(); + } + PtyInstruction::SpawnTerminalVertically(file_to_open) => { + let pid = pty_bus.spawn_terminal(file_to_open); + pty_bus + .send_server_instructions + .send(ServerInstruction::ToScreen( + ScreenInstruction::VerticalSplit(PaneId::Terminal(pid)), + )) + .unwrap(); + } + PtyInstruction::SpawnTerminalHorizontally(file_to_open) => { + let pid = pty_bus.spawn_terminal(file_to_open); + pty_bus + .send_server_instructions + .send(ServerInstruction::ToScreen( + ScreenInstruction::HorizontalSplit(PaneId::Terminal(pid)), + )) + .unwrap(); + } + PtyInstruction::NewTab => { + if let Some(layout) = maybe_layout.clone() { + pty_bus.spawn_terminals_for_layout(layout); + } else { + let pid = pty_bus.spawn_terminal(None); + pty_bus + .send_server_instructions + .send(ServerInstruction::ToScreen(ScreenInstruction::NewTab(pid))) + .unwrap(); + } + } + PtyInstruction::ClosePane(id) => { + pty_bus.close_pane(id); + pty_bus + .send_server_instructions + .send(ServerInstruction::DoneClosingPane) + .unwrap(); + } + PtyInstruction::CloseTab(ids) => { + pty_bus.close_tab(ids); + pty_bus + .send_server_instructions + .send(ServerInstruction::DoneClosingPane) + .unwrap(); + } + PtyInstruction::Exit => { + break; + } + } + }) + .unwrap(); - let join_handle = thread::Builder::new() - .name("ipc_server".to_string()) - .spawn({ - let recv_server_instructions = IpcReceiver::new(server_buffer); - // Fixme: We cannot use uninitialised sender, therefore this Vec. - // For now, We make sure that the first message is `NewClient` so there are no out of bound panics. - let mut send_client_instructions: Vec<IpcSenderWithContext> = Vec::with_capacity(1); - move || loop { - let (mut err_ctx, instruction): (ErrorContext, ServerInstruction) = - recv_server_instructions.recv().unwrap(); - err_ctx.add_call(ContextType::IPCServer); - send_pty_instructions.update(err_ctx); - if send_client_instructions.len() == 1 { - send_client_instructions[0].update(err_ctx); - } + let os_thread = thread::Builder::new() + .name("os".to_string()) + .spawn({ + let mut os_input = os_input.clone(); + move || loop { + let (event, mut err_ctx) = receive_os_instructions + .recv() + .expect("failed to receive an event on the channel"); + err_ctx.add_call(ContextType::Os(OsContext::from(&event))); + match event { + OsApiInstruction::SpawnTerminal(file_to_open) => { + os_input.spawn_terminal(file_to_open); + } + OsApiInstruction::GetTerminalSizeUsingFd(fd) => { + os_input.get_terminal_size_using_fd(fd); + } + OsApiInstruction::SetTerminalSizeUsingFd(fd, cols, rows) => { + os_input.set_terminal_size_using_fd(fd, cols, rows); + } + OsApiInstruction::SetRawMode(fd) => { + os_input.set_raw_mode(fd); + } + OsApiInstruction::UnsetRawMode(fd) => { + os_input.unset_raw_mode(fd); + } + OsApiInstruction::ReadFromTtyStdout(fd, mut buf) => { + let slice = buf.as_mut_slice(); + os_input.read_from_tty_stdout(fd, slice).unwrap(); + } + OsApiInstruction::WriteToTtyStdin(fd, mut buf) => { + let slice = buf.as_mut_slice(); + os_input.write_to_tty_stdin(fd, slice).unwrap(); + } + OsApiInstruction::TcDrain(fd) => { + os_input.tcdrain(fd).unwrap(); + } + OsApiInstruction::Kill(pid) => { + os_input.kill(pid).unwrap(); + } + OsApiInstruction::ReadFromStdin => { + os_input.read_from_stdin(); + } + OsApiInstruction::GetStdoutWriter => { + os_input.get_stdout_writer(); + } + OsApiInstruction::BoxClone => { + os_input.box_clone(); + } + } + } + }) + .unwrap(); - match instruction { - ServerInstruction::OpenFile(file_name) => { - let path = PathBuf::from(file_name); - send_pty_instructions - .send(PtyInstruction::SpawnTerminal(Some(path))) - .unwrap(); - } - ServerInstruction::SplitHorizontally => { - send_pty_instructions - .send(PtyInstruction::SpawnTerminalHorizontally(None)) - .unwrap(); - } - ServerInstruction::SplitVertically => { - send_pty_instructions - .send(PtyInstruction::SpawnTerminalVertically(None)) - .unwrap(); - } - ServerInstruction::MoveFocus => { - send_client_instructions[0] - .send(ClientInstruction::ToScreen(ScreenInstruction::MoveFocus)) - .unwrap(); - } - ServerInstruction::NewClient(buffer_path) => { - send_pty_instructions.send(PtyInstruction::NewTab).unwrap(); - send_client_instructions.push(IpcSenderWithContext::new( - SharedRingBuffer::open(&buffer_path).unwrap(), - )); - } - ServerInstruction::ToPty(instr) => { - send_pty_instructions.send(instr).unwrap(); - } - ServerInstruction::ToScreen(instr) => { - send_client_instructions[0] - .send(ClientInstruction::ToScreen(instr)) - .unwrap(); - } - ServerInstruction::OsApi(instr) => { - send_os_instructions.send(instr).unwrap(); - } - ServerInstruction::DoneClosingPane => { - send_client_instructions[0] - .send(ClientInstruction::DoneClosingPane) - .unwrap(); - } - ServerInstruction::ClosePluginPane(pid) => { - send_client_instructions[0] - .send(ClientInstruction::ClosePluginPane(pid)) - .unwrap(); - } - ServerInstruction::Exit => { - let _ = send_pty_instructions.send(PtyInstruction::Exit); - let _ = pty_thread.join(); - let _ = send_client_instructions[0].send(ClientInstruction::Exit); - break; - } - } - } - }) - .unwrap(); - (join_handle, server_name) + let join_handle = thread::Builder::new() + .name("ipc_server".to_string()) + .spawn({ + let recv_server_instructions = IpcReceiver::new(server_buffer); + // Fixme: We cannot use uninitialised sender, therefore this Vec. + // For now, We make sure that the first message is `NewClient` so there are no out of bound panics. + let mut send_client_instructions: Vec<IpcSenderWithContext> = Vec::with_capacity(1); + move || loop { + let (mut err_ctx, instruction): (ErrorContext, ServerInstruction) = + recv_server_instructions.recv().unwrap(); + err_ctx.add_call(ContextType::IPCServer); + send_pty_instructions.update(err_ctx); + if send_client_instructions.len() == 1 { + send_client_instructions[0].update(err_ctx); + } + + match instruction { + ServerInstruction::OpenFile(file_name) => { + let path = PathBuf::from(file_name); + send_pty_instructions + .send(PtyInstruction::SpawnTerminal(Some(path))) + .unwrap(); + } + ServerInstruction::SplitHorizontally => { + send_pty_instructions + .send(PtyInstruction::SpawnTerminalHorizontally(None)) + .unwrap(); + } + ServerInstruction::SplitVertically => { + send_pty_instructions + .send(PtyInstruction::SpawnTerminalVertically(None)) + .unwrap(); + } + ServerInstruction::MoveFocus => { + send_client_instructions[0] + .send(ClientInstruction::ToScreen(ScreenInstruction::MoveFocus)) + .unwrap(); + } + ServerInstruction::NewClient(buffer_path) => { + send_pty_instructions.send(PtyInstruction::NewTab).unwrap(); + send_client_instructions.push(IpcSenderWithContext::new( + SharedRingBuffer::open(&buffer_path).unwrap(), + )); + } + ServerInstruction::ToPty(instr) => { + send_pty_instructions.send(instr).unwrap(); + } + ServerInstruction::ToScreen(instr) => { + send_client_instructions[0] + .send(ClientInstruction::ToScreen(instr)) + .unwrap(); + } + ServerInstruction::OsApi(instr) => { + send_os_instructions.send(instr).unwrap(); + } + ServerInstruction::DoneClosingPane => { + send_client_instructions[0] + .send(ClientInstruction::DoneClosingPane) + .unwrap(); + } + ServerInstruction::ClosePluginPane(pid) => { + send_client_instructions[0] + .send(ClientInstruction::ClosePluginPane(pid)) + .unwrap(); + } + ServerInstruction::Exit => { + let _ = send_pty_instructions.send(PtyInstruction::Exit); + let _ = pty_thread.join(); + let _ = os_thread.join(); + let _ = send_client_instructions[0].send(ClientInstruction::Exit); + break; + } + } + } + }) + .unwrap(); + (join_handle, server_name) } |