| import httpx |
| import asyncio |
| from websockets import ClientConnection |
| from websockets.asyncio.client import connect |
| from fastapi import FastAPI, Request, Response, WebSocket |
| from fastapi.responses import JSONResponse |
|
|
| app = FastAPI(title="Telegram Proxy") |
|
|
| TELEGRAM_HOST = 'square-term-f712.valerazbanovqs.workers.dev' |
|
|
| async def autocancel(request, coroutine): |
|
|
| async def listen_for_disconnect(): |
| while True: |
| message = await request.receive() |
| if message["type"] == "http.disconnect": |
| break |
| await asyncio.sleep(1) |
| return JSONResponse( |
| status_code=499, |
| content=dict(user_message="Запрос был отменен"), |
| ) |
|
|
| async def process_request(): |
| return await coroutine |
|
|
| process_request_task = asyncio.create_task(process_request()) |
|
|
| tasks = [ |
| process_request_task, |
| asyncio.create_task(listen_for_disconnect()), |
| ] |
| tasks = [task for task in tasks if task is not None] |
|
|
| done, pending = await asyncio.wait( |
| tasks, |
| return_when=asyncio.FIRST_COMPLETED |
| ) |
|
|
| for task in pending: |
| task.cancel() |
|
|
| for task in pending: |
| try: |
| await task |
| except asyncio.CancelledError: |
| ... |
| except: |
| pass |
|
|
| return next(iter(done)).result() |
|
|
| def _prepare_headers(headers: dict): |
| if "authorization" in headers: del headers["authorization"] |
| headers["host"] = TELEGRAM_HOST |
| return headers |
|
|
| async def _proxy_request(request: Request) -> Response: |
| base_url = f'https://{TELEGRAM_HOST}/' |
| url = '/' + request.path_params['url'] |
|
|
| headers = _prepare_headers(dict(request.headers)) |
|
|
| query_params = dict(request.query_params) |
|
|
| content = await request.body() |
|
|
| async with httpx.AsyncClient(base_url=base_url, trust_env=False) as session: |
| response = await session.request( |
| method=request.method, |
| url=url, |
| headers=headers, |
| params=query_params, |
| content=content, |
| timeout=None, |
| ) |
| |
| return Response( |
| content=response.content, |
| status_code=response.status_code, |
| headers=dict(response.headers) |
| ) |
|
|
| async def proxy_request(request): |
| return await autocancel(request, _proxy_request(request)) |
|
|
|
|
| @app.get("/base/telegram_api/{url:path}", summary='Проксирует все методы get в телеграм апи') |
| async def get_base_service_path( |
| request: Request, |
| url: str, |
| ): |
| return await proxy_request(request) |
|
|
|
|
| @app.post("/base/telegram_api/{url:path}", summary='Проксирует все методы post в телеграм апи') |
| async def post_base_service_path( |
| request: Request, |
| url: str, |
| ): |
| return await proxy_request(request) |
|
|
|
|
| @app.put("/base/telegram_api/{url:path}", summary='Проксирует все методы put в телеграм апи') |
| async def put_base_service_path( |
| request: Request, |
| url: str, |
| ): |
| return await proxy_request(request) |
|
|
|
|
| @app.delete("/base/telegram_api/{url:path}", summary='Проксирует все методы delete в телеграм апи') |
| async def delete_base_service_path( |
| request: Request, |
| url: str, |
| ): |
| return await proxy_request(request) |
|
|
|
|
| @app.patch("/base/telegram_api/{url:path}", summary='Проксирует все методы patch в телеграм апи') |
| async def patch_base_service_path( |
| request: Request, |
| url: str, |
| ): |
| return await proxy_request(request) |
|
|
|
|
| @app.options("/base/telegram_api/{url:path}", summary='Проксирует все методы options в телеграм апи') |
| async def options_base_service_path( |
| request: Request, |
| url: str, |
| ): |
| return await proxy_request(request) |
|
|
|
|
| @app.head("/base/telegram_api/{url:path}", summary='Проксирует все методы head в телеграм апи') |
| async def head_base_service_path( |
| request: Request, |
| url: str, |
| ): |
| return await proxy_request(request) |
|
|
|
|
| @app.websocket("/base/telegram_api/{url:path}") |
| async def proxy_websocket(websocket: WebSocket, url: str): |
| await websocket.accept() |
| |
| target_url = f"wss://{TELEGRAM_IP}/{url}" |
| headers = _prepare_headers(dict(websocket.headers)) |
|
|
| async def forward(source: ClientConnection, destination: ClientConnection): |
| async for message in source: |
| await destination.send(message) |
|
|
| try: |
| async with connect(target_url, additional_headers=headers, server_hostname=TELEGRAM_HOST) as target_ws: |
| await asyncio.gather( |
| forward(websocket, target_ws), |
| forward(target_ws, websocket) |
| ) |
| finally: |
| await websocket.close() |
|
|
| @app.get("/test-connection-google") |
| async def test_connection_google(): |
| try: |
| async with httpx.AsyncClient() as client: |
| resp = await client.get("https://google.com", timeout=5.0) |
| return {"status": "google_ok", "code": resp.status_code} |
| except Exception as e: |
| return {"status": "error", "message": str(e)} |
|
|
|
|
| @app.get("/test-connection-telegram") |
| async def test_connection_telegram(): |
| try: |
| async with httpx.AsyncClient() as client: |
| resp = await client.get("https://api.telegram.org", timeout=5.0) |
| return {"status": "telegram_ok", "code": resp.status_code} |
| except Exception as e: |
| return {"status": "error", "message": str(e)} |
|
|
|
|
| if __name__ == "__main__": |
| import uvicorn |
| uvicorn.run(app, host="localhost", port=7860) |
|
|