Fix terminal resize handling and cached updates
ci / test (push) Has been cancelled
ci / remote-bench (push) Has been cancelled

This commit is contained in:
Codex
2026-06-11 10:20:58 -04:00
parent 66c4c97c9d
commit 8ffbb07bfa
3 changed files with 104 additions and 10 deletions
+66 -5
View File
@@ -9,7 +9,7 @@ use dosh::auth::{
use dosh::config::{expand_tilde, load_client_config, load_server_config};
use dosh::crypto;
use dosh::protocol::{
self, AttachOk, BootstrapAttachRequest, CLIENT_TO_SERVER, Frame, Input, PacketKind,
self, AttachOk, BootstrapAttachRequest, CLIENT_TO_SERVER, Frame, Input, PacketKind, Resize,
ResumeRequest, SERVER_TO_CLIENT, TicketAttachBody, TicketAttachEnvelope,
TicketAttachOkEnvelope,
};
@@ -218,11 +218,16 @@ fn run_update(config: &dosh::config::ClientConfig) -> Result<()> {
.unwrap_or_else(|| "https://git.palav.dev/Palav/dosh.git".to_string());
let raw_base = raw_base_from_repo(&repo);
let installer = format!("{raw_base}/raw/branch/main/install.sh");
let update_cache = dirs::cache_dir()
.unwrap_or_else(|| expand_tilde("~/.cache"))
.join("dosh")
.join("source");
let mut script = format!(
"curl -fsSL {} | DOSH_REPO={} DOSH_PORT={} sh -s -- client",
"curl -fsSL {} | DOSH_REPO={} DOSH_PORT={} DOSH_UPDATE_CACHE={} sh -s -- client",
shell_word(&installer),
shell_word(&repo),
config.update_port.unwrap_or(config.dosh_port)
config.update_port.unwrap_or(config.dosh_port),
shell_word(&update_cache.display().to_string())
);
if config.server != "user@example.com" {
script.push_str(&format!(" --server {}", shell_word(&config.server)));
@@ -230,9 +235,8 @@ fn run_update(config: &dosh::config::ClientConfig) -> Result<()> {
if let Some(host) = &config.dosh_host {
script.push_str(&format!(" --dosh-host {}", shell_word(host)));
}
script.push_str(" --force-config");
let status = Command::new("sh")
.arg("-lc")
.arg("-c")
.arg(script)
.stdin(Stdio::null())
.status()
@@ -549,6 +553,8 @@ async fn run_terminal(
let mut last_packet_at = Instant::now();
let mut status_visible = false;
let mut status_tick = tokio::time::interval(Duration::from_secs(1));
let mut resize_tick = tokio::time::interval(Duration::from_millis(250));
let mut last_size = size().unwrap_or((80, 24));
if let Some(frame) = first_frame {
render_frame(&frame)?;
if frame.closed {
@@ -597,6 +603,16 @@ async fn run_terminal(
socket.send_to(&packet, addr).await?;
}
}
_ = resize_tick.tick() => {
if let Ok((cols, rows)) = size()
&& (cols, rows) != last_size
{
last_size = (cols, rows);
if cred.mode != "view-only" {
send_resize(&socket, addr, &cred, &mut send_seq, cols, rows).await?;
}
}
}
recv = socket.recv_from(&mut recv_buf) => {
let (n, _) = recv?;
last_packet_at = Instant::now();
@@ -647,6 +663,29 @@ async fn run_terminal(
Ok(())
}
async fn send_resize(
socket: &UdpSocket,
addr: SocketAddr,
cred: &CachedCredential,
send_seq: &mut u64,
cols: u16,
rows: u16,
) -> Result<()> {
let body = protocol::to_body(&Resize { cols, rows })?;
let packet = protocol::encode_encrypted(
PacketKind::Resize,
cred.client_id,
*send_seq,
cred.last_rendered_seq,
&cred.session_key,
CLIENT_TO_SERVER,
&body,
)?;
*send_seq += 1;
socket.send_to(&packet, addr).await?;
Ok(())
}
async fn send_ack(
socket: &UdpSocket,
addr: SocketAddr,
@@ -733,12 +772,34 @@ struct RawMode;
impl RawMode {
fn enter() -> Result<Self> {
enable_raw_mode()?;
let mut stdout = std::io::stdout();
stdout.write_all(TERMINAL_CLEANUP)?;
stdout.flush()?;
Ok(Self)
}
}
impl Drop for RawMode {
fn drop(&mut self) {
let mut stdout = std::io::stdout();
let _ = stdout.write_all(TERMINAL_CLEANUP);
let _ = stdout.flush();
let _ = disable_raw_mode();
}
}
const TERMINAL_CLEANUP: &[u8] = concat!(
"\x1b[?1l",
"\x1b[0m",
"\x1b[?25h",
"\x1b[?1003l",
"\x1b[?1002l",
"\x1b[?1001l",
"\x1b[?1000l",
"\x1b[?1015l",
"\x1b[?1006l",
"\x1b[?1005l",
"\x1b[?2004l",
"\x1b[?1049l"
)
.as_bytes();