Download scripts/lan_launcher.py from deeep-sec/campus-placement-engine: direct link, hf CLI and curl.
- Browser
- Download file 5.72 kB
-
https://huggingface.co/deeep-sec/campus-placement-engine/resolve/main/scripts/lan_launcher.py
- Command line
-
hf download hf://deeep-sec/campus-placement-engine/scripts/lan_launcher.py
-
curl -L -o lan_launcher.py https://huggingface.co/deeep-sec/campus-placement-engine/resolve/main/scripts/lan_launcher.py
5.72 kB
| """ | |
| Single-Command Local & LAN Institutional Placement Engine Launcher. | |
| Detects LAN network interface, runs migrations, verifies frontend assets, | |
| and launches the unified offline server. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import socket | |
| import subprocess | |
| import sys | |
| PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..")) | |
| if PROJECT_ROOT not in sys.path: | |
| sys.path.insert(0, PROJECT_ROOT) | |
| def get_primary_lan_ip() -> str: | |
| """Detects active physical LAN IPv4 address without making outbound internet connections.""" | |
| s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) | |
| try: | |
| # Routing table lookup to private IP space without sending packets | |
| s.connect(("10.255.255.255", 1)) | |
| ip = s.getsockname()[0] | |
| if ip and not ip.startswith("127.") and not ip.startswith("169.254."): | |
| return ip | |
| except Exception: | |
| pass | |
| finally: | |
| s.close() | |
| try: | |
| hostname = socket.gethostname() | |
| candidates = socket.gethostbyname_ex(hostname)[2] | |
| # Prefer physical / non-VMware interfaces | |
| for ip in candidates: | |
| if not ip.startswith("127.") and not ip.startswith("169.254.") and not ip.startswith("192.168.65.") and not ip.startswith("192.168.83."): | |
| return ip | |
| for ip in candidates: | |
| if not ip.startswith("127.") and not ip.startswith("169.254."): | |
| return ip | |
| return "127.0.0.1" | |
| except Exception: | |
| return "127.0.0.1" | |
| def get_all_lan_ips() -> list[str]: | |
| """Returns all reachable non-loopback IPv4 addresses.""" | |
| try: | |
| hostname = socket.gethostname() | |
| candidates = socket.gethostbyname_ex(hostname)[2] | |
| return [ip for ip in candidates if not ip.startswith("127.") and not ip.startswith("169.254.")] | |
| except Exception: | |
| return [get_primary_lan_ip()] | |
| def print_banner(lan_ip: str, port: int = 8000) -> None: | |
| all_ips = get_all_lan_ips() | |
| is_offline = (lan_ip == "127.0.0.1" and len([ip for ip in all_ips if ip != "127.0.0.1"]) == 0) | |
| print("=" * 76) | |
| print(" INSTITUTIONAL PLACEMENT ELIGIBILITY & SCHEDULING ENGINE") | |
| if is_offline: | |
| print(" 100% OFFLINE STANDALONE MODE (NO NETWORK REQUIRED)") | |
| else: | |
| print(" HYBRID PUBLIC CLOUD & INSTITUTIONAL NETWORK DEPLOYMENT") | |
| print("=" * 76) | |
| print(f" [+] Status: ONLINE (READY FOR TRAFFIC)") | |
| if is_offline: | |
| print(f" [+] Network: OFFLINE (NO INTERNET OR LAN REQUIRED)") | |
| else: | |
| print(f" [+] Network: CONNECTED ({lan_ip})") | |
| print(f" [+] Security: Role-Based RBAC & Encrypted Student PII") | |
| print(f" [+] Storage Engine: SQLite WAL Mode (Local Database)") | |
| print(f" [+] Constraint Solver: Google OR-Tools CP-SAT (Local In-Memory)") | |
| print(" " + "-" * 70) | |
| print(f" --> Local Browser URL: http://localhost:{port}") | |
| if not is_offline: | |
| print(f" --> Primary LAN Access: http://{lan_ip}:{port}") | |
| for alt_ip in all_ips: | |
| if alt_ip != lan_ip and not alt_ip.startswith("192.168.65.") and not alt_ip.startswith("192.168.83."): | |
| print(f" --> Alternate LAN/Hotspot: http://{alt_ip}:{port}") | |
| print(" " + "-" * 70) | |
| print(f" SHARE THIS LINK WITH ANYONE ON YOUR WI-FI / LAN NETWORK:") | |
| print(f" >>> http://{lan_ip}:{port} <<<") | |
| else: | |
| print(f" --> Alternate Loopback: http://127.0.0.1:{port}") | |
| print(" " + "-" * 70) | |
| print(" [!] OFFLINE STANDALONE: Running 100% locally on this machine.") | |
| print(f" [!] Open http://localhost:{port} in any browser (Chrome, Edge, Firefox).") | |
| print(" " + "-" * 70) | |
| print(" Default Officer Login: username='officer', password='officer123'") | |
| print(" Default Student Login: roll_no='BT210001' or 'PIPE_001', code='123456'") | |
| print("=" * 76) | |
| sys.stdout.flush() | |
| def main() -> None: | |
| port = int(os.getenv("PORT", "8000")) | |
| host = os.getenv("HOST", "0.0.0.0") | |
| # 1. Run migrations | |
| print("[*] Verifying database schema and migrations...") | |
| try: | |
| subprocess.run([sys.executable, "-m", "alembic", "-c", "backend/alembic.ini", "upgrade", "head"], check=True) | |
| except Exception as exc: | |
| print(f"[!] Migration notice: {exc}. Verifying schema directly...") | |
| from backend.app.storage.database import Base, engine | |
| Base.metadata.create_all(bind=engine) | |
| # 2. Seed baseline accounts | |
| print("[*] Seeding default institutional accounts...") | |
| from backend.app.api.auth.seeder import seed_default_accounts | |
| seed_default_accounts() | |
| # 3. Check frontend dist | |
| dist_index = os.path.abspath(os.path.join(os.path.dirname(__file__), "../frontend/dist/index.html")) | |
| if not os.path.exists(dist_index): | |
| print("[*] Compiled frontend not found. Building production bundle...") | |
| subprocess.run(["npm", "run", "build"], cwd=os.path.abspath(os.path.join(os.path.dirname(__file__), "../frontend")), check=True) | |
| lan_ip = get_primary_lan_ip() | |
| print_banner(lan_ip, port) | |
| # 4. Optional browser auto-open | |
| if os.getenv("AUTO_OPEN_BROWSER", "0") == "1": | |
| try: | |
| import threading | |
| import time | |
| import webbrowser | |
| def _open(): | |
| time.sleep(1.2) | |
| webbrowser.open(f"http://localhost:{port}") | |
| threading.Thread(target=_open, daemon=True).start() | |
| except Exception: | |
| pass | |
| # 5. Launch unified server | |
| import uvicorn | |
| uvicorn.run("backend.app.api.main:app", host=host, port=port, log_level="info") | |
| if __name__ == "__main__": | |
| main() | |