|
| 1 | +--- |
| 2 | +title: P2P Web Hosting |
| 3 | +date: 25/04/2025 |
| 4 | +--- |
| 5 | + |
| 6 | +# basic local example |
| 7 | + |
| 8 | +### Client A |
| 9 | +#### Host a http web server via unix sockets. |
| 10 | +> server.py |
| 11 | +```python |
| 12 | +import http.server |
| 13 | +import json |
| 14 | +import os |
| 15 | +import socket |
| 16 | +import sys |
| 17 | +import traceback |
| 18 | + |
| 19 | +def process_cmd(cmd, *args): |
| 20 | + print(f"In process_cmd({cmd}, {args})...") |
| 21 | + |
| 22 | +class HTTPHandler(http.server.BaseHTTPRequestHandler): |
| 23 | + def do_POST(self): |
| 24 | + size = int(self.headers.get('Content-Length', 0)) |
| 25 | + body = self.rfile.read(size) |
| 26 | + args = json.loads(body) if body else [] |
| 27 | + try: |
| 28 | + result = process_cmd(self.path[1:], *args) |
| 29 | + self.send(200, result or 'Success') |
| 30 | + except Exception: |
| 31 | + self.send(500, str(traceback.format_exc())) |
| 32 | + |
| 33 | + def do_GET(self): |
| 34 | + self.do_POST() |
| 35 | + |
| 36 | + def send(self, code, reply): |
| 37 | + # avoid exception in server.py address_string() |
| 38 | + self.client_address = ('',) |
| 39 | + self.send_response(code) |
| 40 | + self.end_headers() |
| 41 | + self.wfile.write(reply.encode('utf-8')) |
| 42 | + |
| 43 | +sock_file = sys.argv[1] |
| 44 | +try: |
| 45 | + os.remove(sock_file) |
| 46 | +except OSError: |
| 47 | + pass |
| 48 | +sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
| 49 | +sock.bind(sock_file) |
| 50 | +sock.listen(0) |
| 51 | + |
| 52 | +server = http.server.HTTPServer(sock_file, HTTPHandler, |
| 53 | + False) |
| 54 | +server.socket = sock |
| 55 | +server.serve_forever() |
| 56 | + |
| 57 | +sock.shutdown(socket.SHUT_RDWR) |
| 58 | +sock.close() |
| 59 | +os.remove(sock_file) |
| 60 | +``` |
| 61 | +and run this with: |
| 62 | + |
| 63 | +`python3 server.py /tmp/http.socket` |
| 64 | + |
| 65 | +## Client B |
| 66 | +### Turn the web socket path into a tcp connection that the browser can understand |
| 67 | +```bash |
| 68 | +socat TCP-LISTEN:80,forever,reuseaddr,fork UNIX-CONNECT:/tmp/http.socket |
| 69 | +``` |
| 70 | + |
| 71 | +### Use browser to see web page: |
| 72 | +> `http://localhost` |
| 73 | +
|
| 74 | + |
| 75 | +# same example using P2P |
| 76 | + |
| 77 | +### Client A |
| 78 | +```bash |
| 79 | +python3 server.py /tmp/http.socket |
| 80 | +# From another terminal, pipe the server socket into dumbpipe |
| 81 | +socat UNIX-CONNECT:/tmp/http.socket,keepalive,ignoreeof EXEC:"dumbpipe listen",reuseaddr |
| 82 | +# Note down nodeId from the console. |
| 83 | +``` |
| 84 | + |
| 85 | +### Client B |
| 86 | +```bash |
| 87 | +export nodeId=">>The id from client A Console.<<" |
| 88 | +# Connect to dumbpipe and expose the socket via tcp. |
| 89 | +export CMD="dumbpipe connect $nodeId" |
| 90 | +socat EXEC:"$CMD" TCP-LISTEN:80,forever,reuseaddr,fork |
| 91 | +# Test from another terminal |
| 92 | +curl http://localhost |
| 93 | +``` |
| 94 | + |
| 95 | +> *So far this only accepts 1 http e2e and you have to kill `socat` on client B for `curl` to respond. This is due to unix-listen just stuck with the first request and it won't fork additional requests.* |
| 96 | +
|
0 commit comments