Switch to multiprocess model: Not looking good

This commit is contained in:
Kunal Mohan 2021-05-11 11:47:08 +05:30
parent 20d4b1826d
commit 0d792e26f2
8 changed files with 114 additions and 86 deletions

17
Cargo.lock generated
View file

@ -248,6 +248,12 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "boxfnonce"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5988cb1d626264ac94100be357308f29ff7cbdd3b36bda27f450a4ee3f713426"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.6.1" version = "3.6.1"
@ -467,6 +473,16 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "daemonize"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70c24513e34f53b640819f0ac9f705b673fcf4006d7aab8778bee72ebfc89815"
dependencies = [
"boxfnonce",
"libc",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.12.3" version = "0.12.3"
@ -2261,6 +2277,7 @@ dependencies = [
"backtrace", "backtrace",
"bincode", "bincode",
"colors-transform", "colors-transform",
"daemonize",
"directories-next", "directories-next",
"futures", "futures",
"insta", "insta",

View file

@ -15,6 +15,7 @@ include = ["src/**/*", "assets/plugins/*", "assets/layouts/*", "assets/config/*"
ansi_term = "0.12.1" ansi_term = "0.12.1"
backtrace = "0.3.55" backtrace = "0.3.55"
bincode = "1.3.1" bincode = "1.3.1"
daemonize = "0.4.1"
directories-next = "2.0" directories-next = "2.0"
futures = "0.3.5" futures = "0.3.5"
libc = "0.2" libc = "0.2"

View file

@ -16,6 +16,9 @@ pub struct CliArgs {
#[structopt(long)] #[structopt(long)]
pub data_dir: Option<PathBuf>, pub data_dir: Option<PathBuf>,
#[structopt(long)]
pub server: Option<PathBuf>,
/// Path to a layout yaml file /// Path to a layout yaml file
#[structopt(short, long)] #[structopt(short, long)]
pub layout: Option<PathBuf>, pub layout: Option<PathBuf>,

View file

@ -5,7 +5,10 @@ pub mod panes;
pub mod tab; pub mod tab;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::io::Write; use std::env::current_exe;
use std::io::{self, Write};
use std::path::Path;
use std::process::Command;
use std::sync::mpsc; use std::sync::mpsc;
use std::thread; use std::thread;
@ -18,6 +21,7 @@ use crate::common::{
input::options::Options, input::options::Options,
os_input_output::ClientOsApi, os_input_output::ClientOsApi,
thread_bus::{SenderType, SenderWithContext, SyncChannelWithContext}, thread_bus::{SenderType, SenderWithContext, SyncChannelWithContext},
utils::consts::ZELLIJ_IPC_PIPE,
}; };
use crate::server::ServerInstruction; use crate::server::ServerInstruction;
@ -30,8 +34,25 @@ pub enum ClientInstruction {
Exit, Exit,
} }
fn spawn_server(socket_path: &Path) -> io::Result<()> {
let status = Command::new(current_exe()?)
.arg("--server")
.arg(socket_path)
.status()?;
if status.success() {
Ok(())
} else {
let msg = "Process returned non-zero exit code";
let err_msg = match status.code() {
Some(c) => format!("{}: {}", msg, c),
None => msg.to_string(),
};
Err(io::Error::new(io::ErrorKind::Other, err_msg))
}
}
pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: Config) { pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: Config) {
let clear_client_terminal_attributes = "\u{1b}[?1l\u{1b}=\u{1b}[r\u{1b}12l\u{1b}[?1000l\u{1b}[?1002l\u{1b}[?1003l\u{1b}[?1005l\u{1b}[?1006l\u{1b}[?12l"; spawn_server(&*ZELLIJ_IPC_PIPE).unwrap();
let take_snapshot = "\u{1b}[?1049h"; let take_snapshot = "\u{1b}[?1049h";
let bracketed_paste = "\u{1b}[?2004h"; let bracketed_paste = "\u{1b}[?2004h";
os_input.unset_raw_mode(0); os_input.unset_raw_mode(0);
@ -50,12 +71,8 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
let config_options = Options::from_cli(&config.options, opts.option.clone()); let config_options = Options::from_cli(&config.options, opts.option.clone());
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(); os_input.connect_to_server(&*ZELLIJ_IPC_PIPE);
os_input.send_to_server(ServerInstruction::NewClient( os_input.send_to_server(ServerInstruction::NewClient(full_screen_ws, opts));
full_screen_ws,
opts,
config_options,
));
os_input.set_raw_mode(0); os_input.set_raw_mode(0);
let _ = os_input let _ = os_input
.get_stdout_writer() .get_stdout_writer()
@ -130,7 +147,6 @@ pub fn start_client(mut os_input: Box<dyn ClientOsApi>, opts: CliArgs, config: C
}) })
.unwrap(); .unwrap();
#[warn(clippy::never_loop)]
loop { loop {
let (client_instruction, mut err_ctx) = receive_client_instructions let (client_instruction, mut err_ctx) = receive_client_instructions
.recv() .recv()

View file

@ -1,8 +1,5 @@
use crate::client::ClientInstruction; use crate::client::ClientInstruction;
use crate::common::{ use crate::common::ipc::{IpcReceiverWithContext, IpcSenderWithContext};
ipc::{IpcReceiverWithContext, IpcSenderWithContext},
utils::consts::ZELLIJ_IPC_PIPE,
};
use crate::errors::ErrorContext; use crate::errors::ErrorContext;
use crate::panes::PositionAndSize; use crate::panes::PositionAndSize;
use crate::server::ServerInstruction; use crate::server::ServerInstruction;
@ -319,7 +316,7 @@ pub trait ClientOsApi: Send + Sync {
fn recv_from_server(&self) -> (ClientInstruction, ErrorContext); fn recv_from_server(&self) -> (ClientInstruction, 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); fn connect_to_server(&self, path: &Path);
} }
impl ClientOsApi for ClientOsInputOutput { impl ClientOsApi for ClientOsInputOutput {
@ -379,14 +376,19 @@ impl ClientOsApi for ClientOsInputOutput {
} }
} }
} }
fn connect_to_server(&self) { fn connect_to_server(&self, path: &Path) {
let socket = match LocalSocketStream::connect(&**ZELLIJ_IPC_PIPE) { let socket;
Ok(sock) => sock, loop {
Err(_) => { match LocalSocketStream::connect(path) {
std::thread::sleep(std::time::Duration::from_millis(20)); Ok(sock) => {
LocalSocketStream::connect(&**ZELLIJ_IPC_PIPE).unwrap() socket = sock;
break;
}
Err(_) => {
std::thread::sleep(std::time::Duration::from_millis(50));
}
} }
}; }
let sender = IpcSenderWithContext::new(socket); let sender = IpcSenderWithContext::new(socket);
let receiver = sender.get_receiver(); let receiver = sender.get_receiver();
*self.send_instructions_to_server.lock().unwrap() = Some(sender); *self.send_instructions_to_server.lock().unwrap() = Some(sender);

View file

@ -17,7 +17,7 @@ use crate::command_is_executing::CommandIsExecuting;
use crate::common::input::{config::Config, options::Options}; use crate::common::input::{config::Config, options::Options};
use crate::os_input_output::{get_client_os_input, get_server_os_input, ClientOsApi, ServerOsApi}; use crate::os_input_output::{get_client_os_input, get_server_os_input, ClientOsApi, ServerOsApi};
use crate::utils::{ use crate::utils::{
consts::{ZELLIJ_TMP_DIR, ZELLIJ_TMP_LOG_DIR}, consts::{ZELLIJ_IPC_PIPE, ZELLIJ_TMP_DIR, ZELLIJ_TMP_LOG_DIR},
logging::*, logging::*,
}; };
use std::convert::TryFrom; use std::convert::TryFrom;
@ -39,15 +39,13 @@ pub fn main() {
let config_options = Options::from_cli(&config.options, opts.option.clone()); let config_options = Options::from_cli(&config.options, opts.option.clone());
atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap(); atomic_create_dir(&*ZELLIJ_TMP_DIR).unwrap();
atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap(); atomic_create_dir(&*ZELLIJ_TMP_LOG_DIR).unwrap();
let server_os_input = get_server_os_input(); if let Some(path) = opts.server {
let os_input = get_client_os_input(); let os_input = get_server_os_input();
start( start_server(Box::new(os_input), path);
Box::new(os_input), } else {
opts, let os_input = get_client_os_input();
Box::new(server_os_input), start_client(Box::new(os_input), opts, config);
config, }
config_options,
);
} }
} }
pub fn start( pub fn start(
@ -57,7 +55,7 @@ pub fn start(
config: Config, config: Config,
config_options: Options, config_options: Options,
) { ) {
let ipc_thread = start_server(server_os_input, config_options); start_server(server_os_input, ZELLIJ_IPC_PIPE.clone());
start_client(client_os_input, opts, config); start_client(client_os_input, opts, config);
drop(ipc_thread.join()); //drop(ipc_thread.join());
} }

View file

@ -1,5 +1,6 @@
pub mod route; pub mod route;
use daemonize::Daemonize;
use interprocess::local_socket::LocalSocketListener; use interprocess::local_socket::LocalSocketListener;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::{Arc, RwLock}; use std::sync::{Arc, RwLock};
@ -19,7 +20,7 @@ use crate::common::{
screen::{screen_thread_main, ScreenInstruction}, screen::{screen_thread_main, ScreenInstruction},
setup::{get_default_data_dir, install::populate_data_dir}, setup::{get_default_data_dir, install::populate_data_dir},
thread_bus::{ChannelWithContext, SenderType, SenderWithContext}, thread_bus::{ChannelWithContext, SenderType, SenderWithContext},
utils::consts::ZELLIJ_IPC_PIPE, utils::consts::ZELLIJ_PROJ_DIR,
wasm_vm::{wasm_thread_main, PluginInstruction}, wasm_vm::{wasm_thread_main, PluginInstruction},
}; };
use crate::layout::Layout; use crate::layout::Layout;
@ -56,10 +57,12 @@ impl Drop for SessionMetaData {
} }
} }
pub fn start_server( pub fn start_server(os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
os_input: Box<dyn ServerOsApi>, Daemonize::new()
config_options: Options, .working_directory(std::env::var("HOME").unwrap())
) -> thread::JoinHandle<()> { .umask(0o077)
.start()
.expect("could not daemonize the server process");
let (to_server, server_receiver): ChannelWithContext<ServerInstruction> = channel(); let (to_server, server_receiver): ChannelWithContext<ServerInstruction> = channel();
let to_server = SenderWithContext::new(SenderType::Sender(to_server)); let to_server = SenderWithContext::new(SenderType::Sender(to_server));
let sessions: Arc<RwLock<Option<SessionMetaData>>> = Arc::new(RwLock::new(None)); let sessions: Arc<RwLock<Option<SessionMetaData>>> = Arc::new(RwLock::new(None));
@ -85,13 +88,11 @@ pub fn start_server(
let os_input = os_input.clone(); let os_input = os_input.clone();
let sessions = sessions.clone(); let sessions = sessions.clone();
let to_server = to_server.clone(); let to_server = to_server.clone();
let capabilities = PluginCapabilities { let socket_path = socket_path.clone();
arrow_fonts: config_options.simplified_ui,
};
move || { move || {
drop(std::fs::remove_file(&*ZELLIJ_IPC_PIPE)); drop(std::fs::remove_file(&socket_path));
let listener = LocalSocketListener::bind(&**ZELLIJ_IPC_PIPE).unwrap(); let listener = LocalSocketListener::bind(&*socket_path).unwrap();
set_permissions(&*ZELLIJ_IPC_PIPE).unwrap(); set_permissions(&socket_path).unwrap();
for stream in listener.incoming() { for stream in listener.incoming() {
match stream { match stream {
Ok(stream) => { Ok(stream) => {
@ -125,48 +126,38 @@ pub fn start_server(
} }
}); });
thread::Builder::new() loop {
.name("server_thread".to_string()) let (instruction, mut err_ctx) = server_receiver.recv().unwrap();
.spawn({ err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction)));
move || loop { match instruction {
let (instruction, mut err_ctx) = server_receiver.recv().unwrap(); ServerInstruction::NewClient(full_screen_ws, opts) => {
err_ctx.add_call(ContextType::IPCServer(ServerContext::from(&instruction))); let session_data =
match instruction { init_session(os_input.clone(), opts, to_server.clone(), full_screen_ws);
ServerInstruction::NewClient(full_screen_ws, opts, config_options) => { *sessions.write().unwrap() = Some(session_data);
let session_data = init_session( sessions
os_input.clone(), .read()
opts, .unwrap()
config_options, .as_ref()
to_server.clone(), .unwrap()
full_screen_ws, .senders
); .send_to_pty(PtyInstruction::NewTab)
*sessions.write().unwrap() = Some(session_data); .unwrap();
sessions
.read()
.unwrap()
.as_ref()
.unwrap()
.senders
.send_to_pty(PtyInstruction::NewTab)
.unwrap();
}
ServerInstruction::UnblockInputThread => {
os_input.send_to_client(ClientInstruction::UnblockInputThread);
}
ServerInstruction::ClientExit => {
*sessions.write().unwrap() = None;
os_input.send_to_client(ClientInstruction::Exit);
drop(std::fs::remove_file(&*ZELLIJ_IPC_PIPE));
break;
}
ServerInstruction::Render(output) => {
os_input.send_to_client(ClientInstruction::Render(output))
}
_ => panic!("Received unexpected instruction."),
}
} }
}) ServerInstruction::UnblockInputThread => {
.unwrap() os_input.send_to_client(ClientInstruction::UnblockInputThread);
}
ServerInstruction::ClientExit => {
*sessions.write().unwrap() = None;
os_input.send_to_client(ClientInstruction::Exit);
drop(std::fs::remove_file(&socket_path));
break;
}
ServerInstruction::Render(output) => {
os_input.send_to_client(ClientInstruction::Render(output))
}
_ => panic!("Received unexpected instruction."),
}
}
} }
fn init_session( fn init_session(

View file

@ -217,7 +217,7 @@ impl ClientOsApi for FakeInputOutput {
cb(); cb();
} }
} }
fn connect_to_server(&self) {} fn connect_to_server(&self, path: &std::path::Path) {}
} }
impl ServerOsApi for FakeInputOutput { impl ServerOsApi for FakeInputOutput {