Survive a missing touch panel at boot; retry the open briefly
Two changes to the unattended path, both prompted by deploying to the rack. The autostart can win the race against USB enumeration at boot, so the panel may simply not exist yet when socktop-swipe starts. Opening it now retries for ten seconds -- long enough for enumeration, short enough that a genuinely wrong device path still reports promptly. If the panel cannot be opened at all, `run` no longer treats that as fatal. By that point the dashboard is already on the wall, and exiting would replace a display you cannot swipe with no display at all. It now says loudly that gestures are inactive, points at the movement subcommands, and carries on serving the control socket. `daemon` and `doctor` still fail fast, since there is no display at stake in either. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+30
-2
@@ -253,7 +253,16 @@ fn run(cfg: &Config, no_touch: bool) -> Result<()> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if !no_touch {
|
if !no_touch {
|
||||||
spawn_panel(cfg, tx)?;
|
// Deliberately not fatal. The dashboard is already on the wall by this
|
||||||
|
// point; exiting because the panel is missing would replace a display
|
||||||
|
// you cannot swipe with no display at all. Say so loudly and carry on
|
||||||
|
// serving the control socket, which is still a way to drive it.
|
||||||
|
if let Err(e) = spawn_panel(cfg, tx) {
|
||||||
|
eprintln!("socktop-swipe: touch gestures are NOT active: {e:#}");
|
||||||
|
eprintln!(
|
||||||
|
"socktop-swipe: the dashboard is up; drive it with `socktop-swipe forward` etc."
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
drive(&tmux, &mut grid, rx)
|
drive(&tmux, &mut grid, rx)
|
||||||
}
|
}
|
||||||
@@ -281,11 +290,30 @@ fn daemon(cfg: &Config, no_touch: bool) -> Result<()> {
|
|||||||
drive(&tmux, &mut grid, rx)
|
drive(&tmux, &mut grid, rx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Open the touch panel, retrying briefly.
|
||||||
|
///
|
||||||
|
/// At boot the autostart can win the race against USB enumeration, so the
|
||||||
|
/// device is simply not there yet. Ten seconds covers that without making a
|
||||||
|
/// genuinely wrong device path take ten seconds to report.
|
||||||
|
fn open_panel(cfg: &Config) -> Result<Touchpanel> {
|
||||||
|
let deadline = std::time::Instant::now() + std::time::Duration::from_secs(10);
|
||||||
|
loop {
|
||||||
|
match Touchpanel::open(&cfg.touch) {
|
||||||
|
Ok(p) => return Ok(p),
|
||||||
|
Err(e) if std::time::Instant::now() < deadline => {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||||
|
let _ = e;
|
||||||
|
}
|
||||||
|
Err(e) => return Err(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Read the panel on its own thread. Opening it here rather than in the thread
|
/// Read the panel on its own thread. Opening it here rather than in the thread
|
||||||
/// keeps a permission or grab failure on the main path, where it can be
|
/// keeps a permission or grab failure on the main path, where it can be
|
||||||
/// reported properly instead of vanishing into a detached thread.
|
/// reported properly instead of vanishing into a detached thread.
|
||||||
fn spawn_panel(cfg: &Config, tx: mpsc::Sender<Ctl>) -> Result<()> {
|
fn spawn_panel(cfg: &Config, tx: mpsc::Sender<Ctl>) -> Result<()> {
|
||||||
let mut panel = Touchpanel::open(&cfg.touch)?;
|
let mut panel = open_panel(cfg)?;
|
||||||
let gestures = cfg.gestures.clone();
|
let gestures = cfg.gestures.clone();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
let result = panel.run(|ev| {
|
let result = panel.run(|ev| {
|
||||||
|
|||||||
Reference in New Issue
Block a user