Use ClientToServerMsg and ServerToClientMsg for IPC

This commit is contained in:
Kunal Mohan 2021-05-12 20:16:56 +05:30
parent f2c43ac577
commit c5675e965b
11 changed files with 117 additions and 99 deletions

View file

@ -4,7 +4,6 @@ pub mod pane_resizer;
pub mod panes; pub mod panes;
pub mod tab; pub mod tab;
use serde::{Deserialize, Serialize};
use std::env::current_exe; use std::env::current_exe;
use std::io::{self, Write}; use std::io::{self, Write};
use std::path::Path; use std::path::Path;
@ -15,18 +14,17 @@ use std::thread;
use crate::cli::CliArgs; use crate::cli::CliArgs;
use crate::common::{ use crate::common::{
command_is_executing::CommandIsExecuting, command_is_executing::CommandIsExecuting,
errors::{ClientContext, ContextType}, errors::ContextType,
input::config::Config, input::config::Config,
input::handler::input_loop, input::handler::input_loop,
input::options::Options, ipc::{ClientToServerMsg, ServerToClientMsg},
os_input_output::ClientOsApi, os_input_output::ClientOsApi,
thread_bus::{SenderType, SenderWithContext, SyncChannelWithContext}, thread_bus::{SenderType, SenderWithContext, SyncChannelWithContext},
utils::consts::ZELLIJ_IPC_PIPE, utils::consts::ZELLIJ_IPC_PIPE,
}; };
use crate::server::ServerInstruction;
/// Instructions related to the client-side application and sent from server to client /// Instructions related to the client-side application and sent from server to client
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Debug, Clone)]
pub enum ClientInstruction { pub enum ClientInstruction {
Error(String), Error(String),
Render(Option<String>), Render(Option<String>),
@ -35,6 +33,17 @@ pub enum ClientInstruction {
ServerError(String), ServerError(String),
} }
impl From<ServerToClientMsg> for ClientInstruction {
fn from(instruction: ServerToClientMsg) -> Self {
match instruction {
ServerToClientMsg::Exit => ClientInstruction::Exit,
ServerToClientMsg::Render(buffer) => ClientInstruction::Render(buffer),
ServerToClientMsg::UnblockInputThread => ClientInstruction::UnblockInputThread,
ServerToClientMsg::ServerError(backtrace) => ClientInstruction::ServerError(backtrace),
}
}
}
fn spawn_server(socket_path: &Path) -> io::Result<()> { fn spawn_server(socket_path: &Path) -> io::Result<()> {
let status = Command::new(current_exe()?) let status = Command::new(current_exe()?)
.arg("--server") .arg("--server")
@ -71,7 +80,7 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
let full_screen_ws = os_input.get_terminal_size_using_fd(0); let full_screen_ws = os_input.get_terminal_size_using_fd(0);
os_input.connect_to_server(&*ZELLIJ_IPC_PIPE); os_input.connect_to_server(&*ZELLIJ_IPC_PIPE);
os_input.send_to_server(ServerInstruction::NewClient(full_screen_ws, opts)); os_input.send_to_server(ClientToServerMsg::NewClient(full_screen_ws, opts));
os_input.set_raw_mode(0); os_input.set_raw_mode(0);
let _ = os_input let _ = os_input
.get_stdout_writer() .get_stdout_writer()
@ -117,7 +126,7 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
os_input.receive_sigwinch(Box::new({ os_input.receive_sigwinch(Box::new({
let os_api = os_input.clone(); let os_api = os_input.clone();
move || { move || {
os_api.send_to_server(ServerInstruction::TerminalResize( os_api.send_to_server(ClientToServerMsg::TerminalResize(
os_api.get_terminal_size_using_fd(0), os_api.get_terminal_size_using_fd(0),
)); ));
} }
@ -132,15 +141,15 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
let os_input = os_input.clone(); let os_input = os_input.clone();
let mut should_break = false; let mut should_break = false;
move || loop { move || loop {
let (instruction, mut err_ctx) = os_input.recv_from_server(); let (instruction, err_ctx) = os_input.recv_from_server();
err_ctx.add_call(ContextType::Client(ClientContext::from(&instruction))); err_ctx.update_thread_ctx();
match instruction { match instruction {
ClientInstruction::Exit | ClientInstruction::ServerError(_) => { ServerToClientMsg::Exit | ServerToClientMsg::ServerError(_) => {
should_break = true; should_break = true;
} }
_ => {} _ => {}
} }
send_client_instructions.send(instruction).unwrap(); send_client_instructions.send(instruction.into()).unwrap();
if should_break { if should_break {
break; break;
} }
@ -168,13 +177,11 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
.recv() .recv()
.expect("failed to receive app instruction on channel"); .expect("failed to receive app instruction on channel");
err_ctx.add_call(ContextType::Client(ClientContext::from( err_ctx.add_call(ContextType::Client((&client_instruction).into()));
&client_instruction,
)));
match client_instruction { match client_instruction {
ClientInstruction::Exit => break, ClientInstruction::Exit => break,
ClientInstruction::Error(backtrace) => { ClientInstruction::Error(backtrace) => {
let _ = os_input.send_to_server(ServerInstruction::ClientExit); let _ = os_input.send_to_server(ClientToServerMsg::ClientExit);
handle_error(backtrace); handle_error(backtrace);
} }
ClientInstruction::ServerError(backtrace) => { ClientInstruction::ServerError(backtrace) => {
@ -196,7 +203,7 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
} }
} }
let _ = os_input.send_to_server(ServerInstruction::ClientExit); let _ = os_input.send_to_server(ClientToServerMsg::ClientExit);
router_thread.join().unwrap(); router_thread.join().unwrap();
// cleanup(); // cleanup();

View file

@ -120,6 +120,11 @@ impl ErrorContext {
break; break;
} }
} }
self.update_thread_ctx()
}
/// Updates the thread local [`ErrorContext`].
pub fn update_thread_ctx(&self) {
ASYNCOPENCALLS ASYNCOPENCALLS
.try_with(|ctx| *ctx.borrow_mut() = *self) .try_with(|ctx| *ctx.borrow_mut() = *self)
.unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self)); .unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self));
@ -369,9 +374,7 @@ impl From<&ClientInstruction> for ClientContext {
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum ServerContext { pub enum ServerContext {
NewClient, NewClient,
Action,
Render, Render,
TerminalResize,
UnblockInputThread, UnblockInputThread,
ClientExit, ClientExit,
Error, Error,
@ -381,8 +384,6 @@ impl From<&ServerInstruction> for ServerContext {
fn from(server_instruction: &ServerInstruction) -> Self { fn from(server_instruction: &ServerInstruction) -> Self {
match *server_instruction { match *server_instruction {
ServerInstruction::NewClient(..) => ServerContext::NewClient, ServerInstruction::NewClient(..) => ServerContext::NewClient,
ServerInstruction::Action(_) => ServerContext::Action,
ServerInstruction::TerminalResize(_) => ServerContext::TerminalResize,
ServerInstruction::Render(_) => ServerContext::Render, ServerInstruction::Render(_) => ServerContext::Render,
ServerInstruction::UnblockInputThread => ServerContext::UnblockInputThread, ServerInstruction::UnblockInputThread => ServerContext::UnblockInputThread,
ServerInstruction::ClientExit => ServerContext::ClientExit, ServerInstruction::ClientExit => ServerContext::ClientExit,

View file

@ -4,10 +4,10 @@ use super::actions::Action;
use super::keybinds::Keybinds; use super::keybinds::Keybinds;
use crate::client::ClientInstruction; use crate::client::ClientInstruction;
use crate::common::input::config::Config; use crate::common::input::config::Config;
use crate::common::ipc::ClientToServerMsg;
use crate::common::thread_bus::{SenderWithContext, OPENCALLS}; use crate::common::thread_bus::{SenderWithContext, OPENCALLS};
use crate::errors::ContextType; use crate::errors::ContextType;
use crate::os_input_output::ClientOsApi; use crate::os_input_output::ClientOsApi;
use crate::server::ServerInstruction;
use crate::CommandIsExecuting; use crate::CommandIsExecuting;
use termion::input::{TermRead, TermReadEventsAndRaw}; use termion::input::{TermRead, TermReadEventsAndRaw};
@ -139,7 +139,7 @@ impl InputHandler {
Action::SwitchToMode(mode) => { Action::SwitchToMode(mode) => {
self.mode = mode; self.mode = mode;
self.os_input self.os_input
.send_to_server(ServerInstruction::Action(action)); .send_to_server(ClientToServerMsg::Action(action));
} }
Action::CloseFocus Action::CloseFocus
| Action::NewPane(_) | Action::NewPane(_)
@ -151,13 +151,13 @@ impl InputHandler {
| Action::MoveFocusOrTab(_) => { | Action::MoveFocusOrTab(_) => {
self.command_is_executing.blocking_input_thread(); self.command_is_executing.blocking_input_thread();
self.os_input self.os_input
.send_to_server(ServerInstruction::Action(action)); .send_to_server(ClientToServerMsg::Action(action));
self.command_is_executing self.command_is_executing
.wait_until_input_thread_is_unblocked(); .wait_until_input_thread_is_unblocked();
} }
_ => self _ => self
.os_input .os_input
.send_to_server(ServerInstruction::Action(action)), .send_to_server(ClientToServerMsg::Action(action)),
} }
should_break should_break

View file

@ -1,10 +1,14 @@
//! IPC stuff for starting to split things into a client and server model. //! IPC stuff for starting to split things into a client and server model.
use crate::common::errors::{get_current_ctx, ErrorContext}; use crate::cli::CliArgs;
use crate::common::{
errors::{get_current_ctx, ErrorContext},
input::actions::Action,
};
use crate::panes::PositionAndSize;
use interprocess::local_socket::LocalSocketStream; use interprocess::local_socket::LocalSocketStream;
use nix::unistd::dup; use nix::unistd::dup;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::io::{self, Write}; use std::io::{self, Write};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::os::unix::io::{AsRawFd, FromRawFd}; use std::os::unix::io::{AsRawFd, FromRawFd};
@ -29,9 +33,9 @@ pub enum ClientType {
} }
// Types of messages sent from the client to the server // Types of messages sent from the client to the server
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub enum _ClientToServerMsg { pub enum ClientToServerMsg {
// List which sessions are available /*// List which sessions are available
ListSessions, ListSessions,
// Create a new session // Create a new session
CreateSession, CreateSession,
@ -40,16 +44,24 @@ pub enum _ClientToServerMsg {
// Force detach // Force detach
DetachSession(SessionId), DetachSession(SessionId),
// Disconnect from the session we're connected to // Disconnect from the session we're connected to
DisconnectFromSession, DisconnectFromSession,*/
ClientExit,
TerminalResize(PositionAndSize),
NewClient(PositionAndSize, CliArgs),
Action(Action),
} }
// Types of messages sent from the server to the client // Types of messages sent from the server to the client
// @@@ Implement Serialize and Deserialize for this... #[derive(Serialize, Deserialize, Debug, Clone)]
pub enum _ServerToClientMsg { pub enum ServerToClientMsg {
// Info about a particular session /*// Info about a particular session
SessionInfo(Session), SessionInfo(Session),
// A list of sessions // A list of sessions
SessionList(HashSet<Session>), SessionList(HashSet<Session>),*/
Render(Option<String>),
UnblockInputThread,
Exit,
ServerError(String),
} }
/// Sends messages on a stream socket, along with an [`ErrorContext`]. /// Sends messages on a stream socket, along with an [`ErrorContext`].

View file

@ -1,8 +1,8 @@
use crate::client::ClientInstruction; use crate::common::ipc::{
use crate::common::ipc::{IpcReceiverWithContext, IpcSenderWithContext}; ClientToServerMsg, IpcReceiverWithContext, IpcSenderWithContext, ServerToClientMsg,
};
use crate::errors::ErrorContext; use crate::errors::ErrorContext;
use crate::panes::PositionAndSize; use crate::panes::PositionAndSize;
use crate::server::ServerInstruction;
use crate::utils::shared::default_palette; use crate::utils::shared::default_palette;
use interprocess::local_socket::LocalSocketStream; use interprocess::local_socket::LocalSocketStream;
use nix::fcntl::{fcntl, FcntlArg, OFlag}; use nix::fcntl::{fcntl, FcntlArg, OFlag};
@ -167,8 +167,8 @@ fn spawn_terminal(file_to_open: Option<PathBuf>, orig_termios: termios::Termios)
#[derive(Clone)] #[derive(Clone)]
pub struct ServerOsInputOutput { pub struct ServerOsInputOutput {
orig_termios: Arc<Mutex<termios::Termios>>, orig_termios: Arc<Mutex<termios::Termios>>,
receive_instructions_from_client: Option<Arc<Mutex<IpcReceiverWithContext<ServerInstruction>>>>, receive_instructions_from_client: Option<Arc<Mutex<IpcReceiverWithContext<ClientToServerMsg>>>>,
send_instructions_to_client: Arc<Mutex<Option<IpcSenderWithContext<ClientInstruction>>>>, send_instructions_to_client: Arc<Mutex<Option<IpcSenderWithContext<ServerToClientMsg>>>>,
} }
/// The `ServerOsApi` trait represents an abstract interface to the features of an operating system that /// The `ServerOsApi` trait represents an abstract interface to the features of an operating system that
@ -192,9 +192,9 @@ pub trait ServerOsApi: Send + Sync {
/// Returns a [`Box`] pointer to this [`ServerOsApi`] struct. /// Returns a [`Box`] pointer to this [`ServerOsApi`] struct.
fn box_clone(&self) -> Box<dyn ServerOsApi>; fn box_clone(&self) -> Box<dyn ServerOsApi>;
/// Receives a message on server-side IPC channel /// Receives a message on server-side IPC channel
fn recv_from_client(&self) -> (ServerInstruction, ErrorContext); fn recv_from_client(&self) -> (ClientToServerMsg, ErrorContext);
/// Sends a message to client /// Sends a message to client
fn send_to_client(&self, msg: ClientInstruction); fn send_to_client(&self, msg: ServerToClientMsg);
/// Adds a sender to client /// Adds a sender to client
fn add_client_sender(&mut self); fn add_client_sender(&mut self);
/// Update the receiver socket for the client /// Update the receiver socket for the client
@ -233,7 +233,7 @@ impl ServerOsApi for ServerOsInputOutput {
waitpid(Pid::from_raw(pid), None).unwrap(); waitpid(Pid::from_raw(pid), None).unwrap();
Ok(()) Ok(())
} }
fn recv_from_client(&self) -> (ServerInstruction, ErrorContext) { fn recv_from_client(&self) -> (ClientToServerMsg, ErrorContext) {
self.receive_instructions_from_client self.receive_instructions_from_client
.as_ref() .as_ref()
.unwrap() .unwrap()
@ -241,7 +241,7 @@ impl ServerOsApi for ServerOsInputOutput {
.unwrap() .unwrap()
.recv() .recv()
} }
fn send_to_client(&self, msg: ClientInstruction) { fn send_to_client(&self, msg: ServerToClientMsg) {
self.send_instructions_to_client self.send_instructions_to_client
.lock() .lock()
.unwrap() .unwrap()
@ -288,8 +288,8 @@ pub fn get_server_os_input() -> ServerOsInputOutput {
#[derive(Clone)] #[derive(Clone)]
pub struct ClientOsInputOutput { pub struct ClientOsInputOutput {
orig_termios: Arc<Mutex<termios::Termios>>, orig_termios: Arc<Mutex<termios::Termios>>,
send_instructions_to_server: Arc<Mutex<Option<IpcSenderWithContext<ServerInstruction>>>>, send_instructions_to_server: Arc<Mutex<Option<IpcSenderWithContext<ClientToServerMsg>>>>,
receive_instructions_from_server: Arc<Mutex<Option<IpcReceiverWithContext<ClientInstruction>>>>, receive_instructions_from_server: Arc<Mutex<Option<IpcReceiverWithContext<ServerToClientMsg>>>>,
} }
/// The `ClientOsApi` trait represents an abstract interface to the features of an operating system that /// The `ClientOsApi` trait represents an abstract interface to the features of an operating system that
@ -310,10 +310,10 @@ pub trait ClientOsApi: Send + Sync {
/// Returns a [`Box`] pointer to this [`ClientOsApi`] struct. /// Returns a [`Box`] pointer to this [`ClientOsApi`] struct.
fn box_clone(&self) -> Box<dyn ClientOsApi>; fn box_clone(&self) -> Box<dyn ClientOsApi>;
/// Sends a message to the server. /// Sends a message to the server.
fn send_to_server(&self, msg: ServerInstruction); fn send_to_server(&self, msg: ClientToServerMsg);
/// Receives a message on client-side IPC channel /// Receives a message on client-side IPC channel
// This should be called from the client-side router thread only. // This should be called from the client-side router thread only.
fn recv_from_server(&self) -> (ClientInstruction, ErrorContext); fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext);
fn receive_sigwinch(&self, cb: Box<dyn Fn()>); fn receive_sigwinch(&self, cb: Box<dyn Fn()>);
/// Establish a connection with the server socket. /// Establish a connection with the server socket.
fn connect_to_server(&self, path: &Path); fn connect_to_server(&self, path: &Path);
@ -346,7 +346,7 @@ impl ClientOsApi for ClientOsInputOutput {
let stdout = ::std::io::stdout(); let stdout = ::std::io::stdout();
Box::new(stdout) Box::new(stdout)
} }
fn send_to_server(&self, msg: ServerInstruction) { fn send_to_server(&self, msg: ClientToServerMsg) {
self.send_instructions_to_server self.send_instructions_to_server
.lock() .lock()
.unwrap() .unwrap()
@ -354,7 +354,7 @@ impl ClientOsApi for ClientOsInputOutput {
.unwrap() .unwrap()
.send(msg); .send(msg);
} }
fn recv_from_server(&self) -> (ClientInstruction, ErrorContext) { fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext) {
self.receive_instructions_from_server self.receive_instructions_from_server
.lock() .lock()
.unwrap() .unwrap()

View file

@ -8,7 +8,7 @@ use std::pin::*;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::client::panes::PaneId; use crate::client::panes::PaneId;
use crate::common::errors::{get_current_ctx, ContextType, PtyContext}; use crate::common::errors::{get_current_ctx, ContextType};
use crate::common::screen::ScreenInstruction; use crate::common::screen::ScreenInstruction;
use crate::common::thread_bus::{Bus, ThreadSenders}; use crate::common::thread_bus::{Bus, ThreadSenders};
use crate::layout::Layout; use crate::layout::Layout;
@ -87,7 +87,7 @@ pub struct Pty {
pub fn pty_thread_main(mut pty: Pty, maybe_layout: Option<Layout>) { pub fn pty_thread_main(mut pty: Pty, maybe_layout: Option<Layout>) {
loop { loop {
let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel"); let (event, mut err_ctx) = pty.bus.recv().expect("failed to receive event on channel");
err_ctx.add_call(ContextType::Pty(PtyContext::from(&event))); err_ctx.add_call(ContextType::Pty((&event).into()));
match event { match event {
PtyInstruction::SpawnTerminal(file_to_open) => { PtyInstruction::SpawnTerminal(file_to_open) => {
let pid = pty.spawn_terminal(file_to_open); let pid = pty.spawn_terminal(file_to_open);

View file

@ -7,7 +7,7 @@ use std::str;
use crate::common::input::options::Options; use crate::common::input::options::Options;
use crate::common::pty::{PtyInstruction, VteBytes}; use crate::common::pty::{PtyInstruction, VteBytes};
use crate::common::thread_bus::Bus; use crate::common::thread_bus::Bus;
use crate::errors::{ContextType, ScreenContext}; use crate::errors::ContextType;
use crate::layout::Layout; use crate::layout::Layout;
use crate::panes::PaneId; use crate::panes::PaneId;
use crate::panes::PositionAndSize; use crate::panes::PositionAndSize;
@ -353,7 +353,7 @@ pub fn screen_thread_main(
.bus .bus
.recv() .recv()
.expect("failed to receive event on channel"); .expect("failed to receive event on channel");
err_ctx.add_call(ContextType::Screen(ScreenContext::from(&event))); err_ctx.add_call(ContextType::Screen((&event).into()));
match event { match event {
ScreenInstruction::PtyBytes(pid, vte_bytes) => { ScreenInstruction::PtyBytes(pid, vte_bytes) => {
let active_tab = screen.get_active_tab_mut().unwrap(); let active_tab = screen.get_active_tab_mut().unwrap();

View file

@ -15,7 +15,7 @@ use wasmer::{
use wasmer_wasi::{Pipe, WasiEnv, WasiState}; use wasmer_wasi::{Pipe, WasiEnv, WasiState};
use zellij_tile::data::{Event, EventType, PluginIds}; use zellij_tile::data::{Event, EventType, PluginIds};
use crate::common::errors::{ContextType, PluginContext}; use crate::common::errors::ContextType;
use crate::common::pty::PtyInstruction; use crate::common::pty::PtyInstruction;
use crate::common::screen::ScreenInstruction; use crate::common::screen::ScreenInstruction;
use crate::common::thread_bus::{Bus, ThreadSenders}; use crate::common::thread_bus::{Bus, ThreadSenders};
@ -44,7 +44,7 @@ pub fn wasm_thread_main(bus: Bus<PluginInstruction>, store: Store, data_dir: Pat
let mut plugin_map = HashMap::new(); let mut plugin_map = HashMap::new();
loop { loop {
let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel"); let (event, mut err_ctx) = bus.recv().expect("failed to receive event on channel");
err_ctx.add_call(ContextType::Plugin(PluginContext::from(&event))); err_ctx.add_call(ContextType::Plugin((&event).into()));
match event { match event {
PluginInstruction::Load(pid_tx, path) => { PluginInstruction::Load(pid_tx, path) => {
let plugin_dir = data_dir.join("plugins/"); let plugin_dir = data_dir.join("plugins/");

View file

@ -2,7 +2,6 @@ pub mod route;
use daemonize::Daemonize; use daemonize::Daemonize;
use interprocess::local_socket::LocalSocketListener; use interprocess::local_socket::LocalSocketListener;
use serde::{Deserialize, Serialize};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
use std::thread; use std::thread;
use std::{path::PathBuf, sync::mpsc}; use std::{path::PathBuf, sync::mpsc};
@ -10,11 +9,10 @@ use wasmer::Store;
use zellij_tile::data::PluginCapabilities; use zellij_tile::data::PluginCapabilities;
use crate::cli::CliArgs; use crate::cli::CliArgs;
use crate::client::ClientInstruction;
use crate::common::thread_bus::{Bus, ThreadSenders}; use crate::common::thread_bus::{Bus, ThreadSenders};
use crate::common::{ use crate::common::{
errors::{ContextType, ServerContext}, errors::ContextType,
input::{actions::Action, options::Options}, ipc::{ClientToServerMsg, ServerToClientMsg},
os_input_output::{set_permissions, ServerOsApi}, os_input_output::{set_permissions, ServerOsApi},
pty::{pty_thread_main, Pty, PtyInstruction}, pty::{pty_thread_main, Pty, PtyInstruction},
screen::{screen_thread_main, ScreenInstruction}, screen::{screen_thread_main, ScreenInstruction},
@ -29,17 +27,25 @@ use route::route_thread_main;
/// Instructions related to server-side application including the /// Instructions related to server-side application including the
/// ones sent by client to server /// ones sent by client to server
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Debug, Clone)]
pub enum ServerInstruction { pub enum ServerInstruction {
TerminalResize(PositionAndSize), NewClient(PositionAndSize, CliArgs),
NewClient(PositionAndSize, CliArgs, Options),
Action(Action),
Render(Option<String>), Render(Option<String>),
UnblockInputThread, UnblockInputThread,
ClientExit, ClientExit,
Error(String), Error(String),
} }
impl From<ClientToServerMsg> for ServerInstruction {
fn from(instruction: ClientToServerMsg) -> Self {
match instruction {
ClientToServerMsg::ClientExit => ServerInstruction::ClientExit,
ClientToServerMsg::NewClient(pos, opts) => ServerInstruction::NewClient(pos, opts),
_ => unreachable!(),
}
}
}
pub struct SessionMetaData { pub struct SessionMetaData {
pub senders: ThreadSenders, pub senders: ThreadSenders,
screen_thread: Option<thread::JoinHandle<()>>, screen_thread: Option<thread::JoinHandle<()>>,
@ -65,6 +71,8 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
.start() .start()
.expect("could not daemonize the server process"); .expect("could not daemonize the server process");
std::env::set_var(&"ZELLIJ", "0");
let (to_server, server_receiver): SyncChannelWithContext<ServerInstruction> = let (to_server, server_receiver): SyncChannelWithContext<ServerInstruction> =
mpsc::sync_channel(50); mpsc::sync_channel(50);
let to_server = SenderWithContext::new(SenderType::SyncSender(to_server)); let to_server = SenderWithContext::new(SenderType::SyncSender(to_server));
@ -140,7 +148,7 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
loop { loop {
let (instruction, mut err_ctx) = server_receiver.recv().unwrap(); let (instruction, mut err_ctx) = server_receiver.recv().unwrap();
err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction))); err_ctx.add_call(ContextType::IPCServer((&instruction).into()));
match instruction { match instruction {
ServerInstruction::NewClient(full_screen_ws, opts) => { ServerInstruction::NewClient(full_screen_ws, opts) => {
let session_data = let session_data =
@ -156,21 +164,20 @@ pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
.unwrap(); .unwrap();
} }
ServerInstruction::UnblockInputThread => { ServerInstruction::UnblockInputThread => {
os_input.send_to_client(ClientInstruction::UnblockInputThread); os_input.send_to_client(ServerToClientMsg::UnblockInputThread);
} }
ServerInstruction::ClientExit => { ServerInstruction::ClientExit => {
*sessions.write().unwrap() = None; *sessions.write().unwrap() = None;
os_input.send_to_client(ClientInstruction::Exit); os_input.send_to_client(ServerToClientMsg::Exit);
break; break;
} }
ServerInstruction::Render(output) => { ServerInstruction::Render(output) => {
os_input.send_to_client(ClientInstruction::Render(output)) os_input.send_to_client(ServerToClientMsg::Render(output))
} }
ServerInstruction::Error(backtrace) => { ServerInstruction::Error(backtrace) => {
os_input.send_to_client(ClientInstruction::ServerError(backtrace)); os_input.send_to_client(ServerToClientMsg::ServerError(backtrace));
break; break;
} }
_ => panic!("Received unexpected instruction."),
} }
} }
drop(std::fs::remove_file(&socket_path)); drop(std::fs::remove_file(&socket_path));

View file

@ -2,9 +2,9 @@ use std::sync::{Arc, RwLock};
use zellij_tile::data::{Event, PluginCapabilities}; use zellij_tile::data::{Event, PluginCapabilities};
use crate::common::errors::{ContextType, ServerContext};
use crate::common::input::actions::{Action, Direction}; use crate::common::input::actions::{Action, Direction};
use crate::common::input::handler::get_mode_info; use crate::common::input::handler::get_mode_info;
use crate::common::ipc::ClientToServerMsg;
use crate::common::os_input_output::ServerOsApi; use crate::common::os_input_output::ServerOsApi;
use crate::common::pty::PtyInstruction; use crate::common::pty::PtyInstruction;
use crate::common::screen::ScreenInstruction; use crate::common::screen::ScreenInstruction;
@ -193,23 +193,18 @@ pub fn route_thread_main(
capabilities: PluginCapabilities, capabilities: PluginCapabilities,
) { ) {
loop { loop {
let (instruction, mut err_ctx) = os_input.recv_from_client(); let (instruction, err_ctx) = os_input.recv_from_client();
err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction))); err_ctx.update_thread_ctx();
let rlocked_sessions = sessions.read().unwrap(); let rlocked_sessions = sessions.read().unwrap();
match instruction { match instruction {
ServerInstruction::ClientExit => { ClientToServerMsg::ClientExit => {
to_server.send(instruction).unwrap(); to_server.send(instruction.into()).unwrap();
break; break;
} }
ServerInstruction::Action(action) => { ClientToServerMsg::Action(action) => {
route_action( route_action(action, rlocked_sessions.as_ref().unwrap(), &*os_input);
action,
rlocked_sessions.as_ref().unwrap(),
&*os_input,
capabilities,
);
} }
ServerInstruction::TerminalResize(new_size) => { ClientToServerMsg::TerminalResize(new_size) => {
rlocked_sessions rlocked_sessions
.as_ref() .as_ref()
.unwrap() .unwrap()
@ -217,12 +212,9 @@ pub fn route_thread_main(
.send_to_screen(ScreenInstruction::TerminalResize(new_size)) .send_to_screen(ScreenInstruction::TerminalResize(new_size))
.unwrap(); .unwrap();
} }
ServerInstruction::NewClient(..) => { ClientToServerMsg::NewClient(..) => {
os_input.add_client_sender(); os_input.add_client_sender();
to_server.send(instruction).unwrap(); to_server.send(instruction.into()).unwrap();
}
_ => {
to_server.send(instruction).unwrap();
} }
} }
} }

View file

@ -7,11 +7,10 @@ use std::path::PathBuf;
use std::sync::{mpsc, Arc, Condvar, Mutex}; use std::sync::{mpsc, Arc, Condvar, Mutex};
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use crate::client::ClientInstruction; use crate::common::ipc::{ClientToServerMsg, ServerToClientMsg};
use crate::common::thread_bus::{ChannelWithContext, SenderType, SenderWithContext}; use crate::common::thread_bus::{ChannelWithContext, SenderType, SenderWithContext};
use crate::errors::ErrorContext; use crate::errors::ErrorContext;
use crate::os_input_output::{ClientOsApi, ServerOsApi}; use crate::os_input_output::{ClientOsApi, ServerOsApi};
use crate::server::ServerInstruction;
use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes}; use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes};
use crate::tests::utils::commands::{QUIT, SLEEP}; use crate::tests::utils::commands::{QUIT, SLEEP};
use crate::utils::shared::default_palette; use crate::utils::shared::default_palette;
@ -77,10 +76,10 @@ pub struct FakeInputOutput {
win_sizes: Arc<Mutex<HashMap<RawFd, PositionAndSize>>>, win_sizes: Arc<Mutex<HashMap<RawFd, PositionAndSize>>>,
possible_tty_inputs: HashMap<u16, Bytes>, possible_tty_inputs: HashMap<u16, Bytes>,
last_snapshot_time: Arc<Mutex<Instant>>, last_snapshot_time: Arc<Mutex<Instant>>,
send_instructions_to_client: SenderWithContext<ClientInstruction>, send_instructions_to_client: SenderWithContext<ServerToClientMsg>,
receive_instructions_from_server: Arc<Mutex<mpsc::Receiver<(ClientInstruction, ErrorContext)>>>, receive_instructions_from_server: Arc<Mutex<mpsc::Receiver<(ServerToClientMsg, ErrorContext)>>>,
send_instructions_to_server: SenderWithContext<ServerInstruction>, send_instructions_to_server: SenderWithContext<ClientToServerMsg>,
receive_instructions_from_client: Arc<Mutex<mpsc::Receiver<(ServerInstruction, ErrorContext)>>>, receive_instructions_from_client: Arc<Mutex<mpsc::Receiver<(ClientToServerMsg, ErrorContext)>>>,
should_trigger_sigwinch: Arc<(Mutex<bool>, Condvar)>, should_trigger_sigwinch: Arc<(Mutex<bool>, Condvar)>,
sigwinch_event: Option<PositionAndSize>, sigwinch_event: Option<PositionAndSize>,
} }
@ -90,10 +89,10 @@ impl FakeInputOutput {
let mut win_sizes = HashMap::new(); let mut win_sizes = HashMap::new();
let last_snapshot_time = Arc::new(Mutex::new(Instant::now())); let last_snapshot_time = Arc::new(Mutex::new(Instant::now()));
let stdout_writer = FakeStdoutWriter::new(last_snapshot_time.clone()); let stdout_writer = FakeStdoutWriter::new(last_snapshot_time.clone());
let (client_sender, client_receiver): ChannelWithContext<ClientInstruction> = let (client_sender, client_receiver): ChannelWithContext<ServerToClientMsg> =
mpsc::channel(); mpsc::channel();
let send_instructions_to_client = SenderWithContext::new(SenderType::Sender(client_sender)); let send_instructions_to_client = SenderWithContext::new(SenderType::Sender(client_sender));
let (server_sender, server_receiver): ChannelWithContext<ServerInstruction> = let (server_sender, server_receiver): ChannelWithContext<ClientToServerMsg> =
mpsc::channel(); mpsc::channel();
let send_instructions_to_server = SenderWithContext::new(SenderType::Sender(server_sender)); let send_instructions_to_server = SenderWithContext::new(SenderType::Sender(server_sender));
win_sizes.insert(0, winsize); // 0 is the current terminal win_sizes.insert(0, winsize); // 0 is the current terminal
@ -195,10 +194,10 @@ impl ClientOsApi for FakeInputOutput {
fn get_stdout_writer(&self) -> Box<dyn Write> { fn get_stdout_writer(&self) -> Box<dyn Write> {
Box::new(self.stdout_writer.clone()) Box::new(self.stdout_writer.clone())
} }
fn send_to_server(&self, msg: ServerInstruction) { fn send_to_server(&self, msg: ClientToServerMsg) {
self.send_instructions_to_server.send(msg).unwrap(); self.send_instructions_to_server.send(msg).unwrap();
} }
fn recv_from_server(&self) -> (ClientInstruction, ErrorContext) { fn recv_from_server(&self) -> (ServerToClientMsg, ErrorContext) {
self.receive_instructions_from_server self.receive_instructions_from_server
.lock() .lock()
.unwrap() .unwrap()
@ -278,14 +277,14 @@ impl ServerOsApi for FakeInputOutput {
self.io_events.lock().unwrap().push(IoEvent::Kill(fd)); self.io_events.lock().unwrap().push(IoEvent::Kill(fd));
Ok(()) Ok(())
} }
fn recv_from_client(&self) -> (ServerInstruction, ErrorContext) { fn recv_from_client(&self) -> (ClientToServerMsg, ErrorContext) {
self.receive_instructions_from_client self.receive_instructions_from_client
.lock() .lock()
.unwrap() .unwrap()
.recv() .recv()
.unwrap() .unwrap()
} }
fn send_to_client(&self, msg: ClientInstruction) { fn send_to_client(&self, msg: ServerToClientMsg) {
self.send_instructions_to_client.send(msg).unwrap(); self.send_instructions_to_client.send(msg).unwrap();
} }
fn add_client_sender(&mut self) {} fn add_client_sender(&mut self) {}