Use interprocess crate for IPC
This commit is contained in:
parent
9fc1f0038e
commit
b7aa3fc21a
8 changed files with 217 additions and 329 deletions
179
Cargo.lock
generated
179
Cargo.lock
generated
|
|
@ -234,15 +234,6 @@ dependencies = [
|
|||
"wyz",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.0.2"
|
||||
|
|
@ -293,19 +284,6 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.33.3"
|
||||
|
|
@ -354,12 +332,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpuid-bool"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.68.0"
|
||||
|
|
@ -524,15 +496,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "directories-next"
|
||||
version = "2.0.0"
|
||||
|
|
@ -752,16 +715,6 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "generic-array"
|
||||
version = "0.14.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"
|
||||
dependencies = [
|
||||
"typenum",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getopts"
|
||||
version = "0.2.21"
|
||||
|
|
@ -847,12 +800,6 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
|
@ -939,24 +886,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipmpsc"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e36cf1ebb87bae3dbbf0a91b80463831de213b2921f28c325b22026f318f17a3"
|
||||
dependencies = [
|
||||
"bincode",
|
||||
"hex",
|
||||
"libc",
|
||||
"memmap",
|
||||
"serde",
|
||||
"sha2",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"vergen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
|
|
@ -1062,16 +991,6 @@ version = "2.3.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||
|
||||
[[package]]
|
||||
name = "memmap"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memmap2"
|
||||
version = "0.2.2"
|
||||
|
|
@ -1141,25 +1060,6 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.13.0"
|
||||
|
|
@ -1198,27 +1098,12 @@ version = "1.7.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3"
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
|
||||
dependencies = [
|
||||
"ucd-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.6"
|
||||
|
|
@ -1457,15 +1342,6 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
|
||||
dependencies = [
|
||||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
|
|
@ -1478,24 +1354,6 @@ version = "1.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
|
||||
dependencies = [
|
||||
"semver-parser",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
|
||||
dependencies = [
|
||||
"pest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.125"
|
||||
|
|
@ -1548,19 +1406,6 @@ dependencies = [
|
|||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa827a14b29ab7f44778d14a88d3cb76e949c45083f7dbfa507d0cb699dc12de"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"cfg-if 1.0.0",
|
||||
"cpuid-bool",
|
||||
"digest",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.8"
|
||||
|
|
@ -1861,12 +1706,6 @@ dependencies = [
|
|||
"lazy_static",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
||||
|
||||
[[package]]
|
||||
name = "typetag"
|
||||
version = "0.1.7"
|
||||
|
|
@ -1891,12 +1730,6 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ucd-trie"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.7.1"
|
||||
|
|
@ -1963,17 +1796,6 @@ version = "0.8.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "vergen"
|
||||
version = "3.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"chrono",
|
||||
"rustc_version",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.3"
|
||||
|
|
@ -2384,7 +2206,6 @@ dependencies = [
|
|||
"futures",
|
||||
"insta",
|
||||
"interprocess",
|
||||
"ipmpsc",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"nix",
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ backtrace = "0.3.55"
|
|||
bincode = "1.3.1"
|
||||
directories-next = "2.0"
|
||||
futures = "0.3.5"
|
||||
ipmpsc = "0.5.0"
|
||||
libc = "0.2"
|
||||
nix = "0.19.1"
|
||||
nom = "6.0.1"
|
||||
|
|
@ -36,7 +35,7 @@ strum = "0.20.0"
|
|||
lazy_static = "1.4.0"
|
||||
wasmer = "1.0.0"
|
||||
wasmer-wasi = "1.0.0"
|
||||
interprocess = "1.0.1"
|
||||
interprocess = "1.1.1"
|
||||
zellij-tile = { path = "zellij-tile/", version = "0.5.0" }
|
||||
|
||||
[dependencies.async-std]
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs) {
|
|||
let mut command_is_executing = CommandIsExecuting::new();
|
||||
|
||||
let full_screen_ws = os_input.get_terminal_size_using_fd(0);
|
||||
os_input.connect_to_server();
|
||||
os_input.send_to_server(ServerInstruction::NewClient(full_screen_ws));
|
||||
os_input.set_raw_mode(0);
|
||||
|
||||
let (send_client_instructions, receive_client_instructions): SyncChannelWithContext<
|
||||
|
|
@ -57,8 +59,6 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs) {
|
|||
let send_client_instructions =
|
||||
SenderWithContext::new(SenderType::SyncSender(send_client_instructions));
|
||||
|
||||
os_input.connect_to_server(full_screen_ws);
|
||||
|
||||
#[cfg(not(test))]
|
||||
std::panic::set_hook({
|
||||
use crate::errors::handle_panic;
|
||||
|
|
|
|||
|
|
@ -357,7 +357,6 @@ pub enum ServerContext {
|
|||
DoneOpeningNewPane,
|
||||
DoneUpdatingTabs,
|
||||
ClientExit,
|
||||
Exit,
|
||||
}
|
||||
|
||||
impl From<&ServerInstruction> for ServerContext {
|
||||
|
|
@ -375,7 +374,6 @@ impl From<&ServerInstruction> for ServerContext {
|
|||
ServerInstruction::DoneOpeningNewPane => ServerContext::DoneOpeningNewPane,
|
||||
ServerInstruction::DoneUpdatingTabs => ServerContext::DoneUpdatingTabs,
|
||||
ServerInstruction::ClientExit => ServerContext::ClientExit,
|
||||
ServerInstruction::Exit => ServerContext::Exit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,18 +1,17 @@
|
|||
use ipmpsc::{Receiver as IpcReceiver, Sender as IpcSender, SharedRingBuffer};
|
||||
use interprocess::local_socket::LocalSocketStream;
|
||||
use nix::fcntl::{fcntl, FcntlArg, OFlag};
|
||||
use nix::pty::{forkpty, Winsize};
|
||||
use nix::sys::signal::{kill, Signal};
|
||||
use nix::sys::termios;
|
||||
use nix::sys::wait::waitpid;
|
||||
use nix::unistd;
|
||||
use nix::unistd::{ForkResult, Pid};
|
||||
use nix::unistd::{self, ForkResult, Pid};
|
||||
use serde::Serialize;
|
||||
use signal_hook::{consts::signal::*, iterator::Signals};
|
||||
use std::env;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::marker::PhantomData;
|
||||
use std::os::unix::io::RawFd;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Child, Command};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
|
@ -23,7 +22,7 @@ use crate::panes::PositionAndSize;
|
|||
use crate::server::ServerInstruction;
|
||||
use crate::utils::consts::ZELLIJ_IPC_PIPE;
|
||||
|
||||
const IPC_BUFFER_SIZE: u32 = 8388608;
|
||||
const IPC_BUFFER_SIZE: usize = 262144;
|
||||
|
||||
fn into_raw_mode(pid: RawFd) {
|
||||
let mut tio = termios::tcgetattr(pid).expect("could not get terminal attribute");
|
||||
|
|
@ -162,35 +161,34 @@ fn spawn_terminal(file_to_open: Option<PathBuf>, orig_termios: termios::Termios)
|
|||
}
|
||||
|
||||
/// Sends messages on an [ipmpsc](ipmpsc) channel, along with an [`ErrorContext`].
|
||||
#[derive(Clone)]
|
||||
struct IpcSenderWithContext<T: Serialize> {
|
||||
sender: IpcSender,
|
||||
sender: LocalSocketStream,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: Serialize> IpcSenderWithContext<T> {
|
||||
/// Returns a sender to the given [SharedRingBuffer](ipmpsc::SharedRingBuffer).
|
||||
fn new(buffer: SharedRingBuffer) -> Self {
|
||||
fn new(sender: LocalSocketStream) -> Self {
|
||||
Self {
|
||||
sender: IpcSender::new(buffer),
|
||||
sender,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends an event, along with the current [`ErrorContext`], on this
|
||||
/// [`IpcSenderWithContext`]'s channel.
|
||||
fn send(&self, msg: T) -> ipmpsc::Result<()> {
|
||||
fn send(&mut self, msg: T) -> Result<(), std::io::Error> {
|
||||
let err_ctx = get_current_ctx();
|
||||
self.sender.send(&(msg, err_ctx))
|
||||
self.sender
|
||||
.write_all(&bincode::serialize(&(msg, err_ctx)).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ServerOsInputOutput {
|
||||
orig_termios: Arc<Mutex<termios::Termios>>,
|
||||
server_sender: IpcSenderWithContext<ServerInstruction>,
|
||||
server_receiver: Arc<IpcReceiver>, // Should this be Arc<Mutex<_>> ?
|
||||
client_sender: Option<IpcSenderWithContext<ClientInstruction>>,
|
||||
recv_socket: Option<Arc<Mutex<LocalSocketStream>>>,
|
||||
sender_socket: Arc<Mutex<Option<IpcSenderWithContext<ClientInstruction>>>>,
|
||||
}
|
||||
|
||||
/// The `ServerOsApi` trait represents an abstract interface to the features of an operating system that
|
||||
|
|
@ -213,14 +211,14 @@ pub trait ServerOsApi: Send + Sync {
|
|||
fn kill(&mut self, pid: RawFd) -> Result<(), nix::Error>;
|
||||
/// Returns a [`Box`] pointer to this [`ServerOsApi`] struct.
|
||||
fn box_clone(&self) -> Box<dyn ServerOsApi>;
|
||||
/// Sends an `Exit` message to the server router thread.
|
||||
fn server_exit(&mut self);
|
||||
/// Receives a message on server-side IPC channel
|
||||
fn server_recv(&self) -> (ServerInstruction, ErrorContext);
|
||||
/// Sends a message to client
|
||||
fn send_to_client(&self, msg: ClientInstruction);
|
||||
/// Adds a sender to client
|
||||
fn add_client_sender(&mut self, buffer_path: String);
|
||||
fn add_client_sender(&mut self);
|
||||
/// Update the receiver socket for the client
|
||||
fn update_receiver(&mut self, stream: LocalSocketStream);
|
||||
}
|
||||
|
||||
impl ServerOsApi for ServerOsInputOutput {
|
||||
|
|
@ -254,18 +252,42 @@ impl ServerOsApi for ServerOsInputOutput {
|
|||
waitpid(Pid::from_raw(pid), None).unwrap();
|
||||
Ok(())
|
||||
}
|
||||
fn server_exit(&mut self) {
|
||||
self.server_sender.send(ServerInstruction::Exit).unwrap();
|
||||
}
|
||||
fn server_recv(&self) -> (ServerInstruction, ErrorContext) {
|
||||
self.server_receiver.recv().unwrap()
|
||||
let mut buf = [0; IPC_BUFFER_SIZE];
|
||||
let bytes = self
|
||||
.recv_socket
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.read(&mut buf)
|
||||
.unwrap();
|
||||
bincode::deserialize(&buf[..bytes]).unwrap()
|
||||
}
|
||||
fn send_to_client(&self, msg: ClientInstruction) {
|
||||
self.client_sender.as_ref().unwrap().send(msg).unwrap();
|
||||
self.sender_socket
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(msg)
|
||||
.unwrap();
|
||||
}
|
||||
fn add_client_sender(&mut self, buffer_path: String) {
|
||||
let buffer = SharedRingBuffer::open(buffer_path.as_str()).unwrap();
|
||||
self.client_sender = Some(IpcSenderWithContext::new(buffer));
|
||||
fn add_client_sender(&mut self) {
|
||||
assert!(self.sender_socket.lock().unwrap().is_none());
|
||||
let sock_fd = self
|
||||
.recv_socket
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_raw_fd();
|
||||
let dup_fd = unistd::dup(sock_fd).unwrap();
|
||||
let dup_sock = unsafe { LocalSocketStream::from_raw_fd(dup_fd) };
|
||||
*self.sender_socket.lock().unwrap() = Some(IpcSenderWithContext::new(dup_sock));
|
||||
}
|
||||
fn update_receiver(&mut self, stream: LocalSocketStream) {
|
||||
self.recv_socket = Some(Arc::new(Mutex::new(stream)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,22 +300,18 @@ 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));
|
||||
let server_buffer = SharedRingBuffer::create(ZELLIJ_IPC_PIPE, IPC_BUFFER_SIZE).unwrap();
|
||||
let server_sender = IpcSenderWithContext::new(server_buffer.clone());
|
||||
let server_receiver = Arc::new(IpcReceiver::new(server_buffer));
|
||||
ServerOsInputOutput {
|
||||
orig_termios,
|
||||
server_sender,
|
||||
server_receiver,
|
||||
client_sender: None,
|
||||
recv_socket: None,
|
||||
sender_socket: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ClientOsInputOutput {
|
||||
orig_termios: Arc<Mutex<termios::Termios>>,
|
||||
server_sender: IpcSenderWithContext<ServerInstruction>,
|
||||
client_receiver: Option<Arc<IpcReceiver>>, // Should this be Option<Arc<Mutex<_>>> ?
|
||||
server_sender: Arc<Mutex<Option<IpcSenderWithContext<ServerInstruction>>>>,
|
||||
receiver: Arc<Mutex<Option<LocalSocketStream>>>,
|
||||
}
|
||||
|
||||
/// The `ClientOsApi` trait represents an abstract interface to the features of an operating system that
|
||||
|
|
@ -318,9 +336,9 @@ pub trait ClientOsApi: Send + Sync {
|
|||
/// Receives a message on client-side IPC channel
|
||||
// This should be called from the client-side router thread only.
|
||||
fn client_recv(&self) -> (ClientInstruction, ErrorContext);
|
||||
/// Setup the client IpcChannel and notify server of new client
|
||||
fn connect_to_server(&mut self, full_screen_ws: PositionAndSize);
|
||||
fn receive_sigwinch(&self, cb: Box<dyn Fn()>);
|
||||
/// Establish a connection with the server socket.
|
||||
fn connect_to_server(&self);
|
||||
}
|
||||
|
||||
impl ClientOsApi for ClientOsInputOutput {
|
||||
|
|
@ -351,19 +369,25 @@ impl ClientOsApi for ClientOsInputOutput {
|
|||
Box::new(stdout)
|
||||
}
|
||||
fn send_to_server(&self, msg: ServerInstruction) {
|
||||
self.server_sender.send(msg).unwrap();
|
||||
}
|
||||
fn connect_to_server(&mut self, full_screen_ws: PositionAndSize) {
|
||||
let (client_buffer_path, client_buffer) =
|
||||
SharedRingBuffer::create_temp(IPC_BUFFER_SIZE).unwrap();
|
||||
self.client_receiver = Some(Arc::new(IpcReceiver::new(client_buffer)));
|
||||
self.send_to_server(ServerInstruction::NewClient(
|
||||
client_buffer_path,
|
||||
full_screen_ws,
|
||||
));
|
||||
self.server_sender
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(msg)
|
||||
.unwrap();
|
||||
}
|
||||
fn client_recv(&self) -> (ClientInstruction, ErrorContext) {
|
||||
self.client_receiver.as_ref().unwrap().recv().unwrap()
|
||||
let mut buf = [0; IPC_BUFFER_SIZE];
|
||||
let bytes = self
|
||||
.receiver
|
||||
.lock()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.read(&mut buf)
|
||||
.unwrap();
|
||||
bincode::deserialize(&buf[..bytes]).unwrap()
|
||||
}
|
||||
fn receive_sigwinch(&self, cb: Box<dyn Fn()>) {
|
||||
let mut signals = Signals::new(&[SIGWINCH, SIGTERM, SIGINT, SIGQUIT]).unwrap();
|
||||
|
|
@ -379,6 +403,15 @@ impl ClientOsApi for ClientOsInputOutput {
|
|||
}
|
||||
}
|
||||
}
|
||||
fn connect_to_server(&self) {
|
||||
let socket = LocalSocketStream::connect(ZELLIJ_IPC_PIPE).unwrap();
|
||||
let sock_fd = socket.as_raw_fd();
|
||||
let dup_fd = unistd::dup(sock_fd).unwrap();
|
||||
let receiver = unsafe { LocalSocketStream::from_raw_fd(dup_fd) };
|
||||
let sender = IpcSenderWithContext::new(socket);
|
||||
*self.server_sender.lock().unwrap() = Some(sender);
|
||||
*self.receiver.lock().unwrap() = Some(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Box<dyn ClientOsApi> {
|
||||
|
|
@ -390,11 +423,9 @@ impl Clone for Box<dyn ClientOsApi> {
|
|||
pub fn get_client_os_input() -> ClientOsInputOutput {
|
||||
let current_termios = termios::tcgetattr(0).unwrap();
|
||||
let orig_termios = Arc::new(Mutex::new(current_termios));
|
||||
let server_buffer = SharedRingBuffer::open(ZELLIJ_IPC_PIPE).unwrap();
|
||||
let server_sender = IpcSenderWithContext::new(server_buffer);
|
||||
ClientOsInputOutput {
|
||||
orig_termios,
|
||||
server_sender,
|
||||
client_receiver: None,
|
||||
server_sender: Arc::new(Mutex::new(None)),
|
||||
receiver: Arc::new(Mutex::new(None)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
23
src/main.rs
23
src/main.rs
|
|
@ -60,23 +60,30 @@ pub fn main() {
|
|||
if let Some(split_dir) = opts.split {
|
||||
match split_dir {
|
||||
'h' => {
|
||||
get_client_os_input().send_to_server(ServerInstruction::SplitHorizontally);
|
||||
let os_input = get_client_os_input();
|
||||
os_input.connect_to_server();
|
||||
os_input.send_to_server(ServerInstruction::SplitHorizontally);
|
||||
}
|
||||
'v' => {
|
||||
get_client_os_input().send_to_server(ServerInstruction::SplitVertically);
|
||||
let os_input = get_client_os_input();
|
||||
os_input.connect_to_server();
|
||||
os_input.send_to_server(ServerInstruction::SplitVertically);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
} else if opts.move_focus {
|
||||
get_client_os_input().send_to_server(ServerInstruction::MoveFocus);
|
||||
} else if let Some(file_to_open) = opts.open_file {
|
||||
get_client_os_input().send_to_server(ServerInstruction::OpenFile(file_to_open));
|
||||
} else {
|
||||
// Mind the order: server_os_input should be created before client_os_input
|
||||
let server_os_input = get_server_os_input();
|
||||
let os_input = get_client_os_input();
|
||||
os_input.connect_to_server();
|
||||
os_input.send_to_server(ServerInstruction::MoveFocus);
|
||||
} else if let Some(file_to_open) = opts.open_file {
|
||||
let os_input = get_client_os_input();
|
||||
os_input.connect_to_server();
|
||||
os_input.send_to_server(ServerInstruction::OpenFile(file_to_open));
|
||||
} else {
|
||||
atomic_create_dir(ZELLIJ_TMP_DIR).unwrap();
|
||||
atomic_create_dir(ZELLIJ_TMP_LOG_DIR).unwrap();
|
||||
let server_os_input = get_server_os_input();
|
||||
let os_input = get_client_os_input();
|
||||
start(Box::new(os_input), opts, Box::new(server_os_input));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use directories_next::ProjectDirs;
|
||||
use interprocess::local_socket::LocalSocketListener;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc::channel;
|
||||
|
|
@ -28,6 +29,7 @@ use crate::common::{
|
|||
use crate::layout::Layout;
|
||||
use crate::panes::PaneId;
|
||||
use crate::panes::PositionAndSize;
|
||||
use crate::utils::consts::ZELLIJ_IPC_PIPE;
|
||||
|
||||
/// Instructions related to server-side application including the
|
||||
/// ones sent by client to server
|
||||
|
|
@ -38,15 +40,13 @@ pub enum ServerInstruction {
|
|||
SplitVertically,
|
||||
MoveFocus,
|
||||
TerminalResize(PositionAndSize),
|
||||
NewClient(String, PositionAndSize),
|
||||
NewClient(PositionAndSize),
|
||||
Action(Action),
|
||||
Render(Option<String>),
|
||||
DoneClosingPane,
|
||||
DoneOpeningNewPane,
|
||||
DoneUpdatingTabs,
|
||||
ClientExit,
|
||||
// notify router thread to exit
|
||||
Exit,
|
||||
}
|
||||
|
||||
struct SessionMetaData {
|
||||
|
|
@ -69,71 +69,44 @@ impl Drop for SessionMetaData {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn start_server(mut os_input: Box<dyn ServerOsApi>, opts: CliArgs) -> thread::JoinHandle<()> {
|
||||
pub fn start_server(os_input: Box<dyn ServerOsApi>, opts: CliArgs) -> thread::JoinHandle<()> {
|
||||
let (send_server_instructions, receive_server_instructions): ChannelWithContext<
|
||||
ServerInstruction,
|
||||
> = channel();
|
||||
let send_server_instructions =
|
||||
SenderWithContext::new(SenderType::Sender(send_server_instructions));
|
||||
let sessions: Arc<RwLock<Option<SessionMetaData>>> = Arc::new(RwLock::new(None));
|
||||
|
||||
let sessions: Arc<RwLock<HashMap<String, SessionMetaData>>> =
|
||||
Arc::new(RwLock::new(HashMap::new()));
|
||||
// We handle only single client for now
|
||||
let session: Arc<RwLock<String>> = Arc::new(RwLock::new("session1".into()));
|
||||
let router_thread = thread::Builder::new()
|
||||
.name("server_router".to_string())
|
||||
.spawn({
|
||||
let os_input = os_input.clone();
|
||||
let session = session.clone();
|
||||
let sessions = sessions.clone();
|
||||
let send_server_instructions = send_server_instructions.clone();
|
||||
move || loop {
|
||||
let (instruction, mut err_ctx) = os_input.server_recv();
|
||||
err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction)));
|
||||
let rlocked_session = &*session.read().unwrap();
|
||||
let rlocked_sessions = sessions.read().unwrap();
|
||||
match instruction {
|
||||
ServerInstruction::Exit => break,
|
||||
ServerInstruction::OpenFile(file_name) => {
|
||||
rlocked_sessions[rlocked_session]
|
||||
.send_pty_instructions
|
||||
.send(PtyInstruction::SpawnTerminal(Some(file_name)))
|
||||
.unwrap();
|
||||
#[cfg(test)]
|
||||
handle_client(
|
||||
sessions.clone(),
|
||||
os_input.clone(),
|
||||
send_server_instructions.clone(),
|
||||
);
|
||||
#[cfg(not(test))]
|
||||
let _ = thread::Builder::new().name("listener".to_string()).spawn({
|
||||
let os_input = os_input.clone();
|
||||
let sessions = sessions.clone();
|
||||
let send_server_instructions = send_server_instructions.clone();
|
||||
move || {
|
||||
drop(std::fs::remove_file(ZELLIJ_IPC_PIPE));
|
||||
let listener = LocalSocketListener::bind(ZELLIJ_IPC_PIPE).unwrap();
|
||||
for stream in listener.incoming() {
|
||||
match stream {
|
||||
Ok(stream) => {
|
||||
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);
|
||||
}
|
||||
ServerInstruction::SplitHorizontally => {
|
||||
rlocked_sessions[rlocked_session]
|
||||
.send_pty_instructions
|
||||
.send(PtyInstruction::SpawnTerminalHorizontally(None))
|
||||
.unwrap();
|
||||
}
|
||||
ServerInstruction::SplitVertically => {
|
||||
rlocked_sessions[rlocked_session]
|
||||
.send_pty_instructions
|
||||
.send(PtyInstruction::SpawnTerminalVertically(None))
|
||||
.unwrap();
|
||||
}
|
||||
ServerInstruction::MoveFocus => {
|
||||
rlocked_sessions[rlocked_session]
|
||||
.send_screen_instructions
|
||||
.send(ScreenInstruction::FocusNextPane)
|
||||
.unwrap();
|
||||
}
|
||||
ServerInstruction::Action(action) => {
|
||||
route_action(action, &rlocked_sessions[rlocked_session]);
|
||||
}
|
||||
ServerInstruction::TerminalResize(new_size) => {
|
||||
rlocked_sessions[rlocked_session]
|
||||
.send_screen_instructions
|
||||
.send(ScreenInstruction::TerminalResize(new_size))
|
||||
.unwrap();
|
||||
}
|
||||
_ => {
|
||||
send_server_instructions.send(instruction).unwrap();
|
||||
Err(err) => {
|
||||
panic!("err {:?}", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
});
|
||||
|
||||
thread::Builder::new()
|
||||
.name("ipc_server".to_string())
|
||||
|
|
@ -142,24 +115,22 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, opts: CliArgs) -> thread
|
|||
let (instruction, mut err_ctx) = receive_server_instructions.recv().unwrap();
|
||||
err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction)));
|
||||
match instruction {
|
||||
ServerInstruction::NewClient(buffer_path, full_screen_ws) => {
|
||||
ServerInstruction::NewClient(full_screen_ws) => {
|
||||
let session_data = init_session(
|
||||
os_input.clone(),
|
||||
opts.clone(),
|
||||
send_server_instructions.clone(),
|
||||
full_screen_ws,
|
||||
);
|
||||
drop(
|
||||
sessions
|
||||
.write()
|
||||
.unwrap()
|
||||
.insert(session.read().unwrap().clone(), session_data),
|
||||
);
|
||||
sessions.read().unwrap()[&*session.read().unwrap()]
|
||||
*sessions.write().unwrap() = Some(session_data);
|
||||
sessions
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send_pty_instructions
|
||||
.send(PtyInstruction::NewTab)
|
||||
.unwrap();
|
||||
os_input.add_client_sender(buffer_path);
|
||||
}
|
||||
ServerInstruction::DoneClosingPane => {
|
||||
os_input.send_to_client(ClientInstruction::DoneClosingPane);
|
||||
|
|
@ -171,16 +142,8 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, opts: CliArgs) -> thread
|
|||
os_input.send_to_client(ClientInstruction::DoneUpdatingTabs);
|
||||
}
|
||||
ServerInstruction::ClientExit => {
|
||||
drop(
|
||||
sessions
|
||||
.write()
|
||||
.unwrap()
|
||||
.remove(&*session.read().unwrap())
|
||||
.unwrap(),
|
||||
);
|
||||
*sessions.write().unwrap() = None;
|
||||
os_input.send_to_client(ClientInstruction::Exit);
|
||||
os_input.server_exit();
|
||||
let _ = router_thread.join();
|
||||
break;
|
||||
}
|
||||
ServerInstruction::Render(output) => {
|
||||
|
|
@ -193,6 +156,81 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, opts: CliArgs) -> thread
|
|||
.unwrap()
|
||||
}
|
||||
|
||||
fn handle_client(
|
||||
sessions: Arc<RwLock<Option<SessionMetaData>>>,
|
||||
mut os_input: Box<dyn ServerOsApi>,
|
||||
send_server_instructions: SenderWithContext<ServerInstruction>,
|
||||
) {
|
||||
thread::Builder::new()
|
||||
.name("router".to_string())
|
||||
.spawn(move || loop {
|
||||
let (instruction, mut err_ctx) = os_input.server_recv();
|
||||
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::OpenFile(file_name) => {
|
||||
rlocked_sessions
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send_pty_instructions
|
||||
.send(PtyInstruction::SpawnTerminal(Some(file_name)))
|
||||
.unwrap();
|
||||
break;
|
||||
}
|
||||
ServerInstruction::SplitHorizontally => {
|
||||
rlocked_sessions
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send_pty_instructions
|
||||
.send(PtyInstruction::SpawnTerminalHorizontally(None))
|
||||
.unwrap();
|
||||
break;
|
||||
}
|
||||
ServerInstruction::SplitVertically => {
|
||||
rlocked_sessions
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send_pty_instructions
|
||||
.send(PtyInstruction::SpawnTerminalVertically(None))
|
||||
.unwrap();
|
||||
break;
|
||||
}
|
||||
ServerInstruction::MoveFocus => {
|
||||
rlocked_sessions
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.send_screen_instructions
|
||||
.send(ScreenInstruction::FocusNextPane)
|
||||
.unwrap();
|
||||
break;
|
||||
}
|
||||
ServerInstruction::Action(action) => {
|
||||
route_action(action, rlocked_sessions.as_ref().unwrap());
|
||||
}
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
use crate::panes::PositionAndSize;
|
||||
use interprocess::local_socket::LocalSocketStream;
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
use std::io::Write;
|
||||
use std::os::unix::io::RawFd;
|
||||
|
|
@ -196,12 +197,6 @@ impl ClientOsApi for FakeInputOutput {
|
|||
fn send_to_server(&self, msg: ServerInstruction) {
|
||||
self.server_sender.send(msg).unwrap();
|
||||
}
|
||||
fn connect_to_server(&mut self, full_screen_ws: PositionAndSize) {
|
||||
ClientOsApi::send_to_server(
|
||||
self,
|
||||
ServerInstruction::NewClient("zellij".into(), full_screen_ws),
|
||||
);
|
||||
}
|
||||
fn client_recv(&self) -> (ClientInstruction, ErrorContext) {
|
||||
self.client_receiver.lock().unwrap().recv().unwrap()
|
||||
}
|
||||
|
|
@ -217,6 +212,7 @@ impl ClientOsApi for FakeInputOutput {
|
|||
cb();
|
||||
}
|
||||
}
|
||||
fn connect_to_server(&self) {}
|
||||
}
|
||||
|
||||
impl ServerOsApi for FakeInputOutput {
|
||||
|
|
@ -277,14 +273,12 @@ impl ServerOsApi for FakeInputOutput {
|
|||
self.io_events.lock().unwrap().push(IoEvent::Kill(fd));
|
||||
Ok(())
|
||||
}
|
||||
fn server_exit(&mut self) {
|
||||
self.server_sender.send(ServerInstruction::Exit).unwrap();
|
||||
}
|
||||
fn server_recv(&self) -> (ServerInstruction, ErrorContext) {
|
||||
self.server_receiver.lock().unwrap().recv().unwrap()
|
||||
}
|
||||
fn send_to_client(&self, msg: ClientInstruction) {
|
||||
self.client_sender.send(msg).unwrap();
|
||||
}
|
||||
fn add_client_sender(&mut self, _buffer_path: String) {}
|
||||
fn add_client_sender(&mut self) {}
|
||||
fn update_receiver(&mut self, stream: LocalSocketStream) {}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue