Hide server-side Ipc channels creation behind OsApis and some documentation fixes

This commit is contained in:
Kunal Mohan 2021-03-22 02:08:39 +05:30
parent 3ef2715827
commit bc2345c413
6 changed files with 56 additions and 44 deletions

View File

@ -146,6 +146,7 @@ pub enum ContextType {
Plugin(PluginContext),
/// An app-related call.
App(AppContext),
/// A server-related call.
IPCServer(ServerContext),
StdinHandler,
AsyncTask,
@ -297,6 +298,7 @@ impl From<&PtyInstruction> for PtyContext {
}
}
/// Stack call representations corresponding to the different types of [`ServerOsApiInstruction`]s.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum OsContext {
SetTerminalSizeUsingFd,
@ -372,7 +374,7 @@ impl From<&AppInstruction> for AppContext {
}
}
/// Stack call representations corresponding to the different types of [`AppInstruction`]s.
/// Stack call representations corresponding to the different types of [`ServerInstruction`]s.
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub enum ServerContext {
OpenFile,

View File

@ -42,6 +42,8 @@ use wasmer::{ChainableNamedResolver, Instance, Module, Store, Value};
use wasmer_wasi::{Pipe, WasiState};
use zellij_tile::data::{EventType, InputMode, ModeInfo};
pub const IPC_BUFFER_SIZE: u32 = 8192;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ServerInstruction {
OpenFile(PathBuf),
@ -205,7 +207,7 @@ pub fn start(
opts: CliArgs,
server_os_input: Box<dyn ServerOsApi>,
) {
let (ipc_thread, server_name) = start_server(server_os_input.clone(), opts.clone());
let ipc_thread = start_server(server_os_input.clone(), opts.clone());
let take_snapshot = "\u{1b}[?1049h";
os_input.unset_raw_mode(0);
@ -235,9 +237,9 @@ pub fn start(
let mut send_app_instructions =
SenderWithContext::new(err_ctx, SenderType::SyncSender(send_app_instructions));
let (client_buffer_path, client_buffer) = SharedRingBuffer::create_temp(8192).unwrap();
let mut send_server_instructions =
IpcSenderWithContext::new(SharedRingBuffer::open(&server_name).unwrap());
let (client_buffer_path, client_buffer) =
SharedRingBuffer::create_temp(IPC_BUFFER_SIZE).unwrap();
let mut send_server_instructions = os_input.get_server_sender().unwrap();
send_server_instructions
.send(ServerInstruction::NewClient(client_buffer_path))
.unwrap();

View File

@ -1,5 +1,7 @@
use crate::common::{IpcSenderWithContext, IPC_BUFFER_SIZE};
use crate::panes::PositionAndSize;
use crate::utils::shared::default_palette;
use crate::utils::consts::ZELLIJ_IPC_PIPE;
use ipmpsc::{Receiver as IpcReceiver, Result as IpcResult, SharedRingBuffer};
use nix::fcntl::{fcntl, FcntlArg, OFlag};
use nix::pty::{forkpty, Winsize};
use nix::sys::signal::{kill, Signal};
@ -8,6 +10,7 @@ use nix::sys::wait::waitpid;
use nix::unistd;
use nix::unistd::{ForkResult, Pid};
use serde::{Deserialize, Serialize};
use std::env;
use std::io;
use std::io::prelude::*;
use std::os::unix::io::RawFd;
@ -15,10 +18,6 @@ use std::path::PathBuf;
use std::process::{Child, Command};
use std::sync::{Arc, Mutex};
use signal_hook::{consts::signal::*, iterator::Signals};
use std::env;
fn into_raw_mode(pid: RawFd) {
let mut tio = termios::tcgetattr(pid).expect("could not get terminal attribute");
termios::cfmakeraw(&mut tio);
@ -158,6 +157,7 @@ fn spawn_terminal(file_to_open: Option<PathBuf>, orig_termios: termios::Termios)
#[derive(Clone)]
pub struct ServerOsInputOutput {
orig_termios: Arc<Mutex<termios::Termios>>,
server_buffer: SharedRingBuffer,
}
/// The `ServerOsApi` trait represents an abstract interface to the features of an operating system that
@ -180,6 +180,8 @@ pub trait ServerOsApi: Send + Sync {
fn kill(&mut self, pid: RawFd) -> Result<(), nix::Error>;
/// Returns a [`Box`] pointer to this [`OsApi`] struct.
fn box_clone(&self) -> Box<dyn ServerOsApi>;
fn get_server_receiver(&self) -> IpcReceiver;
fn get_server_sender(&self) -> IpcSenderWithContext;
}
impl ServerOsApi for ServerOsInputOutput {
@ -207,6 +209,12 @@ impl ServerOsApi for ServerOsInputOutput {
waitpid(Pid::from_raw(pid), None).unwrap();
Ok(())
}
fn get_server_receiver(&self) -> IpcReceiver {
IpcReceiver::new(self.server_buffer.clone())
}
fn get_server_sender(&self) -> IpcSenderWithContext {
IpcSenderWithContext::new(self.server_buffer.clone())
}
}
impl Clone for Box<dyn ServerOsApi> {
@ -218,9 +226,14 @@ impl Clone for Box<dyn ServerOsApi> {
pub fn get_server_os_input() -> ServerOsInputOutput {
let current_termios = termios::tcgetattr(0).unwrap();
let orig_termios = Arc::new(Mutex::new(current_termios));
ServerOsInputOutput { orig_termios }
let server_buffer = SharedRingBuffer::create(ZELLIJ_IPC_PIPE, IPC_BUFFER_SIZE).unwrap();
ServerOsInputOutput {
orig_termios,
server_buffer,
}
}
/// OS Instructions sent to the Server by clients
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ServerOsApiInstruction {
SetTerminalSizeUsingFd(RawFd, u16, u16),
@ -251,6 +264,7 @@ pub trait ClientOsApi: Send + Sync {
fn read_from_stdin(&self) -> Vec<u8>;
/// Returns a [`Box`] pointer to this [`OsApi`] struct.
fn box_clone(&self) -> Box<dyn ClientOsApi>;
fn get_server_sender(&self) -> IpcResult<IpcSenderWithContext>;
}
impl ClientOsApi for ClientOsInputOutput {
@ -280,6 +294,10 @@ impl ClientOsApi for ClientOsInputOutput {
let stdout = ::std::io::stdout();
Box::new(stdout)
}
fn get_server_sender(&self) -> IpcResult<IpcSenderWithContext> {
let buffer = SharedRingBuffer::open(ZELLIJ_IPC_PIPE)?;
Ok(IpcSenderWithContext::new(buffer))
}
}
impl Clone for Box<dyn ClientOsApi> {

View File

@ -87,8 +87,8 @@ pub fn main() {
.send(ServerInstruction::OpenFile(file_to_open))
.unwrap();
} else {
let os_input = get_client_os_input();
let server_os_input = get_server_os_input();
let os_input = get_client_os_input();
atomic_create_dir(ZELLIJ_TMP_DIR).unwrap();
atomic_create_dir(ZELLIJ_TMP_LOG_DIR).unwrap();
start(Box::new(os_input), opts, Box::new(server_os_input));

View File

@ -8,16 +8,12 @@ use crate::os_input_output::{ServerOsApi, ServerOsApiInstruction};
use crate::panes::PaneId;
use crate::pty_bus::{PtyBus, PtyInstruction};
use crate::screen::ScreenInstruction;
use crate::utils::consts::ZELLIJ_IPC_PIPE;
use ipmpsc::{Receiver as IpcReceiver, SharedRingBuffer};
use ipmpsc::SharedRingBuffer;
use std::path::PathBuf;
use std::sync::mpsc::channel;
use std::thread;
pub fn start_server(
os_input: Box<dyn ServerOsApi>,
opts: CliArgs,
) -> (thread::JoinHandle<()>, String) {
pub fn start_server(os_input: Box<dyn ServerOsApi>, opts: CliArgs) -> thread::JoinHandle<()> {
let (send_pty_instructions, receive_pty_instructions): ChannelWithContext<PtyInstruction> =
channel();
let mut send_pty_instructions = SenderWithContext::new(
@ -25,14 +21,6 @@ pub fn start_server(
SenderType::Sender(send_pty_instructions),
);
#[cfg(not(test))]
let (server_name, server_buffer) = (
String::from(ZELLIJ_IPC_PIPE),
SharedRingBuffer::create(ZELLIJ_IPC_PIPE, 8192).unwrap(),
);
#[cfg(test)]
let (server_name, server_buffer) = SharedRingBuffer::create_temp(8192).unwrap();
let (send_os_instructions, receive_os_instructions): ChannelWithContext<
ServerOsApiInstruction,
> = channel();
@ -48,7 +36,7 @@ pub fn start_server(
let default_layout = None;
let maybe_layout = opts.layout.or(default_layout);
let send_server_instructions = IpcSenderWithContext::new(server_buffer.clone());
let send_server_instructions = os_input.get_server_sender();
let mut pty_bus = PtyBus::new(
receive_pty_instructions,
@ -151,10 +139,10 @@ pub fn start_server(
})
.unwrap();
let server_handle = thread::Builder::new()
thread::Builder::new()
.name("ipc_server".to_string())
.spawn({
let recv_server_instructions = IpcReceiver::new(server_buffer);
let recv_server_instructions = os_input.get_server_receiver();
// Fixme: We cannot use uninitialised sender, therefore this Vec.
// For now, We make sure that the first message is `NewClient` so there are no out of bound panics.
let mut send_client_instructions: Vec<IpcSenderWithContext> = Vec::with_capacity(1);
@ -228,6 +216,5 @@ pub fn start_server(
}
}
})
.unwrap();
(server_handle, server_name)
.unwrap()
}

View File

@ -1,4 +1,5 @@
use crate::panes::PositionAndSize;
use ipmpsc::{Receiver as IpcReceiver, Result as IpcResult, SharedRingBuffer};
use std::collections::{HashMap, VecDeque};
use std::io::Write;
use std::os::unix::io::RawFd;
@ -6,6 +7,7 @@ use std::path::PathBuf;
use std::sync::{Arc, Condvar, Mutex};
use std::time::{Duration, Instant};
use crate::common::{IpcSenderWithContext, IPC_BUFFER_SIZE};
use crate::os_input_output::{ClientOsApi, ServerOsApi};
use crate::tests::possible_tty_inputs::{get_possible_tty_inputs, Bytes};
use crate::utils::shared::default_palette;
@ -73,8 +75,8 @@ pub struct FakeInputOutput {
win_sizes: Arc<Mutex<HashMap<RawFd, PositionAndSize>>>,
possible_tty_inputs: HashMap<u16, Bytes>,
last_snapshot_time: Arc<Mutex<Instant>>,
should_trigger_sigwinch: Arc<(Mutex<bool>, Condvar)>,
sigwinch_event: Option<PositionAndSize>,
started_reading_from_pty: Arc<AtomicBool>,
server_buffer: SharedRingBuffer,
}
impl FakeInputOutput {
@ -82,7 +84,9 @@ impl FakeInputOutput {
let mut win_sizes = HashMap::new();
let last_snapshot_time = Arc::new(Mutex::new(Instant::now()));
let stdout_writer = FakeStdoutWriter::new(last_snapshot_time.clone());
let (_, server_buffer) = SharedRingBuffer::create_temp(IPC_BUFFER_SIZE).unwrap();
win_sizes.insert(0, winsize); // 0 is the current terminal
FakeInputOutput {
read_buffers: Arc::new(Mutex::new(HashMap::new())),
stdin_writes: Arc::new(Mutex::new(HashMap::new())),
@ -93,8 +97,8 @@ impl FakeInputOutput {
io_events: Arc::new(Mutex::new(vec![])),
win_sizes: Arc::new(Mutex::new(win_sizes)),
possible_tty_inputs: get_possible_tty_inputs(),
should_trigger_sigwinch: Arc::new((Mutex::new(false), Condvar::new())),
sigwinch_event: None,
started_reading_from_pty: Arc::new(AtomicBool::new(false)),
server_buffer,
}
}
pub fn with_tty_inputs(mut self, tty_inputs: HashMap<u16, Bytes>) -> Self {
@ -162,6 +166,9 @@ impl ClientOsApi for FakeInputOutput {
fn get_stdout_writer(&self) -> Box<dyn Write> {
Box::new(self.stdout_writer.clone())
}
fn get_server_sender(&self) -> IpcResult<IpcSenderWithContext> {
Ok(IpcSenderWithContext::new(self.server_buffer.clone()))
}
}
impl ServerOsApi for FakeInputOutput {
@ -222,15 +229,11 @@ impl ServerOsApi for FakeInputOutput {
self.io_events.lock().unwrap().push(IoEvent::Kill(fd));
Ok(())
}
fn receive_sigwinch(&self, cb: Box<dyn Fn()>) {
if self.sigwinch_event.is_some() {
let (lock, cvar) = &*self.should_trigger_sigwinch;
let mut should_trigger_sigwinch = lock.lock().unwrap();
while !*should_trigger_sigwinch {
should_trigger_sigwinch = cvar.wait(should_trigger_sigwinch).unwrap();
}
cb();
}
fn get_server_receiver(&self) -> IpcReceiver {
IpcReceiver::new(self.server_buffer.clone())
}
fn get_server_sender(&self) -> IpcSenderWithContext {
IpcSenderWithContext::new(self.server_buffer.clone())
}
fn load_palette(&self) -> Palette {
default_palette()