Skip to content

Commit 42f4bf5

Browse files
Merge pull request #23 from AhYasse/main
fix: resolve TypeScript import paths and add build configuration
2 parents e845b00 + ac6817f commit 42f4bf5

13 files changed

Lines changed: 2676 additions & 374 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,14 +47,15 @@ A modern UI to visualize the network and chat with models.
4747

4848
**Run Locally:**
4949
```bash
50-
cd desktop-app
50+
cd electron-app
5151
npm install # First time only
5252
npm run dev
5353
```
5454
*Usage:*
5555
- Open the App.
5656
- It connects to `http://localhost:4002` by default.
5757
- Go to "Chat" to talk to available providers.
58+
- See [MANUAL_TESTING.md](MANUAL_TESTING.md) for detailed testing steps.
5859

5960
---
6061

bee2bee/__main__.py

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from .hf import has_transformers, has_datasets, load_model_and_tokenizer, export_torchscript, export_onnx
77
from .p2p import generate_join_link, parse_join_link
88
from .p2p_runtime import run_p2p_node, P2PNode
9+
from .nat import auto_port_forward, get_public_ip
910

1011
console = Console()
1112

@@ -183,6 +184,135 @@ def api(host, port, p2p_port, bootstrap):
183184
console.print(f"[bold green]🚀 Starting Main Point API on http://{host}:{port}[/bold green]")
184185
uvicorn.run("bee2bee.api:app", host=host, port=port, reload=False)
185186

187+
@cli.command()
188+
@click.option('--port', default=4003, help='Port to forward')
189+
@click.option('--test/--no-test', default=True, help='Test connection after forwarding')
190+
def auto_forward(port, test):
191+
"""Automatically forward a port with UPnP and fallbacks"""
192+
async def _run():
193+
console.print(f"[dim]Starting auto port forwarding for port {port}...[/dim]")
194+
195+
# Try auto forwarding
196+
result = await auto_port_forward(port, "TCP")
197+
198+
if result.success:
199+
if result.method == "UPnP":
200+
console.print(f"[green]✅ UPnP Port Forwarding SUCCESS![/green]")
201+
else:
202+
console.print(f"[green]✅ {result.method} SUCCESS! (Fallback)[/green]")
203+
204+
console.print(f" External: {result.external_ip}:{result.external_port}")
205+
console.print(f" Method: {result.method}")
206+
console.print(f" Details: {result.details}")
207+
208+
if result.fallback_used:
209+
console.print(f"[yellow]⚠️ Using fallback method - manual forwarding may still be needed[/yellow]")
210+
211+
# Update config if this is the default P2P port
212+
if port == 4003:
213+
from .config import set_bootstrap_url
214+
set_bootstrap_url(f"ws://{result.external_ip}:{result.external_port}")
215+
console.print(f"[green]✓ Updated bootstrap_url in config[/green]")
216+
217+
if test:
218+
console.print(f"\n[cyan]Testing connection...[/cyan]")
219+
success = await test_connection(f"{result.external_ip}:{result.external_port}")
220+
if success:
221+
console.print("[green]✅ Connection test successful![/green]")
222+
else:
223+
console.print("[yellow]⚠️ Connection test failed (firewall may be blocking)[/yellow]")
224+
225+
else:
226+
console.print(f"[red]❌ All auto methods failed[/red]")
227+
228+
if result.external_ip:
229+
console.print(f"[yellow]Your public IP is: {result.external_ip}[/yellow]")
230+
console.print(f"[yellow]Manual port forwarding required:[/yellow]")
231+
console.print(f" 1. Go to router admin (192.168.1.1)")
232+
console.print(f" 2. Forward TCP port {port}")
233+
console.print(f" 3. Use: ws://{result.external_ip}:{port}")
234+
235+
asyncio.run(_run())
236+
237+
238+
@cli.command()
239+
@click.option('--port', default=4003, help='Port to check')
240+
def port_status(port):
241+
"""Check port forwarding status"""
242+
async def _run():
243+
from .utils import get_lan_ip
244+
245+
console.print(f"[dim]Checking port {port} status...[/dim]")
246+
247+
# Get network info
248+
lan_ip = get_lan_ip()
249+
250+
console.print(f"\n[cyan]Network Information:[/cyan]")
251+
console.print(f" Local IP: {lan_ip}")
252+
console.print(f" Port: {port}")
253+
254+
# Try auto forwarding
255+
result = await auto_port_forward(port, "TCP")
256+
257+
console.print(f"\n[cyan]Port Forwarding Status:[/cyan]")
258+
if result.success:
259+
if result.method == "UPnP":
260+
status = "[green]✅ AUTO-FORWARDED (UPnP)[/green]"
261+
else:
262+
status = f"[yellow]⚠️ DETECTED ({result.method})[/yellow]"
263+
264+
console.print(f" Status: {status}")
265+
console.print(f" External IP: {result.external_ip}")
266+
console.print(f" External Port: {result.external_port}")
267+
console.print(f" Details: {result.details}")
268+
269+
if result.fallback_used:
270+
console.print(f" [dim](Using fallback method)[/dim]")
271+
272+
else:
273+
console.print(f" Status: [red]❌ NOT FORWARDED[/red]")
274+
275+
if result.external_ip:
276+
console.print(f" Your Public IP: {result.external_ip}")
277+
console.print(f" [yellow]Manual forwarding required[/yellow]")
278+
279+
# Check local port
280+
console.print(f"\n[cyan]Local Port Check:[/cyan]")
281+
if is_port_open_locally(port):
282+
console.print(f" [green]✓ Port {port} is open locally[/green]")
283+
else:
284+
console.print(f" [red]✗ Port {port} is not open locally[/red]")
285+
286+
asyncio.run(_run())
287+
288+
289+
async def test_connection(addr: str) -> bool:
290+
"""Test if address is accessible"""
291+
import websockets
292+
try:
293+
# Add ws:// if not present
294+
if not addr.startswith("ws://"):
295+
addr = f"ws://{addr}"
296+
297+
async with websockets.connect(addr, timeout=5) as ws:
298+
await ws.close()
299+
return True
300+
except Exception:
301+
return False
302+
303+
304+
def is_port_open_locally(port: int) -> bool:
305+
"""Check if port is open locally"""
306+
import socket
307+
try:
308+
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
309+
sock.settimeout(1)
310+
result = sock.connect_ex(('127.0.0.1', port))
311+
sock.close()
312+
return result == 0
313+
except:
314+
return False
315+
186316

187317

188318
if __name__ == "__main__":

0 commit comments

Comments
 (0)