summaryrefslogtreecommitdiffstats
path: root/ttun_server
diff options
context:
space:
mode:
authorGravatar Tom van der Lee <tom@vanderlee.io>2026-06-30 22:46:55 +0200
committerGravatar Tom van der Lee <tom@vanderlee.io>2026-06-30 22:46:55 +0200
commit12f2e24e2154113a6329d74aa556ae23506c34e1 (patch)
treee9c685e0a30f819f6b9e89a4f169cfe637dcbbd4 /ttun_server
parentc4f33b3576e3a4a7f70b3d681fadae45f73ae31e (diff)
downloadserver-v3.tar.gz
server-v3.tar.bz2
server-v3.zip
WIPv3
Diffstat (limited to 'ttun_server')
-rw-r--r--ttun_server/__init__.py15
-rw-r--r--ttun_server/endpoints.py97
2 files changed, 48 insertions, 64 deletions
diff --git a/ttun_server/__init__.py b/ttun_server/__init__.py
index 2f8fed0..6c77858 100644
--- a/ttun_server/__init__.py
+++ b/ttun_server/__init__.py
@@ -1,28 +1,31 @@
1import logging 1import logging
2import os 2import os
3 3
4from starlette.applications import Starlette 4from fastapi import FastAPI
5from starlette.routing import Route, WebSocketRoute, Host, Router 5from starlette.routing import Host, Route, Router, WebSocketRoute
6 6
7from ttun_server.endpoints import Proxy, Health 7from ttun_server.endpoints import health, proxy
8from .websockets import WebsocketProxy, Tunnel 8from .websockets import WebsocketProxy, Tunnel
9 9
10logging.basicConfig(level=getattr(logging, os.environ.get('LOG_LEVEL', 'INFO'))) 10logging.basicConfig(level=getattr(logging, os.environ.get('LOG_LEVEL', 'INFO')))
11 11
12base_router = Router(routes=[ 12base_router = Router(routes=[
13 Route('/health/', Health), 13 Route('/health/', health),
14 WebSocketRoute('/tunnel/', Tunnel) 14 WebSocketRoute('/tunnel/', Tunnel)
15]) 15])
16 16
17server = Starlette( 17server = FastAPI(
18 debug=True, 18 debug=True,
19 routes=[ 19 routes=[
20 Host(os.environ['TUNNEL_DOMAIN'], base_router, 'base'), 20 Host(os.environ['TUNNEL_DOMAIN'], base_router, 'base'),
21 Route('/{path:path}', Proxy), 21 Route('/{path:path}', proxy),
22 WebSocketRoute('/{path:path}', WebsocketProxy) 22 WebSocketRoute('/{path:path}', WebsocketProxy)
23 ] 23 ]
24) 24)
25 25
26server.post()
27
28
26try: 29try:
27 from ._version import version 30 from ._version import version
28 __version__ = version 31 __version__ = version
diff --git a/ttun_server/endpoints.py b/ttun_server/endpoints.py
index fa5e7e7..22dcb6d 100644
--- a/ttun_server/endpoints.py
+++ b/ttun_server/endpoints.py
@@ -2,7 +2,7 @@ import logging
2from base64 import b64decode, b64encode 2from base64 import b64decode, b64encode
3from uuid import uuid4 3from uuid import uuid4
4 4
5from starlette.endpoints import HTTPEndpoint 5from starlette.background import BackgroundTask
6from starlette.requests import Request 6from starlette.requests import Request
7from starlette.responses import Response 7from starlette.responses import Response
8 8
@@ -12,62 +12,43 @@ from ttun_server.types import HttpRequestData, HttpMessageType, HttpMessage
12logger = logging.getLogger(__name__) 12logger = logging.getLogger(__name__)
13 13
14 14
15class HeaderMapping: 15async def proxy(request: Request) -> Response:
16 def __init__(self, headers: list[tuple[str, str]]): 16 [subdomain, *_] = request.headers['host'].split('.')
17 self._headers = headers 17 identifier = str(uuid4())
18 18 response_queue = await ProxyQueue.create_for_identifier(identifier)
19 def items(self): 19
20 for header in self._headers: 20 try:
21 yield header 21 request_queue = await ProxyQueue.get_for_identifier(subdomain)
22 22
23 23 logger.debug('PROXY %s%s ', subdomain, request.url)
24class Proxy(HTTPEndpoint): 24 await request_queue.enqueue(
25 async def dispatch(self) -> None: 25 HttpMessage(
26 request = Request(self.scope, self.receive) 26 type=HttpMessageType.request.value,
27 27 identifier=identifier,
28 [subdomain, *_] = request.headers['host'].split('.') 28 payload=HttpRequestData(
29 response = Response(content='Not Found', status_code=404) 29 method=request.method,
30 30 path=str(request.url).replace(str(request.base_url), '/'),
31 identifier = str(uuid4()) 31 headers=list(request.headers.items()),
32 response_queue = await ProxyQueue.create_for_identifier(identifier) 32 body=b64encode(await request.body()).decode()
33
34 try:
35
36 request_queue = await ProxyQueue.get_for_identifier(subdomain)
37
38 logger.debug('PROXY %s%s ', subdomain, request.url)
39 await request_queue.enqueue(
40 HttpMessage(
41 type=HttpMessageType.request.value,
42 identifier=identifier,
43 payload=
44 HttpRequestData(
45 method=request.method,
46 path=str(request.url).replace(str(request.base_url), '/'),
47 headers=list(request.headers.items()),
48 body=b64encode(await request.body()).decode()
49 )
50 ) 33 )
51 ) 34 )
52 35 )
53 _response = await response_queue.dequeue() 36
54 payload = _response['payload'] 37 _response = await response_queue.dequeue()
55 response = Response( 38 payload = _response['payload']
56 status_code=payload['status'], 39 return Response(
57 headers=HeaderMapping(payload['headers']), 40 status_code=payload['status'],
58 content=b64decode(payload['body'].encode()) 41 headers=dict(payload['headers']),
59 ) 42 content=b64decode(payload['body'].encode()),
60 except AssertionError: 43 background=BackgroundTask(response_queue.delete)
61 pass 44 )
62 finally: 45 except AssertionError:
63 await response(self.scope, self.receive, self.send) 46 return Response(
64 await response_queue.delete() 47 content='Not Found',
65 48 status_code=404,
66 49 background=BackgroundTask(response_queue.delete)
67class Health(HTTPEndpoint): 50 )
68 async def get(self, _) -> None: 51
69 response = Response(content='OK', status_code=200) 52
70 53async def health(_: Request) -> Response:
71 await response(self.scope, self.receive, self.send) 54 return Response(content='OK', status_code=200)
72
73