From 9323ed8ac838f9f4519cb8d64b2a54089126769a Mon Sep 17 00:00:00 2001 From: codevski <1435321+codevski@users.noreply.github.com> Date: Sat, 18 Apr 2026 12:13:11 +1000 Subject: [PATCH] Add settings modal and remove passive port options Expose configurable FTP port and root directory (defaults 2121 and /) and remove passive port fields and related validation from frontend and backend. Bump package version to 0.1.1 and update CHANGELOG --- CHANGELOG.md | 14 ++++++++++++++ main.py | 25 ------------------------- package.json | 2 +- src/SettingsModal.tsx | 28 +--------------------------- 4 files changed, 16 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2c2bc7..fba2b10 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to this project will be documented here. +## [0.1.1] - 2026-04-18 + +### Added +- Settings modal accessible from the QAM panel +- Configurable FTP port (default 2121) +- Configurable root directory (default /) + +### Changed +- Server state now updates reactively via events instead of polling +- Root directory setting now properly chroots the FTP session + +### Fixed +- Server getting stuck in a "running but untoggleable" state after rapid start/stop cycles, requiring a reboot to recover + ## [0.1.0] - 2026-04-17 ### Added diff --git a/main.py b/main.py index b6d50bb..9336868 100644 --- a/main.py +++ b/main.py @@ -187,14 +187,6 @@ async def save_settings(self, new_settings: dict) -> dict: port = int(new_settings.get("port", self.DEFAULTS["port"])) root = str(new_settings.get("root_dir", self.DEFAULTS["root_dir"])) - p_start = int( - new_settings.get( - "passive_port_start", self.DEFAULTS["passive_port_start"] - ) - ) - p_end = int( - new_settings.get("passive_port_end", self.DEFAULTS["passive_port_end"]) - ) if not (1024 <= port <= 65535): return {"success": False, "error": "Port must be 1024–65535."} @@ -203,26 +195,9 @@ async def save_settings(self, new_settings: dict) -> dict: "success": False, "error": "Root must be an absolute path.", } - if not (1024 <= p_start <= 65535 and 1024 <= p_end <= 65535): - return { - "success": False, - "error": "Passive ports must be 1024–65535.", - } - if p_end <= p_start: - return { - "success": False, - "error": "Passive end must be greater than start.", - } - if p_start <= port <= p_end: - return { - "success": False, - "error": "Control port must not sit inside the passive range.", - } self._settings.setSetting("port", port) self._settings.setSetting("root_dir", root) - self._settings.setSetting("passive_port_start", p_start) - self._settings.setSetting("passive_port_end", p_end) self._settings.commit() restarted = False diff --git a/package.json b/package.json index 2652f4a..19d0da2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "decky-ftpd", - "version": "0.1.0", + "version": "0.1.1", "description": "FTP server for Steam Deck Game Mode, no desktop required", "type": "module", "scripts": { diff --git a/src/SettingsModal.tsx b/src/SettingsModal.tsx index fd788da..b1e657f 100644 --- a/src/SettingsModal.tsx +++ b/src/SettingsModal.tsx @@ -5,15 +5,11 @@ import { useEffect, useState } from "react"; interface FtpdSettings { port: number; root_dir: string; - passive_port_start: number; - passive_port_end: number; } const DEFAULTS: FtpdSettings = { port: 2121, root_dir: "/", - passive_port_start: 50000, - passive_port_end: 50100, }; const getSettings = callable<[], FtpdSettings>("get_settings"); @@ -29,12 +25,7 @@ interface Props { export default function SettingsModal({ closeModal }: Props) { const [portStr, setPortStr] = useState(String(DEFAULTS.port)); const [rootDir, setRootDir] = useState(DEFAULTS.root_dir); - const [passStartStr, setPassStartStr] = useState( - String(DEFAULTS.passive_port_start), - ); - const [passEndStr, setPassEndStr] = useState( - String(DEFAULTS.passive_port_end), - ); + const [loading, setLoading] = useState(true); const [saving, setSaving] = useState(false); @@ -44,8 +35,6 @@ export default function SettingsModal({ closeModal }: Props) { const cur = s ?? DEFAULTS; setPortStr(String(cur.port)); setRootDir(cur.root_dir); - setPassStartStr(String(cur.passive_port_start)); - setPassEndStr(String(cur.passive_port_end)); }) .catch((e) => console.error("[decky-ftpd] get_settings failed", e)) .finally(() => setLoading(false)); @@ -57,8 +46,6 @@ export default function SettingsModal({ closeModal }: Props) { const res = await saveSettings({ port: portStr, root_dir: rootDir.trim(), - passive_port_start: passStartStr, - passive_port_end: passEndStr, }); if (res.success) { toaster.toast({ @@ -104,19 +91,6 @@ export default function SettingsModal({ closeModal }: Props) { value={rootDir} onChange={(e) => setRootDir(e.target.value)} /> - setPassStartStr(e.target.value)} - /> - setPassEndStr(e.target.value)} - /> -
{saving ? "Saving…" : "Save & Restart Server"}