errors: Don't unwrap in server::terminal_bytes (#1876)

* server/terminal_bytes: Don't unwrap

and return `Result`s instead, where appropriate.

* changelog: Add PR #1876

Don't unwrap in `zellij_server::terminal_bytes`.
This commit is contained in:
har7an 2022-10-28 17:12:05 +00:00 committed by GitHub
parent 086b5d28fb
commit 60322e969f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 18 deletions

View file

@ -13,6 +13,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* debugging: Remove calls to unwrap in `zellij_server::ui::*` (https://github.com/zellij-org/zellij/pull/1870)
* debugging: Remove calls to unwrap in `zellij_server::pty_writer` (https://github.com/zellij-org/zellij/pull/1872)
* docs(example): update the format of the themes for the example directory (https://github.com/zellij-org/zellij/pull/1877)
* debugging: Remove calls to unwrap in `zellij_server::terminal_bytes` (https://github.com/zellij-org/zellij/pull/1876)
## [0.32.0] - 2022-10-25

View file

@ -455,20 +455,23 @@ impl Pty {
.ok_or_else(|| SpawnTerminalError::GenericSpawnError("os input is none"))?
.spawn_terminal(terminal_action, quit_cb, self.default_editor.clone())?;
let terminal_bytes = task::spawn({
let err_context = || format!("failed to run async task for terminal {terminal_id}");
let err_context =
|terminal_id: u32| format!("failed to run async task for terminal {terminal_id}");
let senders = self.bus.senders.clone();
let os_input = self
.bus
.os_input
.as_ref()
.with_context(err_context)
.with_context(|| err_context(terminal_id))
.fatal()
.clone();
let debug_to_file = self.debug_to_file;
async move {
TerminalBytes::new(pid_primary, senders, os_input, debug_to_file, terminal_id)
.listen()
.await;
.await
.with_context(|| err_context(terminal_id))
.fatal();
}
});
@ -657,7 +660,9 @@ impl Pty {
terminal_id,
)
.listen()
.await;
.await
.context("failed to spawn terminals for layout")
.fatal();
}
});
self.task_handles.insert(terminal_id, terminal_bytes);
@ -758,20 +763,23 @@ impl Pty {
.ok_or_else(|| SpawnTerminalError::GenericSpawnError("os input is none"))?
.re_run_command_in_terminal(id, run_command, quit_cb)?;
let terminal_bytes = task::spawn({
let err_context = || format!("failed to run async task for pane {pane_id:?}");
let err_context =
|pane_id| format!("failed to run async task for pane {pane_id:?}");
let senders = self.bus.senders.clone();
let os_input = self
.bus
.os_input
.as_ref()
.with_context(err_context)
.with_context(|| err_context(pane_id))
.fatal()
.clone();
let debug_to_file = self.debug_to_file;
async move {
TerminalBytes::new(pid_primary, senders, os_input, debug_to_file, id)
.listen()
.await;
.await
.with_context(|| err_context(pane_id))
.fatal();
}
});

View file

@ -10,7 +10,7 @@ use std::{
};
use zellij_utils::{
async_std,
errors::{get_current_ctx, ContextType},
errors::{get_current_ctx, prelude::*, ContextType},
logging::debug_to_file,
};
@ -63,7 +63,7 @@ impl TerminalBytes {
last_render: Instant::now(),
}
}
pub async fn listen(&mut self) {
pub async fn listen(&mut self) -> Result<()> {
// This function reads bytes from the pty and then sends them as
// ScreenInstruction::PtyBytes to screen to be parsed there
// We also send a separate instruction to Screen to render as ScreenInstruction::Render
@ -75,6 +75,8 @@ impl TerminalBytes {
// only send a render instruction sparingly, giving screen time to process bytes and render
// while still allowing the user to see an indication that things are happening (the
// sparing render instructions)
let err_context = || "failed to listen for bytes from PTY".to_string();
let mut err_ctx = get_current_ctx();
err_ctx.add_call(ContextType::AsyncTask);
let mut buf = [0u8; 65536];
@ -82,8 +84,10 @@ impl TerminalBytes {
match self.deadline_read(&mut buf).await {
ReadResult::Ok(0) | ReadResult::Err(_) => break, // EOF or error
ReadResult::Timeout => {
let time_to_send_render =
self.async_send_to_screen(ScreenInstruction::Render).await;
let time_to_send_render = self
.async_send_to_screen(ScreenInstruction::Render)
.await
.with_context(err_context)?;
self.update_render_send_time(time_to_send_render);
// next read does not need a deadline as we just rendered everything
self.render_deadline = None;
@ -98,11 +102,14 @@ impl TerminalBytes {
self.terminal_id,
bytes.to_vec(),
))
.await;
.await
.with_context(err_context)?;
if !self.backed_up {
// we're not backed up, let's send an immediate render instruction
let time_to_send_render =
self.async_send_to_screen(ScreenInstruction::Render).await;
let time_to_send_render = self
.async_send_to_screen(ScreenInstruction::Render)
.await
.with_context(err_context)?;
self.update_render_send_time(time_to_send_render);
self.last_render = Instant::now();
}
@ -113,16 +120,22 @@ impl TerminalBytes {
},
}
}
self.async_send_to_screen(ScreenInstruction::Render).await;
self.async_send_to_screen(ScreenInstruction::Render)
.await
.with_context(err_context)?;
Ok(())
}
async fn async_send_to_screen(&self, screen_instruction: ScreenInstruction) -> Duration {
async fn async_send_to_screen(
&self,
screen_instruction: ScreenInstruction,
) -> Result<Duration> {
// returns the time it blocked the thread for
let sent_at = Instant::now();
let senders = self.senders.clone();
task::spawn_blocking(move || senders.send_to_screen(screen_instruction))
.await
.unwrap();
sent_at.elapsed()
.context("failed to async-send to screen")?;
Ok(sent_at.elapsed())
}
fn update_render_send_time(&mut self, time_to_send_render: Duration) {
match self.minimum_render_send_time.as_mut() {