Fix robustness issues across backend and frontend

- Add shutil.which guard to _run() in settings, asi_bridge routers
- Catch RuntimeError on WebSocket disconnect in services, asi_bridge
- Make file listing resilient to individual entry errors
- Fix keyboard double-fire on touch devices (touchstart + click)
- Update install.sh with correct Gitea repo URL
- Add six to requirements.txt (python-pam dependency)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
roberts 2026-03-14 17:41:43 -05:00
parent f9743bb29a
commit 342dc0f0cf
7 changed files with 21 additions and 5 deletions

View file

@ -1,6 +1,7 @@
fastapi==0.115.6 fastapi==0.115.6
uvicorn[standard]==0.34.0 uvicorn[standard]==0.34.0
python-pam==2.0.2 python-pam==2.0.2
six==1.17.0
PyJWT==2.10.1 PyJWT==2.10.1
psutil==6.1.1 psutil==6.1.1
ptyprocess==0.7.0 ptyprocess==0.7.0

View file

@ -110,7 +110,13 @@ async def list_dir(
entries = sorted(p.iterdir(), key=lambda x: (not x.is_dir(), x.name.lower())) entries = sorted(p.iterdir(), key=lambda x: (not x.is_dir(), x.name.lower()))
except PermissionError: except PermissionError:
raise HTTPException(403, f"Permission denied: {path}") raise HTTPException(403, f"Permission denied: {path}")
return [_file_info(e) for e in entries] results = []
for e in entries:
try:
results.append(_file_info(e))
except (OSError, PermissionError):
continue
return results
@router.get("/info") @router.get("/info")

View file

@ -25,6 +25,9 @@ class MountConfig(BaseModel):
async def _run(cmd: list[str]) -> tuple[int, str, str]: async def _run(cmd: list[str]) -> tuple[int, str, str]:
import shutil
if not shutil.which(cmd[0]):
return 1, "", f"{cmd[0]}: command not found"
proc = await asyncio.create_subprocess_exec( proc = await asyncio.create_subprocess_exec(
*cmd, *cmd,
stdout=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,
@ -195,7 +198,7 @@ async def bridge_ws(websocket: WebSocket):
seen_files = current_paths seen_files = current_paths
await asyncio.sleep(5) await asyncio.sleep(5)
except WebSocketDisconnect: except (WebSocketDisconnect, RuntimeError):
pass pass
except Exception: except Exception:
log.exception("ASI Bridge WS error") log.exception("ASI Bridge WS error")

View file

@ -122,7 +122,7 @@ async def service_logs(websocket: WebSocket, unit: str):
"unit": unit, "unit": unit,
"line": line.decode(errors="replace").rstrip(), "line": line.decode(errors="replace").rstrip(),
}) })
except WebSocketDisconnect: except (WebSocketDisconnect, RuntimeError):
pass pass
except Exception: except Exception:
log.exception("log stream error for %s", unit) log.exception("log stream error for %s", unit)

View file

@ -34,6 +34,9 @@ class TimezoneRequest(BaseModel):
async def _run(cmd: list[str]) -> tuple[int, str, str]: async def _run(cmd: list[str]) -> tuple[int, str, str]:
import shutil
if not shutil.which(cmd[0]):
return 1, "", f"{cmd[0]}: command not found"
proc = await asyncio.create_subprocess_exec( proc = await asyncio.create_subprocess_exec(
*cmd, *cmd,
stdout=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE,

View file

@ -160,12 +160,15 @@
const btn = document.createElement('button'); const btn = document.createElement('button');
btn.className = 'osk-key ' + className; btn.className = 'osk-key ' + className;
btn.textContent = label; btn.textContent = label;
let touchFired = false;
btn.addEventListener('touchstart', (e) => { btn.addEventListener('touchstart', (e) => {
e.preventDefault(); e.preventDefault();
touchFired = true;
handler(); handler();
}); });
btn.addEventListener('click', (e) => { btn.addEventListener('click', (e) => {
e.preventDefault(); e.preventDefault();
if (touchFired) { touchFired = false; return; }
handler(); handler();
}); });
return btn; return btn;

View file

@ -1,13 +1,13 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Atlus installer — targets DietPi, Armbian, Debian, Ubuntu # Atlus installer — targets DietPi, Armbian, Debian, Ubuntu
# Usage: curl -sSL https://raw.githubusercontent.com/YOUR_REPO/atlus/main/install.sh | bash # Usage: curl -sSL https://git.bytestud.io/roberts/atlus/raw/branch/main/install.sh | sudo bash
set -euo pipefail set -euo pipefail
INSTALL_DIR="/opt/atlus" INSTALL_DIR="/opt/atlus"
CONFIG_DIR="/etc/atlus" CONFIG_DIR="/etc/atlus"
DATA_DIR="/var/lib/atlus" DATA_DIR="/var/lib/atlus"
SERVICE_FILE="/etc/systemd/system/atlus.service" SERVICE_FILE="/etc/systemd/system/atlus.service"
REPO_URL="https://github.com/YOUR_REPO/atlus.git" REPO_URL="https://git.bytestud.io/roberts/atlus.git"
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Helpers # Helpers