diff options
| author | Kunal Mohan <kunalmohan99@gmail.com> | 2021-05-16 16:42:50 +0530 |
|---|---|---|
| committer | Kunal Mohan <kunalmohan99@gmail.com> | 2021-05-16 21:41:56 +0530 |
| commit | 2038947a14d32d89da2bdbcaa1381c3015ac9c7a (patch) | |
| tree | 5a332470e32b380816098594a89d3c3db1f6eb53 /src/common/errors.rs | |
| parent | handle error on termios initialization (#511) (diff) | |
| download | sl0ppij-2038947a14d32d89da2bdbcaa1381c3015ac9c7a.tar.gz sl0ppij-2038947a14d32d89da2bdbcaa1381c3015ac9c7a.tar.xz sl0ppij-2038947a14d32d89da2bdbcaa1381c3015ac9c7a.zip | |
Big refactor: separate crates for client, server and utilities
Diffstat (limited to 'src/common/errors.rs')
| -rw-r--r-- | src/common/errors.rs | 393 |
1 files changed, 0 insertions, 393 deletions
diff --git a/src/common/errors.rs b/src/common/errors.rs deleted file mode 100644 index 262dfd6b..00000000 --- a/src/common/errors.rs +++ /dev/null @@ -1,393 +0,0 @@ -//! Error context system based on a thread-local representation of the call stack, itself based on -//! the instructions that are sent between threads. - -use serde::{Deserialize, Serialize}; - -use std::fmt::{Display, Error, Formatter}; - -use crate::client::ClientInstruction; -use crate::common::thread_bus::{ASYNCOPENCALLS, OPENCALLS}; -use crate::pty::PtyInstruction; -use crate::screen::ScreenInstruction; -use crate::server::ServerInstruction; - -/// The maximum amount of calls an [`ErrorContext`] will keep track -/// of in its stack representation. This is a per-thread maximum. -const MAX_THREAD_CALL_STACK: usize = 6; - -#[cfg(not(test))] -use super::thread_bus::SenderWithContext; -#[cfg(not(test))] -use std::panic::PanicInfo; - -pub trait ErrorInstruction { - fn error(err: String) -> Self; -} - -impl ErrorInstruction for ClientInstruction { - fn error(err: String) -> Self { - ClientInstruction::Error(err) - } -} - -impl ErrorInstruction for ServerInstruction { - fn error(err: String) -> Self { - ServerInstruction::Error(err) - } -} - -/// Custom panic handler/hook. Prints the [`ErrorContext`]. -#[cfg(not(test))] -pub fn handle_panic<T>(info: &PanicInfo<'_>, sender: &SenderWithContext<T>) -where - T: ErrorInstruction + Clone, -{ - use backtrace::Backtrace; - use std::{process, thread}; - let backtrace = Backtrace::new(); - let thread = thread::current(); - let thread = thread.name().unwrap_or("unnamed"); - - let msg = match info.payload().downcast_ref::<&'static str>() { - Some(s) => Some(*s), - None => info.payload().downcast_ref::<String>().map(|s| &**s), - }; - - let err_ctx = OPENCALLS.with(|ctx| *ctx.borrow()); - - let backtrace = match (info.location(), msg) { - (Some(location), Some(msg)) => format!( - "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}': {}:{}\n\u{1b}[0;0m{:?}", - err_ctx, - thread, - msg, - location.file(), - location.line(), - backtrace, - ), - (Some(location), None) => format!( - "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked: {}:{}\n\u{1b}[0;0m{:?}", - err_ctx, - thread, - location.file(), - location.line(), - backtrace - ), - (None, Some(msg)) => format!( - "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked at '{}'\n\u{1b}[0;0m{:?}", - err_ctx, thread, msg, backtrace - ), - (None, None) => format!( - "{}\n\u{1b}[0;0mError: \u{1b}[0;31mthread '{}' panicked\n\u{1b}[0;0m{:?}", - err_ctx, thread, backtrace - ), - }; - - if thread == "main" { - println!("{}", backtrace); - process::exit(1); - } else { - let _ = sender.send(T::error(backtrace)); - } -} - -pub fn get_current_ctx() -> ErrorContext { - ASYNCOPENCALLS - .try_with(|ctx| *ctx.borrow()) - .unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow())) -} - -/// A representation of the call stack. -#[derive(Clone, Copy, Serialize, Deserialize)] -pub struct ErrorContext { - calls: [ContextType; MAX_THREAD_CALL_STACK], -} - -impl ErrorContext { - /// Returns a new, blank [`ErrorContext`] containing only [`Empty`](ContextType::Empty) - /// calls. - pub fn new() -> Self { - Self { - calls: [ContextType::Empty; MAX_THREAD_CALL_STACK], - } - } - - /// Adds a call to this [`ErrorContext`]'s call stack representation. - pub fn add_call(&mut self, call: ContextType) { - for ctx in self.calls.iter_mut() { - if *ctx == ContextType::Empty { - *ctx = call; - break; - } - } - self.update_thread_ctx() - } - - /// Updates the thread local [`ErrorContext`]. - pub fn update_thread_ctx(&self) { - ASYNCOPENCALLS - .try_with(|ctx| *ctx.borrow_mut() = *self) - .unwrap_or_else(|_| OPENCALLS.with(|ctx| *ctx.borrow_mut() = *self)); - } -} - -impl Default for ErrorContext { - fn default() -> Self { - Self::new() - } -} - -impl Display for ErrorContext { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - writeln!(f, "Originating Thread(s):")?; - for (index, ctx) in self.calls.iter().enumerate() { - if *ctx == ContextType::Empty { - break; - } - writeln!(f, "\u{1b}[0;0m{}. {}", index + 1, ctx)?; - } - Ok(()) - } -} - -/// Different types of calls that form an [`ErrorContext`] call stack. -/// -/// Complex variants store a variant of a related enum, whose variants can be built from -/// the corresponding Zellij MSPC instruction enum variants ([`ScreenInstruction`], -/// [`PtyInstruction`], [`ClientInstruction`], etc). -#[derive(Copy, Clone, PartialEq, Serialize, Deserialize)] -pub enum ContextType { - /// A screen-related call. - Screen(ScreenContext), - /// A PTY-related call. - Pty(PtyContext), - /// A plugin-related call. - Plugin(PluginContext), - /// An app-related call. - Client(ClientContext), - /// A server-related call. - IPCServer(ServerContext), - StdinHandler, - AsyncTask, - /// An empty, placeholder call. This should be thought of as representing no call at all. - /// A call stack representation filled with these is the representation of an empty call stack. - Empty, -} - -// TODO use the `colored` crate for color formatting -impl Display for ContextType { - fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - let purple = "\u{1b}[1;35m"; - let green = "\u{1b}[0;32m"; - match *self { - ContextType::Screen(c) => write!(f, "{}screen_thread: {}{:?}", purple, green, c), - ContextType::Pty(c) => write!(f, "{}pty_thread: {}{:?}", purple, green, c), - ContextType::Plugin(c) => write!(f, "{}plugin_thread: {}{:?}", purple, green, c), - ContextType::Client(c) => write!(f, "{}main_thread: {}{:?}", purple, green, c), - ContextType::IPCServer(c) => write!(f, "{}ipc_server: {}{:?}", purple, green, c), - ContextType::StdinHandler => { - write!(f, "{}stdin_handler_thread: {}AcceptInput", purple, green) - } - ContextType::AsyncTask => { - write!(f, "{}stream_terminal_bytes: {}AsyncTask", purple, green) - } - ContextType::Empty => write!(f, ""), - } - } -} - -// FIXME: Just deriving EnumDiscriminants from strum will remove the need for any of this!!! -/// Stack call representations corresponding to the different types of [`ScreenInstruction`]s. -#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] -pub enum ScreenContext { - HandlePtyBytes, - Render, - NewPane, - HorizontalSplit, - VerticalSplit, - WriteCharacter, - ResizeLeft, - ResizeRight, - ResizeDown, - ResizeUp, - SwitchFocus, - FocusNextPane, - FocusPreviousPane, - MoveFocusLeft, - MoveFocusLeftOrPreviousTab, - MoveFocusDown, - MoveFocusUp, - MoveFocusRight, - MoveFocusRightOrNextTab, - Exit, - ScrollUp, - ScrollDown, - PageScrollUp, - PageScrollDown, - ClearScroll, - CloseFocusedPane, - ToggleActiveSyncTab, - ToggleActiveTerminalFullscreen, - SetSelectable, - SetInvisibleBorders, - SetMaxHeight, - ClosePane, - ApplyLayout, - NewTab, - SwitchTabNext, - SwitchTabPrev, - CloseTab, - GoToTab, - UpdateTabName, - TerminalResize, - ChangeMode, -} - -// FIXME: Just deriving EnumDiscriminants from strum will remove the need for any of this!!! -impl From<&ScreenInstruction> for ScreenContext { - fn from(screen_instruction: &ScreenInstruction) -> Self { - match *screen_instruction { - ScreenInstruction::PtyBytes(..) => ScreenContext::HandlePtyBytes, - ScreenInstruction::Render => ScreenContext::Render, - ScreenInstruction::NewPane(_) => ScreenContext::NewPane, - ScreenInstruction::HorizontalSplit(_) => ScreenContext::HorizontalSplit, - ScreenInstruction::VerticalSplit(_) => ScreenContext::VerticalSplit, - ScreenInstruction::WriteCharacter(_) => ScreenContext::WriteCharacter, - ScreenInstruction::ResizeLeft => ScreenContext::ResizeLeft, - ScreenInstruction::ResizeRight => ScreenContext::ResizeRight, - ScreenInstruction::ResizeDown => ScreenContext::ResizeDown, - ScreenInstruction::ResizeUp => ScreenContext::ResizeUp, - ScreenInstruction::SwitchFocus => ScreenContext::SwitchFocus, - ScreenInstruction::FocusNextPane => ScreenContext::FocusNextPane, - ScreenInstruction::FocusPreviousPane => ScreenContext::FocusPreviousPane, - ScreenInstruction::MoveFocusLeft => ScreenContext::MoveFocusLeft, - ScreenInstruction::MoveFocusLeftOrPreviousTab => { - ScreenContext::MoveFocusLeftOrPreviousTab - } - ScreenInstruction::MoveFocusDown => ScreenContext::MoveFocusDown, - ScreenInstruction::MoveFocusUp => ScreenContext::MoveFocusUp, - ScreenInstruction::MoveFocusRight => ScreenContext::MoveFocusRight, - ScreenInstruction::MoveFocusRightOrNextTab => ScreenContext::MoveFocusRightOrNextTab, - ScreenInstruction::Exit => ScreenContext::Exit, - ScreenInstruction::ScrollUp => ScreenContext::ScrollUp, - ScreenInstruction::ScrollDown => ScreenContext::ScrollDown, - ScreenInstruction::PageScrollUp => ScreenContext::PageScrollUp, - ScreenInstruction::PageScrollDown => ScreenContext::PageScrollDown, - ScreenInstruction::ClearScroll => ScreenContext::ClearScroll, - ScreenInstruction::CloseFocusedPane => ScreenContext::CloseFocusedPane, - ScreenInstruction::ToggleActiveTerminalFullscreen => { - ScreenContext::ToggleActiveTerminalFullscreen - } - ScreenInstruction::SetSelectable(..) => ScreenContext::SetSelectable, - ScreenInstruction::SetInvisibleBorders(..) => ScreenContext::SetInvisibleBorders, - ScreenInstruction::SetMaxHeight(..) => ScreenContext::SetMaxHeight, - ScreenInstruction::ClosePane(_) => ScreenContext::ClosePane, - ScreenInstruction::ApplyLayout(..) => ScreenContext::ApplyLayout, - ScreenInstruction::NewTab(_) => ScreenContext::NewTab, - ScreenInstruction::SwitchTabNext => ScreenContext::SwitchTabNext, - ScreenInstruction::SwitchTabPrev => ScreenContext::SwitchTabPrev, - ScreenInstruction::CloseTab => ScreenContext::CloseTab, - ScreenInstruction::GoToTab(_) => ScreenContext::GoToTab, - ScreenInstruction::UpdateTabName(_) => ScreenContext::UpdateTabName, - ScreenInstruction::TerminalResize(_) => ScreenContext::TerminalResize, - ScreenInstruction::ChangeMode(_) => ScreenContext::ChangeMode, - ScreenInstruction::ToggleActiveSyncTab => ScreenContext::ToggleActiveSyncTab, - } - } -} - -/// Stack call representations corresponding to the different types of [`PtyInstruction`]s. -#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] -pub enum PtyContext { - SpawnTerminal, - SpawnTerminalVertically, - SpawnTerminalHorizontally, - NewTab, - ClosePane, - CloseTab, - Exit, -} - -impl From<&PtyInstruction> for PtyContext { - fn from(pty_instruction: &PtyInstruction) -> Self { - match *pty_instruction { - PtyInstruction::SpawnTerminal(_) => PtyContext::SpawnTerminal, - PtyInstruction::SpawnTerminalVertically(_) => PtyContext::SpawnTerminalVertically, - PtyInstruction::SpawnTerminalHorizontally(_) => PtyContext::SpawnTerminalHorizontally, - PtyInstruction::ClosePane(_) => PtyContext::ClosePane, - PtyInstruction::CloseTab(_) => PtyContext::CloseTab, - PtyInstruction::NewTab => PtyContext::NewTab, - PtyInstruction::Exit => PtyContext::Exit, - } - } -} - -// FIXME: This whole pattern *needs* a macro eventually, it's soul-crushing to write - -use crate::wasm_vm::PluginInstruction; - -/// Stack call representations corresponding to the different types of [`PluginInstruction`]s. -#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] -pub enum PluginContext { - Load, - Update, - Render, - Unload, - Exit, -} - -impl From<&PluginInstruction> for PluginContext { - fn from(plugin_instruction: &PluginInstruction) -> Self { - match *plugin_instruction { - PluginInstruction::Load(..) => PluginContext::Load, - PluginInstruction::Update(..) => PluginContext::Update, - PluginInstruction::Render(..) => PluginContext::Render, - PluginInstruction::Unload(_) => PluginContext::Unload, - PluginInstruction::Exit => PluginContext::Exit, - } - } -} - -/// Stack call representations corresponding to the different types of [`ClientInstruction`]s. -#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] -pub enum ClientContext { - Exit, - Error, - UnblockInputThread, - Render, - ServerError, -} - -impl From<&ClientInstruction> for ClientContext { - fn from(client_instruction: &ClientInstruction) -> Self { - match *client_instruction { - ClientInstruction::Exit => ClientContext::Exit, - ClientInstruction::Error(_) => ClientContext::Error, - ClientInstruction::ServerError(_) => ClientContext::ServerError, - ClientInstruction::Render(_) => ClientContext::Render, - ClientInstruction::UnblockInputThread => ClientContext::UnblockInputThread, - } - } -} - -/// Stack call representations corresponding to the different types of [`ServerInstruction`]s. -#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] -pub enum ServerContext { - NewClient, - Render, - UnblockInputThread, - ClientExit, - Error, -} - -impl From<&ServerInstruction> for ServerContext { - fn from(server_instruction: &ServerInstruction) -> Self { - match *server_instruction { - ServerInstruction::NewClient(..) => ServerContext::NewClient, - ServerInstruction::Render(_) => ServerContext::Render, - ServerInstruction::UnblockInputThread => ServerContext::UnblockInputThread, - ServerInstruction::ClientExit => ServerContext::ClientExit, - ServerInstruction::Error(_) => ServerContext::Error, - } - } -} |
