From 55733579e05781e41298d943af6e09d0cc6a0d80 Mon Sep 17 00:00:00 2001 From: patx Date: Thu, 30 Jan 2025 00:55:15 -0500 Subject: [PATCH] cleaned up examples folders, remove pycache etc --- examples/socketio/webtrc/MicroPie.py | 372 ------------------ .../__pycache__/MicroPie.cpython-310.pyc | Bin 9677 -> 0 bytes .../webtrc/__pycache__/app.cpython-310.pyc | Bin 3826 -> 0 bytes examples/socketio/webtrc/templates/index.html | 17 - .../socketio/webtrc/templates/stream.html~ | 118 ------ examples/socketio/webtrc/templates/watch.html | 2 +- 6 files changed, 1 insertion(+), 508 deletions(-) delete mode 100644 examples/socketio/webtrc/MicroPie.py delete mode 100644 examples/socketio/webtrc/__pycache__/MicroPie.cpython-310.pyc delete mode 100644 examples/socketio/webtrc/__pycache__/app.cpython-310.pyc delete mode 100644 examples/socketio/webtrc/templates/index.html delete mode 100644 examples/socketio/webtrc/templates/stream.html~ diff --git a/examples/socketio/webtrc/MicroPie.py b/examples/socketio/webtrc/MicroPie.py deleted file mode 100644 index 867cf7c..0000000 --- a/examples/socketio/webtrc/MicroPie.py +++ /dev/null @@ -1,372 +0,0 @@ -""" -MicroPie: A simple Python ultra-micro web framework with ASGI -support. https://patx.github.io/micropie - -Copyright Harrison Erd - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -""" -import inspect -import mimetypes -import os -import time -from typing import Optional, Dict, Any, Union, Tuple, List -from urllib.parse import parse_qs -import uuid - -try: - from jinja2 import Environment, FileSystemLoader - JINJA_INSTALLED = True - import asyncio -except ImportError: - JINJA_INSTALLED = False - - -class Server: - SESSION_TIMEOUT: int = 8 * 3600 # 8 hours - - def __init__(self) -> None: - if JINJA_INSTALLED: - self.env = Environment(loader=FileSystemLoader("templates")) - - self.sessions: Dict[str, Dict[str, Any]] = {} - self.query_params: Dict[str, List[str]] = {} - self.body_params: Dict[str, List[str]] = {} - self.path_params: List[str] = [] - self.session: Dict[str, Any] = {} - self.files: Dict[str, Any] = {} - - async def __call__(self, scope, receive, send): - await self.asgi_app(scope, receive, send) - - async def asgi_app(self, scope: Dict[str, Any], receive: Any, send: Any) -> None: - """ASGI application entrypoint for both HTTP and WebSockets.""" - - if scope["type"] == "http": - self.scope = scope - method = scope["method"] - path = scope["path"].lstrip("/") - path_parts = path.split("/") if path else [] - func_name = path_parts[0] if path_parts else "index" - self.path_params = path_parts[1:] if len(path_parts) > 1 else [] - - handler_function = getattr(self, func_name, None) - if not handler_function: - self.path_params = path_parts - handler_function = getattr(self, "index", None) - - raw_query = scope.get("query_string", b"") - self.query_params = parse_qs(raw_query.decode("utf-8", "ignore")) - - headers_dict = { - k.decode("latin-1").lower(): v.decode("latin-1") - for k, v in scope.get("headers", []) - } - cookies = self._parse_cookies(headers_dict.get("cookie", "")) - - session_id = cookies.get("session_id") - if session_id and session_id in self.sessions: - self.session = self.sessions[session_id] - self.session["last_access"] = time.time() - else: - self.session = {} - - self.body_params = {} - self.files = {} - if method in ("POST", "PUT", "PATCH"): - body_data = bytearray() - while True: - msg = await receive() - if msg["type"] == "http.request": - body_data += msg.get("body", b"") - if not msg.get("more_body"): - break - content_type = headers_dict.get("content-type", "") - if "multipart/form-data" in content_type: - self.parse_multipart(bytes(body_data), content_type) - else: - body_str = body_data.decode("utf-8", "ignore") - self.body_params = parse_qs(body_str) - - sig = inspect.signature(handler_function) - func_args = [] - for param in sig.parameters.values(): - if self.path_params: - func_args.append(self.path_params.pop(0)) - elif param.name in self.query_params: - func_args.append(self.query_params[param.name][0]) - elif param.name in self.body_params: - func_args.append(self.body_params[param.name][0]) - elif param.name in self.files: - func_args.append(self.files[param.name]) - elif param.name in self.session: - func_args.append(self.session[param.name]) - elif param.default is not param.empty: - func_args.append(param.default) - else: - await self._send_response( - send, - status_code=400, - body=f"400 Bad Request: Missing required parameter '{param.name}'", - ) - return - - if handler_function == getattr(self, "index", None) and not func_args and path: - await self._send_response(send, status_code=404, body="404 Not Found") - return - - try: - if inspect.iscoroutinefunction(handler_function): - result = await handler_function(*func_args) - else: - result = handler_function(*func_args) - except Exception as e: - print(f"Error processing request: {e}") - await self._send_response( - send, status_code=500, body="500 Internal Server Error" - ) - return - - status_code = 200 - response_body = result - extra_headers: List[Tuple[str, str]] = [] - - if isinstance(result, tuple): - if len(result) == 2: - status_code, response_body = result - elif len(result) == 3: - status_code, response_body, extra_headers = result - else: - await self._send_response( - send, status_code=500, - body="500 Internal Server Error: Invalid response tuple" - ) - return - - if self.session: - session_id = cookies.get("session_id", str(uuid.uuid4())) - self.sessions[session_id] = self.session # Store session only if used - extra_headers.append(("Set-Cookie", f"session_id={session_id}; Path=/; HttpOnly; SameSite=Strict")) - - await self._send_response( - send, - status_code=status_code, - body=response_body, - extra_headers=extra_headers - ) - else: - pass - - def _parse_cookies(self, cookie_header: str) -> Dict[str, str]: - cookies: Dict[str, str] = {} - if not cookie_header: - return cookies - for cookie in cookie_header.split(";"): - if "=" in cookie: - k, v = cookie.strip().split("=", 1) - cookies[k] = v - return cookies - - def parse_multipart(self, body: bytes, content_type: str) -> None: - boundary = None - parts = content_type.split(";") - for part in parts: - part = part.strip() - if part.startswith("boundary="): - boundary = part.split("=", 1)[1] - break - - if not boundary: - raise ValueError("Boundary not found in Content-Type header.") - - boundary_bytes = boundary.encode("utf-8") - delimiter = b"--" + boundary_bytes - sections = body.split(delimiter) - for section in sections: - if not section or section in (b"--", b"--\r\n"): - continue - if section.startswith(b"\r\n"): - section = section[2:] - if section.endswith(b"\r\n"): - section = section[:-2] - if section == b"--": - continue - - try: - headers, content = section.split(b"\r\n\r\n", 1) - except ValueError: - continue - - headers_list = headers.decode("utf-8", "ignore").split("\r\n") - header_dict = {} - for header_line in headers_list: - if ":" in header_line: - key, value = header_line.split(":", 1) - header_dict[key.strip().lower()] = value.strip() - - disposition = header_dict.get("content-disposition", "") - disposition_parts = disposition.split(";") - disposition_dict = {} - for disp_part in disposition_parts: - if "=" in disp_part: - k, v = disp_part.strip().split("=", 1) - disposition_dict[k] = v.strip('"') - - name = disposition_dict.get("name") - filename = disposition_dict.get("filename") - - if filename: - file_content_type = header_dict.get("content-type", "application/octet-stream") - self.files[name] = { - "filename": filename, - "content_type": file_content_type, - "data": content - } - elif name: - value = content.decode("utf-8", "ignore") - if name in self.body_params: - self.body_params[name].append(value) - else: - self.body_params[name] = [value] - - async def _send_response( - self, - send, - status_code: int, - body, - extra_headers=None - ): - if extra_headers is None: - extra_headers = [] - - # Common HTTP status text - status_map = { - 200: "200 OK", - 206: "206 Partial Content", - 302: "302 Found", - 403: "403 Forbidden", - 404: "404 Not Found", - 500: "500 Internal Server Error", - } - # Fallback if not in map - status_text = status_map.get(status_code, f"{status_code} OK") - - # Ensure there's a Content-Type unless already provided - has_content_type = any(h[0].lower() == "content-type" for h in extra_headers) - if not has_content_type: - extra_headers.append(("Content-Type", "text/html; charset=utf-8")) - - # Send the initial response start - await send({ - "type": "http.response.start", - "status": status_code, - "headers": [ - (k.encode("latin-1"), v.encode("latin-1")) for k, v in extra_headers - ], - }) - - # 1) Check if body is an async generator (has __aiter__) - if hasattr(body, "__aiter__"): - async for chunk in body: - if isinstance(chunk, str): - chunk = chunk.encode("utf-8") - await send({ - "type": "http.response.body", - "body": chunk, - "more_body": True - }) - # Send a final empty chunk to mark the end - await send({ - "type": "http.response.body", - "body": b"", - "more_body": False - }) - return - - # 2) Check if body is a *sync* generator (has __iter__) and - # is not a plain string/bytes - if hasattr(body, "__iter__") and not isinstance(body, (bytes, str)): - for chunk in body: - if isinstance(chunk, str): - chunk = chunk.encode("utf-8") - await send({ - "type": "http.response.body", - "body": chunk, - "more_body": True - }) - # Send a final empty chunk - await send({ - "type": "http.response.body", - "body": b"", - "more_body": False - }) - return - - if isinstance(body, str): - response_body = body.encode("utf-8") - elif isinstance(body, bytes): - response_body = body - else: - # Convert anything else to string then to bytes - response_body = str(body).encode("utf-8") - - await send({ - "type": "http.response.body", - "body": response_body, - "more_body": False - }) - - def cleanup_sessions(self) -> None: - now = time.time() - self.sessions = { - sid: data - for sid, data in self.sessions.items() - if data.get("last_access", now) + self.SESSION_TIMEOUT > now - } - - def redirect(self, location: str) -> Tuple[int, str]: - return ( - 302, - ( - "" - f"" - "" - ), - ) - - async def render_template(self, name: str, **kwargs: Any) -> str: - """ - Async-compatible template rendering using Jinja2. - """ - if not JINJA_INSTALLED: - raise ImportError("Jinja2 is not installed.") - - def render_sync(): - return self.env.get_template(name).render(kwargs) - - return await asyncio.get_event_loop().run_in_executor(None, render_sync) - diff --git a/examples/socketio/webtrc/__pycache__/MicroPie.cpython-310.pyc b/examples/socketio/webtrc/__pycache__/MicroPie.cpython-310.pyc deleted file mode 100644 index 8083fa3057d0c790fcb42546218f0e4f9622603d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9677 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 diff --git a/examples/socketio/webtrc/__pycache__/app.cpython-310.pyc b/examples/socketio/webtrc/__pycache__/app.cpython-310.pyc deleted file mode 100644 index d0554d671649e619761e7116774a5b9ddd35320f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3826 zcmbVP&u`nv73K^nilQW2ahznEZVR^C!mDi7D!M)NN0M&3O?J~Z#sc1L0U3eHaKk%la!d7Jm*JAL2>>ghE+L46Q!BcMxmrH8`*rQ?daACxXVz2EZ*Z%jd~W&LIclor3!z%7$&waJ+K?=%HcQ$p zS%##e&aq^PB`c7eSF0>pX2}IeE~-l`>F7FaIj60o747JAFJ%9`5}Q`{t-oO()<#$4 z?xr?-+T>1{K8Vrw!}MSr4MvI55$P=cY&1T^lYS3{w)#R@eW`?!&#XRnubpkF994Vf z^lN3yRduvnvy;)16cgw+&6g#miszc9N0q?S#g}X)@ME^?q)W$^GPU?^BcP z>L^Qlqd0;n);;|=98HEg?WIZdP-k({+t>Fq6ZOK$WPNgw*W$6#k6UCW1%v$3k<%vc zXPtX;ud*Mx`Uf;<^ z!((A6G`n`*3ZpFE(*s&3&FxUBeA#GNWd@ms?O~>mrKv-iN1Qmqc#!38F)5aD@xcaOqh(PJ8zA-7?-p)Hwnrq^)btGuqqd$CEzXT4A_2YrKxf|;o^BdFF)_f25g6R?ug*uO1dnwksZf-x&nIR&Z zHVT3%$$j7m9+8@P3(~I5uFD-2X5pLYWWEWl@8U@*(7`3!5x!Uvmxc2xZ;ti;ptSy! zCkg1eCx4B`DNmA5;l(fPOu%P$<+DSFJT{Y=+_OwKvv-kVm7LkJn4whea|gbzldn}B zUd7Y(rhoAR{BBl04C3*2Vn%6@?dSmc0~tSvGxUx#$dW>B(VaZ}H#)d)l2AoqngweM zn_8nWG!@(y8(p|pKaTVyV{y6nt2|3usLqj1wPrhvUL#O3ZLk;XeOQD^BV_wb2jMtK zwznaI)$2S9gOC@AMw`u8O_#P7ECSemaQ#NP5%V4R78G;{(A-NO#*+cqxY4bd06h$G z5dy@3+|i>r>pBHn-XR4_xp}kP1`Rz!B3@t}N-2>N@Yj8@Dm>vzS4jLjubhA7HQvIh z03h%wLo=1OQF(I!FuiPqg2OcjwHkt=#zb;CH0ngBLzhA$lXUl(IWzPt?+*wa)p%|r zD0~hI9|6&vChWz}2!1|M;oB642M}0rHQ-1mI*PaBsEQnTx&Q#d05JALqbPC|V2`rl zK@kWcg%VC=24(>-LkuxjP~;7E#%Bi;J-xWa^?Si>13u5qnYQMU2;-*ps~lF>K}DLt zyhpQ?CnK+eTr0C=D+Z~W29fie;(B}&GZsn7U= z>OdH`N#HA0o$>V;U%p#Se>=ywM52WEei%I@j0@u`-d0YZqkFrAHroM~CAll5640yI zi}`?d>KBuhU>1!M&1&&!n`WtI2mm6DG(Vt%gW`SEHcSsCNXf?(5if65Lx^FklG@d+CQil${&{0QPu`d>ifg5s z+yzu^djBdO>pOH$o_4lQc^B!~q4aEi1ZN`C{sb>`jf(3i@&=_MCbe0JivG zVj7&+vEE>Wg_pT9#L5G{h@U0%Y8e}_XD~NA#uRCQq6!hDZ|P9-<}d-V|0&(hKb(J? zpFyd+iZi7AEXcjP^vUpPtPS1m^X5(ZUMfDK44)=;THP;*{drCA;gsa7U2)5jxDC?n zfzJ?59fsnOSIRy53>)B^Bd_1w{P+$&mvGacOcpjpv02=ty=%qQ_=bQer6lQDEzz=F byJI^mzHn?`c=UL9I(RPNIqwViQb+s;-nX*P diff --git a/examples/socketio/webtrc/templates/index.html b/examples/socketio/webtrc/templates/index.html deleted file mode 100644 index b710858..0000000 --- a/examples/socketio/webtrc/templates/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - Webcam Streaming - - -

Webcam Streaming App

-
- - - -
- - - diff --git a/examples/socketio/webtrc/templates/stream.html~ b/examples/socketio/webtrc/templates/stream.html~ deleted file mode 100644 index 7224a90..0000000 --- a/examples/socketio/webtrc/templates/stream.html~ +++ /dev/null @@ -1,118 +0,0 @@ - - - - WebRTC Streaming (Streamer) - - - - - -

Streaming as {{ username }}

- - - - - - diff --git a/examples/socketio/webtrc/templates/watch.html b/examples/socketio/webtrc/templates/watch.html index 56a2378..1dfca07 100644 --- a/examples/socketio/webtrc/templates/watch.html +++ b/examples/socketio/webtrc/templates/watch.html @@ -16,7 +16,7 @@

Watching: {{ username }}

autoplay controls muted - style="width: 640px; background: black;"> + style="transform: scaleX(-1);">