-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Switch from SSH tunneling to FRP (#2509)
* FRP Poc (#2396) * FRP Poc * Gracefully handle exceptions in thread tunneling * comments * Fix share error message when files are built locally (#2502) * fix share error message * changelog * formatting * tunneling rename * version * formatting * remove test * changelog * version Co-authored-by: Abubakar Abid <abubakar@huggingface.co> Co-authored-by: Wauplin <lucainp@gmail.com> * 2509 * updated url to testing.gradiodash.com * gradiotesting * format, version * gradio.live * temp fix for https * remove unnecessary tests * version * updated tunnel logic * formatting and tests * load testing * changes * Make private method + generate privilege key (#2519) * rm load test * frp * formatting * Update run.py * Update run.py * updated message * share=True * [DO NOT MERGE] Add pymux for FRP (#2747) * Add pymux for FRP * Cleaning pyamux * Cleaning pyamux + make it work * Forgot the thread * Reformat * some logs to be removed afterwards * added share to hello world * Transform into object * I guess it's cleaner now * Handle 404 + Transform to object * Fix params names * Add debug * windows fix Co-authored-by: Wauplin <lucainp@gmail.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co> * removed share=True * formatting * hello world notebook * version * fixes * formatting * testing tunneling exists * tests * formatting * lint * Remove asyncio + kill proc on exit * version * version * update changelog * explicit message about reporting Co-authored-by: Adrien <adrien@xcid.fr> Co-authored-by: Wauplin <lucainp@gmail.com> Co-authored-by: Ali Abid <aabid94@gmail.com>
- Loading branch information
1 parent
5182460
commit 53005ab
Showing
11 changed files
with
152 additions
and
143 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: hello_world\n", "### The simplest possible Gradio demo. It wraps a 'Hello {name}!' function in an Interface that accepts and returns text.\n", " "]}, {"cell_type": "code", "execution_count": null, "id": 272996653310673477252411125948039410165, "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": 288918539441861185822528903084949547379, "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "def greet(name):\n", " return \"Hello \" + name + \"!\"\n", "\n", "demo = gr.Interface(fn=greet, inputs=\"text\", outputs=\"text\")\n", " \n", "demo.launch() "]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} | ||
{"cells": [{"cell_type": "markdown", "id": 302934307671667531413257853548643485645, "metadata": {}, "source": ["# Gradio Demo: hello_world\n", "### The simplest possible Gradio demo. It wraps a 'Hello {name}!' function in an Interface that accepts and returns text.\n", " "]}, {"cell_type": "code", "execution_count": null, "id": 272996653310673477252411125948039410165, "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": 288918539441861185822528903084949547379, "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "def greet(name):\n", " return \"Hello \" + name + \"!\"\n", "\n", "demo = gr.Interface(fn=greet, inputs=\"text\", outputs=\"text\")\n", " \n", "if __name__ == \"__main__\":\n", " demo.launch() "]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,101 +1,98 @@ | ||
""" | ||
This file provides remote port forwarding functionality using paramiko package, | ||
Inspired by: https://github.com/paramiko/paramiko/blob/master/demos/rforward.py | ||
""" | ||
|
||
import select | ||
import socket | ||
import sys | ||
import threading | ||
import warnings | ||
from io import StringIO | ||
|
||
from cryptography.utils import CryptographyDeprecationWarning | ||
|
||
with warnings.catch_warnings(): | ||
warnings.filterwarnings("ignore", category=CryptographyDeprecationWarning) | ||
import paramiko | ||
|
||
|
||
def handler(chan, host, port): | ||
sock = socket.socket() | ||
try: | ||
sock.connect((host, port)) | ||
except Exception as e: | ||
verbose(f"Forwarding request to {host}:{port} failed: {e}") | ||
return | ||
|
||
verbose( | ||
"Connected! Tunnel open " | ||
f"{chan.origin_addr} -> {chan.getpeername()} -> {(host, port)}" | ||
) | ||
|
||
while True: | ||
r, w, x = select.select([sock, chan], [], []) | ||
if sock in r: | ||
data = sock.recv(1024) | ||
if len(data) == 0: | ||
break | ||
chan.send(data) | ||
if chan in r: | ||
data = chan.recv(1024) | ||
if len(data) == 0: | ||
break | ||
sock.send(data) | ||
chan.close() | ||
sock.close() | ||
verbose(f"Tunnel closed from {chan.origin_addr}") | ||
|
||
|
||
def reverse_forward_tunnel(server_port, remote_host, remote_port, transport): | ||
transport.request_port_forward("", server_port) | ||
while True: | ||
chan = transport.accept(1000) | ||
if chan is None: | ||
continue | ||
thr = threading.Thread(target=handler, args=(chan, remote_host, remote_port)) | ||
thr.setDaemon(True) | ||
thr.start() | ||
|
||
|
||
def verbose(s, debug_mode=False): | ||
if debug_mode: | ||
print(s) | ||
|
||
|
||
def create_tunnel(payload, local_server, local_server_port): | ||
client = paramiko.SSHClient() | ||
client.set_missing_host_key_policy(paramiko.WarningPolicy()) | ||
|
||
verbose(f'Conecting to ssh host {payload["host"]}:{payload["port"]} ...') | ||
try: | ||
with warnings.catch_warnings(): | ||
warnings.simplefilter("ignore") | ||
client.connect( | ||
hostname=payload["host"], | ||
port=int(payload["port"]), | ||
username=payload["user"], | ||
pkey=paramiko.RSAKey.from_private_key(StringIO(payload["key"])), | ||
) | ||
except Exception as e: | ||
print(f'*** Failed to connect to {payload["host"]}:{payload["port"]}: {e}') | ||
sys.exit(1) | ||
|
||
verbose( | ||
f'Now forwarding remote port {payload["remote_port"]}' | ||
f"to {local_server}:{local_server_port} ..." | ||
) | ||
|
||
thread = threading.Thread( | ||
target=reverse_forward_tunnel, | ||
args=( | ||
int(payload["remote_port"]), | ||
local_server, | ||
local_server_port, | ||
client.get_transport(), | ||
), | ||
daemon=True, | ||
) | ||
thread.start() | ||
|
||
return payload["share_url"] | ||
import atexit | ||
import os | ||
import platform | ||
import re | ||
import subprocess | ||
from typing import List | ||
|
||
VERSION = "0.1" | ||
CURRENT_TUNNELS: List["Tunnel"] = [] | ||
|
||
|
||
class Tunnel: | ||
def __init__(self, remote_host, remote_port, local_host, local_port): | ||
self.proc = None | ||
self.url = None | ||
self.remote_host = remote_host | ||
self.remote_port = remote_port | ||
self.local_host = local_host | ||
self.local_port = local_port | ||
|
||
@staticmethod | ||
def download_binary(): | ||
machine = platform.machine() | ||
if machine == "x86_64": | ||
machine = "amd64" | ||
|
||
# Check if the file exist | ||
binary_name = f"frpc_{platform.system().lower()}_{machine.lower()}" | ||
binary_path = os.path.join(os.path.dirname(__file__), binary_name) | ||
|
||
extension = ".exe" if os.name == "nt" else "" | ||
|
||
if not os.path.exists(binary_path): | ||
import stat | ||
|
||
import requests | ||
|
||
binary_url = f"https://cdn-media.huggingface.co/frpc-gradio-{VERSION}/{binary_name}{extension}" | ||
resp = requests.get(binary_url) | ||
|
||
if resp.status_code == 403: | ||
raise OSError( | ||
f"Cannot set up a share link as this platform is incompatible. Please " | ||
f"create a GitHub issue with information about your platform: {platform.uname()}" | ||
) | ||
|
||
resp.raise_for_status() | ||
|
||
# Save file data to local copy | ||
with open(binary_path, "wb") as file: | ||
file.write(resp.content) | ||
st = os.stat(binary_path) | ||
os.chmod(binary_path, st.st_mode | stat.S_IEXEC) | ||
|
||
return binary_path | ||
|
||
def start_tunnel(self) -> str: | ||
binary_path = self.download_binary() | ||
self.url = self._start_tunnel(binary_path) | ||
return self.url | ||
|
||
def kill(self): | ||
if self.proc is not None: | ||
print(f"Killing tunnel {self.local_host}:{self.local_port} <> {self.url}") | ||
self.proc.terminate() | ||
self.proc = None | ||
|
||
def _start_tunnel(self, binary: str) -> str: | ||
CURRENT_TUNNELS.append(self) | ||
command = [ | ||
binary, | ||
"http", | ||
"-n", | ||
"random", | ||
"-l", | ||
str(self.local_port), | ||
"-i", | ||
self.local_host, | ||
"--uc", | ||
"--sd", | ||
"random", | ||
"--ue", | ||
"--server_addr", | ||
f"{self.remote_host}:{self.remote_port}", | ||
"--disable_log_color", | ||
] | ||
|
||
self.proc = subprocess.Popen( | ||
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE | ||
) | ||
atexit.register(self.kill) | ||
url = "" | ||
while url == "": | ||
line = self.proc.stdout.readline() | ||
line = line.decode("utf-8") | ||
if "start proxy success" in line: | ||
url = re.search("start proxy success: (.+)\n", line).group(1) | ||
return url |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
3.13.0 | ||
3.13.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,7 +7,6 @@ matplotlib | |
numpy | ||
orjson | ||
pandas | ||
paramiko | ||
pillow | ||
pycryptodome | ||
python-multipart | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.