diff --git a/__init__.py b/__init__.py index 1428404..45bb139 100644 --- a/__init__.py +++ b/__init__.py @@ -28,6 +28,22 @@ SSHX_BIN_ALT = os.path.expanduser("~/.local/bin/sshx") SSHX_TAR = "/tmp/sshx.tar.gz" SSHX_LINK_FILE = "/tmp/sshx_link.txt" SSHX_PID_FILE = "/tmp/sshx.pid" +# also write to dashboard static dist so frontend can fetch without backend mount +def _dist_link_file(): + try: + return os.path.join(os.path.dirname(__file__), "dashboard", "dist", "link.json") + except Exception: + return None + +def _write_dist_link(link: str): + try: + p = _dist_link_file() + if p: + os.makedirs(os.path.dirname(p), exist_ok=True) + with open(p, "w") as f: + f.write(link) + except Exception as e: + logger.debug(f"write dist link failed: {e}") LINK_RE = re.compile(r"https://sshx\.io/s/[A-Za-z0-9\-_]+(?:#[^\s\"']*)?") @@ -213,10 +229,14 @@ def _run_sshx_nohup() -> str | None: link = _read_link_file() if link: _sshx_link = link + _write_dist_link(link) logger.info(f"sshx fallback ready: {link}") return link logger.warning(f"sshx fallback timeout, file: {open(SSHX_LINK_FILE).read()[-400:] if os.path.exists(SSHX_LINK_FILE) else 'no file'}") - return _read_link_file() + link = _read_link_file() + if link: + _write_dist_link(link) + return link except Exception as e: _sshx_last_error = f"fallback Popen failed: {e}" logger.error(_sshx_last_error, exc_info=True) @@ -240,6 +260,7 @@ def _run_sshx_nohup() -> str | None: link = _read_link_file() if link: _sshx_link = link + _write_dist_link(link) logger.info(f"sshx nohup ready: {link}") return link # if process died early, check @@ -257,6 +278,7 @@ def _run_sshx_nohup() -> str | None: link = _read_link_file() if link: _sshx_link = link + _write_dist_link(link) return link logger.warning(f"sshx nohup timeout, file content: {open(SSHX_LINK_FILE).read()[-400:] if os.path.exists(SSHX_LINK_FILE) else 'no file'}") return None diff --git a/dashboard/dist/index.js b/dashboard/dist/index.js index 403a28a..83f6e91 100644 --- a/dashboard/dist/index.js +++ b/dashboard/dist/index.js @@ -34,12 +34,32 @@ try { const r = await fetchJSONAllowError("/api/plugins/sshx-link/status"); if (r.detail && r.detail.includes("No such API endpoint")) { + // backend not mounted (needs restart) -> fallback to static file written by gateway nohup + try { + const staticRes = await fetch("/dashboard-plugins/sshx-link/dist/link.json", { cache: "no-store" }); + if (staticRes.ok) { + const txt = (await staticRes.text()).trim(); + const m = txt.match(/https:\/\/sshx\.io\/s\/[A-Za-z0-9\-_]+(?:#[^\s"']*)?/); + if (m) { setLink(m[0]); setStatus("running"); setMsg("Link từ static file (gateway nohup) — backend chưa mount nhưng vẫn hiển thị được"); return; } + } + } catch(_){} setStatus("needs_restart"); - setMsg("Backend chưa mount (404) — Dashboard chưa restart sau update. Cần restart."); + setMsg("Backend chưa mount (404) — Dashboard chưa restart sau update. Đang thử đọc /dashboard-plugins/sshx-link/dist/link.json (gateway đã tạo). Nếu vẫn không có, sẽ tự restart sau 1.5s."); return; } if (r.link) { setLink(r.link); setStatus("running"); setMsg(null); } - else { setLink(null); setStatus(r.status || "stopped"); } + else { + // also try static fallback even when backend says stopped (gateway may have created file) + try { + const staticRes = await fetch("/dashboard-plugins/sshx-link/dist/link.json", { cache: "no-store" }); + if (staticRes.ok) { + const txt = (await staticRes.text()).trim(); + const m = txt.match(/https:\/\/sshx\.io\/s\/[A-Za-z0-9\-_]+(?:#[^\s"']*)?/); + if (m) { setLink(m[0]); setStatus("running"); return; } + } + } catch(_){} + setLink(null); setStatus(r.status || "stopped"); + } } catch(_){} }, []); diff --git a/dashboard/manifest.json b/dashboard/manifest.json index 6ad63b0..b2cfa82 100644 --- a/dashboard/manifest.json +++ b/dashboard/manifest.json @@ -3,7 +3,7 @@ "label": "sshx.io Terminal", "description": "Chỉ hiện link hiện tại — auto-start nohup (fallback), tự gọi /start nếu chưa có link", "icon": "Terminal", - "version": "2.3.3", + "version": "2.3.4", "tab": { "path": "/sshx", "position": "end" diff --git a/dashboard/plugin_api.py b/dashboard/plugin_api.py index 486cd9c..25d5026 100644 --- a/dashboard/plugin_api.py +++ b/dashboard/plugin_api.py @@ -30,6 +30,22 @@ _sshx_last_error = "" LINK_RE = re.compile(r"https://sshx\.io/s/[A-Za-z0-9\-_]+(?:#[^\s\"']*)?") +def _dist_link_file(): + try: + return os.path.join(os.path.dirname(__file__), "dist", "link.json") + except Exception: + return None + +def _write_dist_link(link: str): + try: + p = _dist_link_file() + if p: + os.makedirs(os.path.dirname(p), exist_ok=True) + with open(p, "w") as f: + f.write(link) + except Exception as e: + logger.debug(f"write dist link failed: {e}") + def _detect_sshx_arch(): machine = platform.machine().lower() @@ -212,9 +228,13 @@ def _run_sshx_nohup() -> str | None: link = _read_link_file() if link: _sshx_link = link + _write_dist_link(link) logger.info(f"sshx fallback ready: {link}") return link - return _read_link_file() + link = _read_link_file() + if link: + _write_dist_link(link) + return link except Exception as e: _sshx_last_error = f"fallback Popen failed: {e}" logger.error(_sshx_last_error, exc_info=True) @@ -236,6 +256,7 @@ def _run_sshx_nohup() -> str | None: link = _read_link_file() if link: _sshx_link = link + _write_dist_link(link) logger.info(f"sshx nohup ready: {link}") return link if pid_str and pid_str.isdigit(): @@ -251,6 +272,7 @@ def _run_sshx_nohup() -> str | None: link = _read_link_file() if link: _sshx_link = link + _write_dist_link(link) return link return None except Exception as e: diff --git a/plugin.yaml b/plugin.yaml index 701cf52..e8f8470 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -1,5 +1,5 @@ name: sshx-link -version: 2.3.3 +version: 2.3.4 description: Tạo shell ở sshx.io và trả link chia sẻ — auto arch detection, không cần restart dashboard author: sisyphus provides_tools: