aboutsummaryrefslogtreecommitdiffstats
path: root/src/server
diff options
context:
space:
mode:
authora-kenji <aks.kenji@protonmail.com>2021-05-10 20:54:39 +0200
committera-kenji <aks.kenji@protonmail.com>2021-05-10 20:54:39 +0200
commit85a4e476f2011dc0491a15bcce3b0052ebb15adb (patch)
treeeb5d120250c5c3b0d74314a42129a857bf6b1afe /src/server
parentfixup! Add Option for Simplified Layout (diff)
parentMerge pull request #480 from a-kenji/dump-config-exit (diff)
downloadsl0ppij-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.rs754
-rw-r--r--src/server/route.rs214
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();
+ }
+ }
+ }
+}