diff options
| author | a-kenji <aks.kenji@protonmail.com> | 2021-05-10 20:54:39 +0200 |
|---|---|---|
| committer | a-kenji <aks.kenji@protonmail.com> | 2021-05-10 20:54:39 +0200 |
| commit | 85a4e476f2011dc0491a15bcce3b0052ebb15adb (patch) | |
| tree | eb5d120250c5c3b0d74314a42129a857bf6b1afe /src/server | |
| parent | fixup! Add Option for Simplified Layout (diff) | |
| parent | Merge pull request #480 from a-kenji/dump-config-exit (diff) | |
| download | sl0ppij-85a4e476f2011dc0491a15bcce3b0052ebb15adb.tar.gz sl0ppij-85a4e476f2011dc0491a15bcce3b0052ebb15adb.tar.xz sl0ppij-85a4e476f2011dc0491a15bcce3b0052ebb15adb.zip | |
fixup! Merge branch 'main' of https://github.com/zellij-org/zellij into simple-font-ui
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/mod.rs | 754 | ||||
| -rw-r--r-- | src/server/route.rs | 214 |
2 files changed, 306 insertions, 662 deletions
diff --git a/src/server/mod.rs b/src/server/mod.rs index 58a92c55..1b08f95f 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -1,36 +1,29 @@ +pub mod route; + use interprocess::local_socket::LocalSocketListener; use serde::{Deserialize, Serialize}; -use std::path::PathBuf; -use std::sync::mpsc::channel; +use std::sync::{Arc, RwLock}; use std::thread; -use std::{collections::HashMap, fs}; -use std::{ - collections::HashSet, - str::FromStr, - sync::{Arc, Mutex, RwLock}, -}; -use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value}; -use wasmer_wasi::{Pipe, WasiState}; -use zellij_tile::data::{Event, EventType, InputMode, ModeInfo, PluginCapabilities}; +use std::{path::PathBuf, sync::mpsc::channel}; +use wasmer::Store; -use crate::cli::{CliArgs, ConfigCli}; +use crate::cli::CliArgs; use crate::client::ClientInstruction; +use crate::common::thread_bus::{Bus, ThreadSenders}; use crate::common::{ - errors::{ContextType, PluginContext, PtyContext, ScreenContext, ServerContext}, - input::actions::{Action, Direction}, - input::options::Options, - input::handler::get_mode_info, + errors::{ContextType, ServerContext}, + input::{actions::Action, options::Options}, os_input_output::{set_permissions, ServerOsApi}, - pty_bus::{PtyBus, PtyInstruction}, - screen::{Screen, ScreenInstruction}, + pty::{pty_thread_main, Pty, PtyInstruction}, + screen::{screen_thread_main, ScreenInstruction}, setup::install::populate_data_dir, + thread_bus::{ChannelWithContext, SenderType, SenderWithContext}, utils::consts::{ZELLIJ_IPC_PIPE, ZELLIJ_PROJ_DIR}, - wasm_vm::{wasi_read_string, wasi_write_object, zellij_exports, PluginEnv, PluginInstruction}, - ChannelWithContext, SenderType, SenderWithContext, + wasm_vm::{wasm_thread_main, PluginInstruction}, }; use crate::layout::Layout; -use crate::panes::PaneId; use crate::panes::PositionAndSize; +use route::route_thread_main; /// Instructions related to server-side application including the /// ones sent by client to server @@ -44,10 +37,8 @@ pub enum ServerInstruction { ClientExit, } -struct SessionMetaData { - pub send_pty_instructions: SenderWithContext<PtyInstruction>, - pub send_screen_instructions: SenderWithContext<ScreenInstruction>, - pub send_plugin_instructions: SenderWithContext<PluginInstruction>, +pub struct SessionMetaData { + pub senders: ThreadSenders, screen_thread: Option<thread::JoinHandle<()>>, pty_thread: Option<thread::JoinHandle<()>>, wasm_thread: Option<thread::JoinHandle<()>>, @@ -55,9 +46,9 @@ struct SessionMetaData { impl Drop for SessionMetaData { fn drop(&mut self) { - let _ = self.send_pty_instructions.send(PtyInstruction::Exit); - let _ = self.send_screen_instructions.send(ScreenInstruction::Exit); - let _ = self.send_plugin_instructions.send(PluginInstruction::Exit); + let _ = self.senders.send_to_pty(PtyInstruction::Exit); + let _ = self.senders.send_to_screen(ScreenInstruction::Exit); + let _ = self.senders.send_to_plugin(PluginInstruction::Exit); let _ = self.screen_thread.take().unwrap().join(); let _ = self.pty_thread.take().unwrap().join(); let _ = self.wasm_thread.take().unwrap().join(); @@ -65,26 +56,28 @@ impl Drop for SessionMetaData { } pub fn start_server(os_input: Box<dyn ServerOsApi>) -> thread::JoinHandle<()> { - let (send_server_instructions, receive_server_instructions): ChannelWithContext< - ServerInstruction, - > = channel(); - let send_server_instructions = - SenderWithContext::new(SenderType::Sender(send_server_instructions)); + let (to_server, server_receiver): ChannelWithContext<ServerInstruction> = channel(); + let to_server = SenderWithContext::new(SenderType::Sender(to_server)); let sessions: Arc<RwLock<Option<SessionMetaData>>> = Arc::new(RwLock::new(None)); #[cfg(test)] - handle_client( - sessions.clone(), - os_input.clone(), - send_server_instructions.clone(), - ); + thread::Builder::new() + .name("server_router".to_string()) + .spawn({ + let sessions = sessions.clone(); + let os_input = os_input.clone(); + let to_server = to_server.clone(); + + move || route_thread_main(sessions, os_input, to_server) + }) + .unwrap(); #[cfg(not(test))] let _ = thread::Builder::new() .name("server_listener".to_string()) .spawn({ let os_input = os_input.clone(); let sessions = sessions.clone(); - let send_server_instructions = send_server_instructions.clone(); + let to_server = to_server.clone(); move || { drop(std::fs::remove_file(&*ZELLIJ_IPC_PIPE)); let listener = LocalSocketListener::bind(&**ZELLIJ_IPC_PIPE).unwrap(); @@ -95,8 +88,17 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>) -> thread::JoinHandle<()> { let mut os_input = os_input.clone(); os_input.update_receiver(stream); let sessions = sessions.clone(); - let send_server_instructions = send_server_instructions.clone(); - handle_client(sessions, os_input, send_server_instructions); + let to_server = to_server.clone(); + thread::Builder::new() + .name("server_router".to_string()) + .spawn({ + let sessions = sessions.clone(); + let os_input = os_input.clone(); + let to_server = to_server.clone(); + + move || route_thread_main(sessions, os_input, to_server) + }) + .unwrap(); } Err(err) => { panic!("err {:?}", err); @@ -110,7 +112,7 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>) -> thread::JoinHandle<()> { .name("server_thread".to_string()) .spawn({ move || loop { - let (instruction, mut err_ctx) = receive_server_instructions.recv().unwrap(); + let (instruction, mut err_ctx) = server_receiver.recv().unwrap(); err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction))); match instruction { ServerInstruction::NewClient(full_screen_ws, opts, config_options) => { @@ -118,7 +120,7 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>) -> thread::JoinHandle<()> { os_input.clone(), opts, config_options, - send_server_instructions.clone(), + to_server.clone(), full_screen_ws, ); *sessions.write().unwrap() = Some(session_data); @@ -127,8 +129,8 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>) -> thread::JoinHandle<()> { .unwrap() .as_ref() .unwrap() - .send_pty_instructions - .send(PtyInstruction::NewTab) + .senders + .send_to_pty(PtyInstruction::NewTab) .unwrap(); } ServerInstruction::UnblockInputThread => { @@ -150,66 +152,20 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>) -> thread::JoinHandle<()> { .unwrap() } -fn handle_client( - sessions: Arc<RwLock<Option<SessionMetaData>>>, - mut os_input: Box<dyn ServerOsApi>, - send_server_instructions: SenderWithContext<ServerInstruction>, -) { - thread::Builder::new() - .name("server_router".to_string()) - .spawn(move || loop { - let (instruction, mut err_ctx) = os_input.recv_from_client(); - err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction))); - let rlocked_sessions = sessions.read().unwrap(); - match instruction { - ServerInstruction::ClientExit => { - send_server_instructions.send(instruction).unwrap(); - break; - } - ServerInstruction::Action(action) => { - route_action(action, rlocked_sessions.as_ref().unwrap(), &*os_input); - } - ServerInstruction::TerminalResize(new_size) => { - rlocked_sessions - .as_ref() - .unwrap() - .send_screen_instructions - .send(ScreenInstruction::TerminalResize(new_size)) - .unwrap(); - } - ServerInstruction::NewClient(..) => { - os_input.add_client_sender(); - send_server_instructions.send(instruction).unwrap(); - } - _ => { - send_server_instructions.send(instruction).unwrap(); - } - } - }) - .unwrap(); -} - fn init_session( os_input: Box<dyn ServerOsApi>, opts: CliArgs, config_options: Options, - send_server_instructions: SenderWithContext<ServerInstruction>, + to_server: SenderWithContext<ServerInstruction>, full_screen_ws: PositionAndSize, ) -> SessionMetaData { - let (send_screen_instructions, receive_screen_instructions): ChannelWithContext< - ScreenInstruction, - > = channel(); - let send_screen_instructions = - SenderWithContext::new(SenderType::Sender(send_screen_instructions)); + let (to_screen, screen_receiver): ChannelWithContext<ScreenInstruction> = channel(); + let to_screen = SenderWithContext::new(SenderType::Sender(to_screen)); - let (send_plugin_instructions, receive_plugin_instructions): ChannelWithContext< - PluginInstruction, - > = channel(); - let send_plugin_instructions = - SenderWithContext::new(SenderType::Sender(send_plugin_instructions)); - let (send_pty_instructions, receive_pty_instructions): ChannelWithContext<PtyInstruction> = - channel(); - let send_pty_instructions = SenderWithContext::new(SenderType::Sender(send_pty_instructions)); + let (to_plugin, plugin_receiver): ChannelWithContext<PluginInstruction> = channel(); + let to_plugin = SenderWithContext::new(SenderType::Sender(to_plugin)); + let (to_pty, pty_receiver): ChannelWithContext<PtyInstruction> = channel(); + let to_pty = SenderWithContext::new(SenderType::Sender(to_pty)); // Determine and initialize the data directory let data_dir = opts @@ -227,330 +183,41 @@ fn init_session( .map(|p| Layout::new(&p, &data_dir)) .or_else(|| default_layout.map(|p| Layout::from_defaults(&p, &data_dir))); - let mut pty_bus = PtyBus::new( - receive_pty_instructions, - send_screen_instructions.clone(), - send_plugin_instructions.clone(), - os_input.clone(), - opts.debug, - ); - let pty_thread = thread::Builder::new() .name("pty".to_string()) .spawn({ - let send_server_instructions = send_server_instructions.clone(); - 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_screen_instructions - .send(ScreenInstruction::NewPane(PaneId::Terminal(pid))) - .unwrap(); - } - PtyInstruction::SpawnTerminalVertically(file_to_open) => { - let pid = pty_bus.spawn_terminal(file_to_open); - pty_bus - .send_screen_instructions - .send(ScreenInstruction::VerticalSplit(PaneId::Terminal(pid))) - .unwrap(); - } - PtyInstruction::SpawnTerminalHorizontally(file_to_open) => { - let pid = pty_bus.spawn_terminal(file_to_open); - pty_bus - .send_screen_instructions - .send(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_screen_instructions - .send(ScreenInstruction::NewTab(pid)) - .unwrap(); - } - } - PtyInstruction::ClosePane(id) => { - pty_bus.close_pane(id); - send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - PtyInstruction::CloseTab(ids) => { - pty_bus.close_tab(ids); - send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - PtyInstruction::Exit => { - break; - } - } - } + let pty = Pty::new( + Bus::new( + pty_receiver, + Some(&to_screen), + None, + Some(&to_plugin), + Some(&to_server), + Some(os_input.clone()), + ), + opts.debug, + ); + + move || pty_thread_main(pty, maybe_layout) }) .unwrap(); let screen_thread = thread::Builder::new() .name("screen".to_string()) .spawn({ - let os_input = os_input.clone(); - let send_plugin_instructions = send_plugin_instructions.clone(); - let send_pty_instructions = send_pty_instructions.clone(); - let send_server_instructions = send_server_instructions; + let screen_bus = Bus::new( + screen_receiver, + None, + Some(&to_pty), + Some(&to_plugin), + Some(&to_server), + Some(os_input.clone()), + ); let max_panes = opts.max_panes; - let capabilities = if let Some(ConfigCli::Options(options)) = opts.option { - options.simplified_ui - } else { - config_options.simplified_ui - }; - let colors = os_input.load_palette(); + let options = opts.option; move || { - let mut screen = Screen::new( - receive_screen_instructions, - send_plugin_instructions, - send_pty_instructions, - send_server_instructions, - &full_screen_ws, - os_input, - max_panes, - ModeInfo { - palette: colors, - capabilities: PluginCapabilities { - arrow_fonts: capabilities, - }, - ..ModeInfo::default() - }, - InputMode::Normal, - colors, - ); - loop { - let (event, mut err_ctx) = screen - .receiver - .recv() - .expect("failed to receive event on channel"); - err_ctx.add_call(ContextType::Screen(ScreenContext::from(&event))); - match event { - ScreenInstruction::PtyBytes(pid, vte_bytes) => { - let active_tab = screen.get_active_tab_mut().unwrap(); - if active_tab.has_terminal_pid(pid) { - // it's most likely that this event is directed at the active tab - // look there first - active_tab.handle_pty_bytes(pid, vte_bytes); - } else { - // if this event wasn't directed at the active tab, start looking - // in other tabs - let all_tabs = screen.get_tabs_mut(); - for tab in all_tabs.values_mut() { - if tab.has_terminal_pid(pid) { - tab.handle_pty_bytes(pid, vte_bytes); - break; - } - } - } - } - ScreenInstruction::Render => { - screen.render(); - } - ScreenInstruction::NewPane(pid) => { - screen.get_active_tab_mut().unwrap().new_pane(pid); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::HorizontalSplit(pid) => { - screen.get_active_tab_mut().unwrap().horizontal_split(pid); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::VerticalSplit(pid) => { - screen.get_active_tab_mut().unwrap().vertical_split(pid); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::WriteCharacter(bytes) => { - let active_tab = screen.get_active_tab_mut().unwrap(); - match active_tab.is_sync_panes_active() { - true => active_tab.write_to_terminals_on_current_tab(bytes), - false => active_tab.write_to_active_terminal(bytes), - } - } - ScreenInstruction::ResizeLeft => { - screen.get_active_tab_mut().unwrap().resize_left(); - } - ScreenInstruction::ResizeRight => { - screen.get_active_tab_mut().unwrap().resize_right(); - } - ScreenInstruction::ResizeDown => { - screen.get_active_tab_mut().unwrap().resize_down(); - } - ScreenInstruction::ResizeUp => { - screen.get_active_tab_mut().unwrap().resize_up(); - } - ScreenInstruction::SwitchFocus => { - screen.get_active_tab_mut().unwrap().move_focus(); - } - ScreenInstruction::FocusNextPane => { - screen.get_active_tab_mut().unwrap().focus_next_pane(); - } - ScreenInstruction::FocusPreviousPane => { - screen.get_active_tab_mut().unwrap().focus_previous_pane(); - } - ScreenInstruction::MoveFocusLeft => { - screen.get_active_tab_mut().unwrap().move_focus_left(); - } - ScreenInstruction::MoveFocusDown => { - screen.get_active_tab_mut().unwrap().move_focus_down(); - } - ScreenInstruction::MoveFocusRight => { - screen.get_active_tab_mut().unwrap().move_focus_right(); - } - ScreenInstruction::MoveFocusUp => { - screen.get_active_tab_mut().unwrap().move_focus_up(); - } - ScreenInstruction::ScrollUp => { - screen - .get_active_tab_mut() - .unwrap() - .scroll_active_terminal_up(); - } - ScreenInstruction::ScrollDown => { - screen - .get_active_tab_mut() - .unwrap() - .scroll_active_terminal_down(); - } - ScreenInstruction::PageScrollUp => { - screen - .get_active_tab_mut() - .unwrap() - .scroll_active_terminal_up_page(); - } - ScreenInstruction::PageScrollDown => { - screen - .get_active_tab_mut() - .unwrap() - .scroll_active_terminal_down_page(); - } - ScreenInstruction::ClearScroll => { - screen - .get_active_tab_mut() - .unwrap() - .clear_active_terminal_scroll(); - } - ScreenInstruction::CloseFocusedPane => { - screen.get_active_tab_mut().unwrap().close_focused_pane(); - screen.render(); - } - ScreenInstruction::SetSelectable(id, selectable) => { - screen - .get_active_tab_mut() - .unwrap() - .set_pane_selectable(id, selectable); - } - ScreenInstruction::SetMaxHeight(id, max_height) => { - screen - .get_active_tab_mut() - .unwrap() - .set_pane_max_height(id, max_height); - } - ScreenInstruction::SetInvisibleBorders(id, invisible_borders) => { - screen - .get_active_tab_mut() - .unwrap() - .set_pane_invisible_borders(id, invisible_borders); - screen.render(); - } - ScreenInstruction::ClosePane(id) => { - screen.get_active_tab_mut().unwrap().close_pane(id); - screen.render(); - } - ScreenInstruction::ToggleActiveTerminalFullscreen => { - screen - .get_active_tab_mut() - .unwrap() - .toggle_active_pane_fullscreen(); - } - ScreenInstruction::NewTab(pane_id) => { - screen.new_tab(pane_id); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::SwitchTabNext => { - screen.switch_tab_next(); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::SwitchTabPrev => { - screen.switch_tab_prev(); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::CloseTab => { - screen.close_tab(); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::ApplyLayout(layout, new_pane_pids) => { - screen.apply_layout(layout, new_pane_pids); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::GoToTab(tab_index) => { - screen.go_to_tab(tab_index as usize); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::UpdateTabName(c) => { - screen.update_active_tab_name(c); - screen - .send_server_instructions - .send(ServerInstruction::UnblockInputThread) - .unwrap(); - } - ScreenInstruction::TerminalResize(new_size) => { - screen.resize_to_screen(new_size); - } - ScreenInstruction::ChangeMode(mode_info) => { - screen.change_mode(mode_info); - } - ScreenInstruction::ToggleActiveSyncTab => { - screen - .get_active_tab_mut() - .unwrap() - .toggle_sync_tab_is_active(); - screen.update_tabs(); - } - ScreenInstruction::Exit => { - break; - } - } - } + screen_thread_main(screen_bus, max_panes, full_screen_ws, options, config_options); } }) .unwrap(); @@ -558,265 +225,28 @@ fn init_session( let wasm_thread = thread::Builder::new() .name("wasm".to_string()) .spawn({ - let send_screen_instructions = send_screen_instructions.clone(); - let send_pty_instructions = send_pty_instructions.clone(); - let send_plugin_instructions = send_plugin_instructions.clone(); - + let plugin_bus = Bus::new( + plugin_receiver, + Some(&to_screen), + Some(&to_pty), + None, + None, + None, + ); let store = Store::default(); - let mut plugin_id = 0; - let mut plugin_map = HashMap::new(); - move || loop { - let (event, mut err_ctx) = receive_plugin_instructions - .recv() - .expect("failed to receive event on channel"); - err_ctx.add_call(ContextType::Plugin(PluginContext::from(&event))); - match event { - PluginInstruction::Load(pid_tx, path) => { - let plugin_dir = data_dir.join("plugins/"); - let wasm_bytes = fs::read(&path) - .or_else(|_| fs::read(&path.with_extension("wasm"))) - .or_else(|_| fs::read(&plugin_dir.join(&path).with_extension("wasm"))) - .unwrap_or_else(|_| panic!("cannot find plugin {}", &path.display())); - - // FIXME: Cache this compiled module on disk. I could use `(de)serialize_to_file()` for that - let module = Module::new(&store, &wasm_bytes).unwrap(); - - let output = Pipe::new(); - let input = Pipe::new(); - let mut wasi_env = WasiState::new("Zellij") - .env("CLICOLOR_FORCE", "1") - .preopen(|p| { - p.directory(".") // FIXME: Change this to a more meaningful dir - .alias(".") - .read(true) - .write(true) - .create(true) - }) - .unwrap() - .stdin(Box::new(input)) - .stdout(Box::new(output)) - .finalize() - .unwrap(); - - let wasi = wasi_env.import_object(&module).unwrap(); - - let plugin_env = PluginEnv { - plugin_id, - send_screen_instructions: send_screen_instructions.clone(), - send_pty_instructions: send_pty_instructions.clone(), - send_plugin_instructions: send_plugin_instructions.clone(), - wasi_env, - subscriptions: Arc::new(Mutex::new(HashSet::new())), - }; - - let zellij = zellij_exports(&store, &plugin_env); - let instance = Instance::new(&module, &zellij.chain_back(wasi)).unwrap(); - - let start = instance.exports.get_function("_start").unwrap(); - // This eventually calls the `.init()` method - start.call(&[]).unwrap(); - - plugin_map.insert(plugin_id, (instance, plugin_env)); - pid_tx.send(plugin_id).unwrap(); - plugin_id += 1; - } - PluginInstruction::Update(pid, event) => { - for (&i, (instance, plugin_env)) in &plugin_map { - let subs = plugin_env.subscriptions.lock().unwrap(); - // FIXME: This is very janky... Maybe I should write my own macro for Event -> EventType? - let event_type = EventType::from_str(&event.to_string()).unwrap(); - if (pid.is_none() || pid == Some(i)) && subs.contains(&event_type) { - let update = instance.exports.get_function("update").unwrap(); - wasi_write_object(&plugin_env.wasi_env, &event); - update.call(&[]).unwrap(); - } - } - drop(send_screen_instructions.send(ScreenInstruction::Render)); - } - PluginInstruction::Render(buf_tx, pid, rows, cols) => { - let (instance, plugin_env) = plugin_map.get(&pid).unwrap(); - - let render = instance.exports.get_function("render").unwrap(); - - render - .call(&[Value::I32(rows as i32), Value::I32(cols as i32)]) - .unwrap(); - - buf_tx.send(wasi_read_string(&plugin_env.wasi_env)).unwrap(); - } - PluginInstruction::Unload(pid) => drop(plugin_map.remove(&pid)), - PluginInstruction::Exit => break, - } - } + move || wasm_thread_main(plugin_bus, store, data_dir) }) .unwrap(); SessionMetaData { - send_plugin_instructions, - send_screen_instructions, - send_pty_instructions, + senders: ThreadSenders { + to_screen: Some(to_screen), + to_pty: Some(to_pty), + to_plugin: Some(to_plugin), + to_server: None, + }, screen_thread: Some(screen_thread), pty_thread: Some(pty_thread), wasm_thread: Some(wasm_thread), } } - -fn route_action(action: Action, session: &SessionMetaData, os_input: &dyn ServerOsApi) { - match action { - Action::Write(val) => { - session - .send_screen_instructions - .send(ScreenInstruction::ClearScroll) - .unwrap(); - session - .send_screen_instructions - .send(ScreenInstruction::WriteCharacter(val)) - .unwrap(); - } - Action::SwitchToMode(mode) => { - let palette = os_input.load_palette(); - session - .send_plugin_instructions - .send(PluginInstruction::Update( - None, - Event::ModeUpdate(get_mode_info(mode, palette)), - )) - .unwrap(); - session - .send_screen_instructions - .send(ScreenInstruction::ChangeMode(get_mode_info(mode, palette))) - .unwrap(); - session - .send_screen_instructions - .send(ScreenInstruction::Render) - .unwrap(); - } - Action::Resize(direction) => { - let screen_instr = match direction { - Direction::Left => ScreenInstruction::ResizeLeft, - Direction::Right => ScreenInstruction::ResizeRight, - Direction::Up => ScreenInstruction::ResizeUp, - Direction::Down => ScreenInstruction::ResizeDown, - }; - session.send_screen_instructions.send(screen_instr).unwrap(); - } - Action::SwitchFocus => { - session - .send_screen_instructions - .send(ScreenInstruction::SwitchFocus) - .unwrap(); - } - Action::FocusNextPane => { - session - .send_screen_instructions - .send(ScreenInstruction::FocusNextPane) - .unwrap(); - } - Action::FocusPreviousPane => { - session - .send_screen_instructions - .send(ScreenInstruction::FocusPreviousPane) - .unwrap(); - } - Action::MoveFocus(direction) => { - let screen_instr = match direction { - Direction::Left => ScreenInstruction::MoveFocusLeft, - Direction::Right => ScreenInstruction::MoveFocusRight, - Direction::Up => ScreenInstruction::MoveFocusUp, - Direction::Down => ScreenInstruction::MoveFocusDown, - }; - session.send_screen_instructions.send(screen_instr).unwrap(); - } - Action::ScrollUp => { - session - .send_screen_instructions - .send(ScreenInstruction::ScrollUp) - .unwrap(); - } - Action::ScrollDown => { - session - .send_screen_instructions - .send(ScreenInstruction::ScrollDown) - .unwrap(); - } - Action::PageScrollUp => { - session - .send_screen_instructions - .send(ScreenInstruction::PageScrollUp) - .unwrap(); - } - Action::PageScrollDown => { - session - .send_screen_instructions - .send(ScreenInstruction::PageScrollDown) - .unwrap(); - } - Action::ToggleFocusFullscreen => { - session - .send_screen_instructions - .send(ScreenInstruction::ToggleActiveTerminalFullscreen) - .unwrap(); - } - Action::NewPane(direction) => { - let pty_instr = match direction { - Some(Direction::Left) => PtyInstruction::SpawnTerminalVertically(None), - Some(Direction::Right) => PtyInstruction::SpawnTerminalVertically(None), - Some(Direction::Up) => PtyInstruction::SpawnTerminalHorizontally(None), - Some(Direction::Down) => PtyInstruction::SpawnTerminalHorizontally(None), - // No direction specified - try to put it in the biggest available spot - None => PtyInstruction::SpawnTerminal(None), - }; - session.send_pty_instructions.send(pty_instr).unwrap(); - } - Action::CloseFocus => { - session - .send_screen_instructions - .send(ScreenInstruction::CloseFocusedPane) - .unwrap(); - } - Action::NewTab => { - session - .send_pty_instructions - .send(PtyInstruction::NewTab) - .unwrap(); - } - Action::GoToNextTab => { - session - .send_screen_instructions - .send(ScreenInstruction::SwitchTabNext) - .unwrap(); - } - Action::GoToPreviousTab => { - session - .send_screen_instructions - .send(ScreenInstruction::SwitchTabPrev) - .unwrap(); - } - Action::ToggleActiveSyncTab => { - session - .send_screen_instructions - .send(ScreenInstruction::ToggleActiveSyncTab) - .unwrap(); - } - Action::CloseTab => { - session - .send_screen_instructions - .send(ScreenInstruction::CloseTab) - .unwrap(); - } - Action::GoToTab(i) => { - session - .send_screen_instructions - .send(ScreenInstruction::GoToTab(i)) - .unwrap(); - } - Action::TabNameInput(c) => { - session - .send_screen_instructions - .send(ScreenInstruction::UpdateTabName(c)) - .unwrap(); - } - Action::NoOp => {} - Action::Quit => panic!("Received unexpected action"), - } -} diff --git a/src/server/route.rs b/src/server/route.rs new file mode 100644 index 00000000..668cdfbd --- /dev/null +++ b/src/server/route.rs @@ -0,0 +1,214 @@ +use std::sync::{Arc, RwLock}; + +use zellij_tile::data::Event; + +use crate::common::errors::{ContextType, ServerContext}; +use crate::common::input::actions::{Action, Direction}; +use crate::common::input::handler::get_mode_info; +use crate::common::os_input_output::ServerOsApi; +use crate::common::pty::PtyInstruction; +use crate::common::screen::ScreenInstruction; +use crate::common::thread_bus::SenderWithContext; +use crate::common::wasm_vm::PluginInstruction; +use crate::server::{ServerInstruction, SessionMetaData}; + +fn route_action(action: Action, session: &SessionMetaData, os_input: &dyn ServerOsApi) { + match action { + Action::Write(val) => { + session + .senders + .send_to_screen(ScreenInstruction::ClearScroll) + .unwrap(); + session + .senders + .send_to_screen(ScreenInstruction::WriteCharacter(val)) + .unwrap(); + } + Action::SwitchToMode(mode) => { + let palette = os_input.load_palette(); + session + .senders + .send_to_plugin(PluginInstruction::Update( + None, + Event::ModeUpdate(get_mode_info(mode, palette)), + )) + .unwrap(); + session + .senders + .send_to_screen(ScreenInstruction::ChangeMode(get_mode_info(mode, palette))) + .unwrap(); + session + .senders + .send_to_screen(ScreenInstruction::Render) + .unwrap(); + } + Action::Resize(direction) => { + let screen_instr = match direction { + Direction::Left => ScreenInstruction::ResizeLeft, + Direction::Right => ScreenInstruction::ResizeRight, + Direction::Up => ScreenInstruction::ResizeUp, + Direction::Down => ScreenInstruction::ResizeDown, + }; + session.senders.send_to_screen(screen_instr).unwrap(); + } + Action::SwitchFocus => { + session + .senders + .send_to_screen(ScreenInstruction::SwitchFocus) + .unwrap(); + } + Action::FocusNextPane => { + session + .senders + .send_to_screen(ScreenInstruction::FocusNextPane) + .unwrap(); + } + Action::FocusPreviousPane => { + session + .senders + .send_to_screen(ScreenInstruction::FocusPreviousPane) + .unwrap(); + } + Action::MoveFocus(direction) => { + let screen_instr = match direction { + Direction::Left => ScreenInstruction::MoveFocusLeft, + Direction::Right => ScreenInstruction::MoveFocusRight, + Direction::Up => ScreenInstruction::MoveFocusUp, + Direction::Down => ScreenInstruction::MoveFocusDown, + }; + session.senders.send_to_screen(screen_instr).unwrap(); + } + Action::MoveFocusOrTab(direction) => { + let screen_instr = match direction { + Direction::Left => ScreenInstruction::MoveFocusLeftOrPreviousTab, + Direction::Right => ScreenInstruction::MoveFocusRightOrNextTab, + _ => unreachable!(), + }; + session.senders.send_to_screen(screen_instr).unwrap(); + } + Action::ScrollUp => { + session + .senders + .send_to_screen(ScreenInstruction::ScrollUp) + .unwrap(); + } + Action::ScrollDown => { + session + .senders + .send_to_screen(ScreenInstruction::ScrollDown) + .unwrap(); + } + Action::PageScrollUp => { + session + .senders + .send_to_screen(ScreenInstruction::PageScrollUp) + .unwrap(); + } + Action::PageScrollDown => { + session + .senders + .send_to_screen(ScreenInstruction::PageScrollDown) + .unwrap(); + } + Action::ToggleFocusFullscreen => { + session + .senders + .send_to_screen(ScreenInstruction::ToggleActiveTerminalFullscreen) + .unwrap(); + } + Action::NewPane(direction) => { + let pty_instr = match direction { + Some(Direction::Left) => PtyInstruction::SpawnTerminalVertically(None), + Some(Direction::Right) => PtyInstruction::SpawnTerminalVertically(None), + Some(Direction::Up) => PtyInstruction::SpawnTerminalHorizontally(None), + Some(Direction::Down) => PtyInstruction::SpawnTerminalHorizontally(None), + // No direction specified - try to put it in the biggest available spot + None => PtyInstruction::SpawnTerminal(None), + }; + session.senders.send_to_pty(pty_instr).unwrap(); + } + Action::CloseFocus => { + session + .senders + .send_to_screen(ScreenInstruction::CloseFocusedPane) + .unwrap(); + } + Action::NewTab => { + session.senders.send_to_pty(PtyInstruction::NewTab).unwrap(); + } + Action::GoToNextTab => { + session + .senders + .send_to_screen(ScreenInstruction::SwitchTabNext) + .unwrap(); + } + Action::GoToPreviousTab => { + session + .senders + .send_to_screen(ScreenInstruction::SwitchTabPrev) + .unwrap(); + } + Action::ToggleActiveSyncTab => { + session + .senders + .send_to_screen(ScreenInstruction::ToggleActiveSyncTab) + .unwrap(); + } + Action::CloseTab => { + session + .senders + .send_to_screen(ScreenInstruction::CloseTab) + .unwrap(); + } + Action::GoToTab(i) => { + session + .senders + .send_to_screen(ScreenInstruction::GoToTab(i)) + .unwrap(); + } + Action::TabNameInput(c) => { + session + .senders + .send_to_screen(ScreenInstruction::UpdateTabName(c)) + .unwrap(); + } + Action::NoOp => {} + Action::Quit => panic!("Received unexpected action"), + } +} + +pub fn route_thread_main( + sessions: Arc<RwLock<Option<SessionMetaData>>>, + mut os_input: Box<dyn ServerOsApi>, + to_server: SenderWithContext<ServerInstruction>, +) { + loop { + let (instruction, mut err_ctx) = os_input.recv_from_client(); + err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction))); + let rlocked_sessions = sessions.read().unwrap(); + match instruction { + ServerInstruction::ClientExit => { + to_server.send(instruction).unwrap(); + break; + } + ServerInstruction::Action(action) => { + route_action(action, rlocked_sessions.as_ref().unwrap(), &*os_input); + } + ServerInstruction::TerminalResize(new_size) => { + rlocked_sessions + .as_ref() + .unwrap() + .senders + .send_to_screen(ScreenInstruction::TerminalResize(new_size)) + .unwrap(); + } + ServerInstruction::NewClient(..) => { + os_input.add_client_sender(); + to_server.send(instruction).unwrap(); + } + _ => { + to_server.send(instruction).unwrap(); + } + } + } +} |
