From ff09c2d5f6d705af9617891994e47f47377f0fdd Mon Sep 17 00:00:00 2001 From: 7000pctAUTO Date: Thu, 29 Jan 2026 13:53:46 +0000 Subject: [PATCH] Initial upload: API Mock CLI v0.1.0 --- src/core/tunnel.py | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/core/tunnel.py diff --git a/src/core/tunnel.py b/src/core/tunnel.py new file mode 100644 index 0000000..068130f --- /dev/null +++ b/src/core/tunnel.py @@ -0,0 +1,42 @@ +import os +import time +from typing import Optional, Dict, Any +from pyngrok import ngrok + + +class TunnelError(Exception): + pass + + +class Tunnel: + def __init__(self, authtoken: Optional[str] = None): + self.authtoken = authtoken or os.environ.get("NGROK_AUTHTOKEN") + self.tunnel: Optional[ngrok.HTTPEndpoint] = None + self.url: Optional[str] = None + + def start(self, port: int, region: str = "us") -> str: + try: + if self.authtoken: + ngrok.set_auth_token(self.authtoken) + self.tunnel = ngrok.connect(port, "http") + self.url = self.tunnel.public_url if self.tunnel else None + if not self.url: + raise TunnelError("Failed to get tunnel URL") + return self.url + except Exception as e: + raise TunnelError(f"Failed to create tunnel: {e}") + + def stop(self) -> None: + try: + if self.tunnel: + ngrok.disconnect(self.tunnel.public_url) + self.tunnel = None + self.url = None + except Exception: + pass + + def get_url(self) -> Optional[str]: + return self.url + + def is_active(self) -> bool: + return self.tunnel is not None and self.url is not None