josephrw commited on
Commit
e0cbd7a
·
verified ·
1 Parent(s): 6cdfba9

Upload rm_proxy_colab.ipynb with huggingface_hub

Browse files
Files changed (1) hide show
  1. rm_proxy_colab.ipynb +144 -0
rm_proxy_colab.ipynb ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "nbformat": 4,
3
+ "nbformat_minor": 0,
4
+ "metadata": {
5
+ "colab": {
6
+ "name": "RM API Proxy",
7
+ "provenance": [],
8
+ "toc_visible": true
9
+ },
10
+ "kernelspec": {
11
+ "name": "python3",
12
+ "display_name": "Python 3"
13
+ }
14
+ },
15
+ "cells": [
16
+ {
17
+ "cell_type": "markdown",
18
+ "metadata": {},
19
+ "source": [
20
+ "# RM API Proxy — Colab Backup\n",
21
+ "\n",
22
+ "Runs a FastAPI proxy on Colab that forwards requests to rentmasseur.com.\n",
23
+ "Bypasses Cloudflare IP blocks on GitHub Actions.\n",
24
+ "\n",
25
+ "**Setup:**\n",
26
+ "1. Run all cells\n",
27
+ "2. Copy the ngrok URL\n",
28
+ "3. Set it as `PROXY_URL` GitHub secret"
29
+ ]
30
+ },
31
+ {
32
+ "cell_type": "code",
33
+ "execution_count": null,
34
+ "metadata": {},
35
+ "outputs": [],
36
+ "source": [
37
+ "!pip install fastapi uvicorn pyngrok httpx -q"
38
+ ]
39
+ },
40
+ {
41
+ "cell_type": "code",
42
+ "execution_count": null,
43
+ "metadata": {},
44
+ "outputs": [],
45
+ "source": [
46
+ "PROXY_SECRET = 'rm-proxy-2026' # @param {type:'string'}\n",
47
+ "NGROK_AUTHTOKEN = '' # @param {type:'string'}\n",
48
+ "\n",
49
+ "from pyngrok import ngrok\n",
50
+ "ngrok.set_auth_token(NGROK_AUTHTOKEN)"
51
+ ]
52
+ },
53
+ {
54
+ "cell_type": "code",
55
+ "execution_count": null,
56
+ "metadata": {},
57
+ "outputs": [],
58
+ "source": [
59
+ "%%writefile proxy_app.py\n",
60
+ "import os, httpx\n",
61
+ "from fastapi import FastAPI, Request, Response, HTTPException\n",
62
+ "from fastapi.middleware.cors import CORSMiddleware\n",
63
+ "\n",
64
+ "UPSTREAM = 'https://rentmasseur.com'\n",
65
+ "PROXY_SECRET = os.environ.get('PROXY_SECRET', 'rm-proxy-2026')\n",
66
+ "\n",
67
+ "app = FastAPI()\n",
68
+ "app.add_middleware(CORSMiddleware, allow_origins=['*'], allow_methods=['*'], allow_headers=['*'])\n",
69
+ "\n",
70
+ "@app.get('/')\n",
71
+ "async def health():\n",
72
+ " return {'status': 'ok', 'proxy': 'rm-api-colab'}\n",
73
+ "\n",
74
+ "@app.api_route('/{path:path}', methods=['GET','POST','PUT','DELETE','PATCH','OPTIONS'])\n",
75
+ "async def proxy(path: str, request: Request):\n",
76
+ " client_secret = request.headers.get('X-Proxy-Secret', '')\n",
77
+ " if client_secret != PROXY_SECRET:\n",
78
+ " raise HTTPException(status_code=401, detail='unauthorized')\n",
79
+ " upstream_url = f'{UPSTREAM}/{path}'\n",
80
+ " if request.url.query:\n",
81
+ " upstream_url += f'?{request.url.query}'\n",
82
+ " headers = {\n",
83
+ " 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36',\n",
84
+ " 'Accept': 'application/json, text/plain, */*',\n",
85
+ " 'Accept-Language': 'en-US,en;q=0.9',\n",
86
+ " 'Origin': UPSTREAM,\n",
87
+ " 'Referer': UPSTREAM + '/settings',\n",
88
+ " }\n",
89
+ " auth = request.headers.get('Authorization')\n",
90
+ " if auth:\n",
91
+ " headers['Authorization'] = auth\n",
92
+ " ct = request.headers.get('Content-Type')\n",
93
+ " if ct:\n",
94
+ " headers['Content-Type'] = ct\n",
95
+ " body = None\n",
96
+ " if request.method not in ('GET','HEAD','OPTIONS'):\n",
97
+ " body = await request.body()\n",
98
+ " async with httpx.AsyncClient(timeout=30.0, follow_redirects=True) as client:\n",
99
+ " try:\n",
100
+ " resp = await client.request(method=request.method, url=upstream_url, headers=headers, content=body)\n",
101
+ " return Response(content=resp.content, status_code=resp.status_code, headers=dict(resp.headers), media_type=resp.headers.get('content-type','application/json'))\n",
102
+ " except httpx.TimeoutException:\n",
103
+ " raise HTTPException(status_code=504, detail='upstream timeout')\n",
104
+ " except Exception as e:\n",
105
+ " raise HTTPException(status_code=502, detail=f'proxy error: {str(e)}')"
106
+ ]
107
+ },
108
+ {
109
+ "cell_type": "code",
110
+ "execution_count": null,
111
+ "metadata": {},
112
+ "outputs": [],
113
+ "source": [
114
+ "import subprocess, threading, time, os\n",
115
+ "os.environ['PROXY_SECRET'] = PROXY_SECRET\n",
116
+ "\n",
117
+ "# Start uvicorn in background\n",
118
+ "def run_server():\n",
119
+ " os.system('uvicorn proxy_app:app --host 0.0.0.0 --port 8000 &')\n",
120
+ "\n",
121
+ "threading.Thread(target=run_server, daemon=True).start()\n",
122
+ "time.sleep(3)\n",
123
+ "\n",
124
+ "# Expose via ngrok\n",
125
+ "public_url = ngrok.connect(8000)\n",
126
+ "print(f'✅ Proxy URL: {public_url}')\n",
127
+ "print(f'Set PROXY_URL secret to: {public_url}')\n",
128
+ "print(f'PROXY_SECRET: {PROXY_SECRET}')"
129
+ ]
130
+ },
131
+ {
132
+ "cell_type": "code",
133
+ "execution_count": null,
134
+ "metadata": {},
135
+ "outputs": [],
136
+ "source": [
137
+ "# Test the proxy\n",
138
+ "import requests\n",
139
+ "r = requests.get(str(public_url) + '/', headers={'X-Proxy-Secret': PROXY_SECRET})\n",
140
+ "print(f'Health: {r.status_code} {r.json()}')"
141
+ ]
142
+ }
143
+ ]
144
+ }