patx/micropie
added WSGI support with wrapper method wsgi_app()
Commit 0b1222e ยท patx ยท 2025-01-19T17:49:52-05:00
Comments
No comments yet.
Diff
diff --git a/MicroPie.py b/MicroPie.py
index 70b1462..b577390 100644
--- a/MicroPie.py
+++ b/MicroPie.py
@@ -1,10 +1,11 @@
"""
-MicroPie: A simple and lightweight Python micro web framework.
+MicroPie: A simple and lightweight Python micro web framework w/ WSGI support
https://patx.github.io/micropie
"""
import http.server
import socketserver
+from urllib.parse import parse_qs
import time
import uuid
import inspect
@@ -281,3 +282,86 @@ class Server:
print(f"Error during request validation: {e}")
return False
+ def wsgi_app(self, environ, start_response):
+ """
+ WSGI-compatible application wrapper for running MicroPie apps with Gunicorn or other WSGI servers.
+
+ :param environ: WSGI environment dictionary.
+ :param start_response: WSGI start_response function.
+ """
+ path = environ['PATH_INFO'].strip("/")
+ method = environ['REQUEST_METHOD']
+
+ # Default to index if root is accessed
+ if not path:
+ path = "index"
+
+ # Parse query parameters
+ self.query_params = parse_qs(environ['QUERY_STRING'])
+
+ # Split the path to extract potential parameters
+ path_parts = path.split('/')
+
+ # Determine the function name from path, default to index
+ func_name = path_parts[0] if path_parts[0] else "index"
+
+ # Assign request properties to app
+ self.request = method
+ self.path_params = path_parts[1:] # Exclude the function name
+
+ # Handle POST request body
+ if method == "POST":
+ try:
+ content_length = int(environ.get('CONTENT_LENGTH', 0))
+ body = environ['wsgi.input'].read(content_length) if content_length > 0 else b""
+ post_params = parse_qs(body.decode('utf-8'))
+ self.body_params = {k: v[0] for k, v in post_params.items()}
+ except Exception as e:
+ start_response('400 Bad Request', [('Content-Type', 'text/html')])
+ return [f"400 Bad Request: {str(e)}".encode('utf-8')]
+ else:
+ self.body_params = {}
+
+ try:
+ # Find the function to call or return 404 if not found
+ handler_function = getattr(self, func_name, None)
+ if handler_function:
+ # Get function signature to determine required arguments
+ 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])
+ elif param.default is not param.empty:
+ func_args.append(param.default)
+ else:
+ start_response('400 Bad Request', [('Content-Type', 'text/html')])
+ return [f"400 Bad Request: Missing required parameter '{param.name}'".encode('utf-8')]
+
+ # Call the handler with the parameters
+ response = handler_function(*func_args)
+
+ # Handle tuple (status, body) response
+ if isinstance(response, tuple) and len(response) == 2:
+ status, body = response
+ status = f"{status} Found" if status == 302 else f"{status} OK"
+ else:
+ status, body = '200 OK', response
+
+ start_response(status, [('Content-Type', 'text/html')])
+ return [body.encode('utf-8')]
+ else:
+ start_response('404 Not Found', [('Content-Type', 'text/html')])
+ return [b'404 Not Found']
+
+ except Exception as e:
+ if not environ.get('gunicorn.error_handled'):
+ start_response('500 Internal Server Error', [('Content-Type', 'text/html')])
+ environ['gunicorn.error_handled'] = True
+ return [f"500 Internal Server Error: {str(e)}".encode('utf-8')]
+
diff --git a/README.md b/README.md
index 991f0bf..5ac81ed 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
- ๐ **Routing:** Maps URLs to functions automatically.
- ๐ **Sessions:** Simple session management using cookies.
- ๐จ **Templates:** Jinja2 for dynamic HTML pages.
-- โก **Fast & Lightweight:** No unnecessary dependencies.
+- โก **Fast & Lightweight:** No unnecessary dependencies. WSGI support.
## **Installation**
@@ -138,7 +138,7 @@ class MyApp(Server):
return f"Registered {username} with email {email}"
```
-### 4. Session Cleanup
+### 4. **Session Cleanup**
Sessions expire after 8 hours but can be manually cleaned:
```python
@@ -147,6 +147,34 @@ class MyApp(Server):
super().cleanup_sessions()
```
+### 5. **WSGI Support**
+MicroPie includes built-in WSGI support via the wsgi_app() method, allowing you to deploy your applications with WSGI-compatible servers like Gunicorn.
+
+#### **Example**
+Create a file named app.py:
+```python
+from MicroPie import Server
+
+class MyApp(Server):
+ def index(self):
+ return "Hello, WSGI World!"
+
+app = MyApp()
+wsgi_application = app.wsgi_app
+```
+
+Run `app.py` with:
+```bash
+gunicorn app:wsgi_application
+```
+
+#### Why Use WSGI?
+WSGI (Web Server Gateway Interface) is the standard Python interface between web servers and web applications. Deploying with a WSGI server like Gunicorn provides benefits such as:
+- Better Performance: Multi-threaded and multi-process capabilities.
+- Scalability: Easily handle multiple requests concurrently.
+- Production Readiness: Designed for high-load environments.
+
+
## **API Reference**
### Class: Server
@@ -169,6 +197,11 @@ Renders a Jinja2 template with provided context variables.
#### validate_request(method)
Validates incoming requests for both GET and POST methods based on query and body parameters.
+#### wsgi_app(environ, start_response)
+- Parses incoming HTTP requests and routes them to appropriate handler methods.
+- Handles both GET and POST requests.
+- Provides response headers and status codes.
+
## **Examples**
[See the examples folder!](https://github.com/patx/micropie/tree/main/examples)
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index 606b44a..0000000
--- a/examples/README.md
+++ /dev/null
@@ -1,187 +0,0 @@
-# MicroPie User Guides
-
-Welcome to the comprehensive set of guides and examples designed to help you master the MicroPie framework. These guides and examples cover everything from getting started to advanced topics like deployment and security.
-
-## **1. Beginner's Guide to MicroPie Framework**
-
-### Introduction to MicroPie
-MicroPie is a lightweight Python web framework designed for rapid development with minimal configuration. It provides essential features such as routing, templating, and session management.
-
-### Creating Your First Application
-1. Install MicroPie:
- ```bash
- pip install micropie
- ```
-2. Create a `server.py` file with:
- ```python
- from MicroPie import Server
-
- class MyApp(Server):
- def index(self):
- return "Hello, MicroPie!"
-
- MyApp().run()
- ```
-3. Run the server:
- ```bash
- python server.py
- ```
-4. Visit `http://127.0.0.1:8080` to see your app in action.
-
-### Understanding Routing
-MicroPie automatically maps URL paths to class methods, making routing simple and intuitive.
-
-
-## **2. MicroPie Templating with Jinja2**
-
-### Creating Templates
-MicroPie integrates with Jinja2 for dynamic HTML rendering. Store your templates in a `templates/` folder.
-
-Example template (`index.html`):
-```html
-<!DOCTYPE html>
-<html>
-<body>
- <h1>Hello, {{ name }}!</h1>
-</body>
-</html>
-```
-
-### Rendering Templates
-In your MicroPie application:
-```python
-return self.render_template("index.html", name="MicroPie User")
-```
-
-
-## **3. Session Management in MicroPie**
-
-### How Sessions Work
-MicroPie uses cookies to store session IDs, allowing persistent data across requests.
-
-### Managing Session Data
-```python
-self.session['username'] = 'JohnDoe'
-print(self.session.get('username'))
-```
-
-### Securing Sessions
-- Use HTTPS for secure cookie transmission.
-- Configure session timeout to prevent long-term exposure.
-
-
-## **4. Advanced Database Handling with PickleDB**
-
-### Storing Data
-```python
-from pickledb import PickleDB
-
-db = PickleDB("data.db")
-db.set("key", "value")
-db.save()
-```
-
-### Querying Data
-```python
-value = db.get("key")
-```
-
-### Backup Strategies
-- Regular backups of `data.db`.
-- Automated scripts for periodic exports.
-
-
-## **5. Security Best Practices for MicroPie Applications**
-
-### Input Validation
-Always validate user inputs to prevent injection attacks.
-
-### Authentication
-Implement secure authentication mechanisms using sessions and encryption.
-
-### Secure Deployment
-- Use HTTPS.
-- Set secure headers.
-- Perform regular security audits.
-
-
-## **6. Extending MicroPie with REST APIs**
-
-### Creating an API Endpoint
-```python
-class MyApp(Server):
- def api_greet(self, name):
- return {"message": f"Hello, {name}!"}
-```
-
-### Testing with cURL
-```bash
-curl http://127.0.0.1:8080/api_greet?name=Alice
-```
-
-
-## **7. Deploying MicroPie Applications on Cloud Platforms**
-
-### AWS Deployment
-- Use AWS Elastic Beanstalk for easy deployments.
-
-### Google Cloud Run
-Deploy using:
-```bash
-gcloud run deploy --source .
-```
-
-
-## **8. Logging and Monitoring MicroPie Applications**
-
-### Setting Up Logging
-```python
-import logging
-logging.basicConfig(level=logging.INFO)
-logging.info("Server started")
-```
-
-### Using Monitoring Tools
-Integrate with tools like Prometheus and Grafana.
-
-
-## **9. Styling MicroPie Applications with CSS Frameworks**
-
-### Integrating Bootstrap
-Add the Bootstrap CDN link to your templates:
-```html
-<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
-```
-
-### Customizing Styles
-Create a `static/` folder and include your CSS files.
-
-
-## **10. Automated Testing for MicroPie Applications**
-
-### Writing Unit Tests
-```python
-import unittest
-from MicroPie import Server
-
-class TestApp(unittest.TestCase):
- def test_index(self):
- app = MyApp()
- response = app.index()
- self.assertEqual(response, "Hello, MicroPie!")
-
-if __name__ == "__main__":
- unittest.main()
-```
-
-### Using pytest
-```bash
-pytest test_app.py
-```
-
-# Main Examples
-Check out the other directors `gunicorn`, `todo-app`, `pastebin-app`, and `websockets` for even more examples.
-
-These guides aim to provide a thorough understanding of the MicroPie framework and its capabilities. Whether you're a beginner or an experienced developer, you'll find valuable insights and practical examples to enhance your web development skills.
-
-
diff --git a/examples/pastebin-app/README.md b/examples/pastebin-app/README.md
deleted file mode 100644
index 296f7c9..0000000
--- a/examples/pastebin-app/README.md
+++ /dev/null
@@ -1,157 +0,0 @@
-# Guide: Building a Simple Pastebin with MicroPie, PickleDB, and Pygments
-
-This guide provides instructions on how to set up and run a simple pastebin web application using the MicroPie framework, PickleDB for storage, and Pygments for syntax highlighting.
-
-
-## **1. Overview**
-
-This application allows users to:
-
-- Submit code snippets to be stored.
-- Retrieve and view formatted code with syntax highlighting.
-
-### **Technologies Used:**
-- **MicroPie** โ A lightweight web framework.
-- **PickleDB** โ A lightweight key-value store for storing pastes.
-- **Pygments** โ A syntax highlighter for rendering code.
-
-
-## **2. Prerequisites**
-
-Ensure you have Python installed along with the required dependencies:
-
-```bash
-pip install micropie pickledb pygments
-```
-
-
-## **3. Application Code Explanation**
-
-### **`pastebin.py` (Main Application)**
-
-```python
-"""
- A simple no frills pastebin using MicroPie, PickleDB, and Pygments.
-"""
-
-import os
-from uuid import uuid4
-
-from MicroPie import Server
-from pickledb import PickleDB
-from pygments import highlight
-from pygments.lexers import guess_lexer
-from pygments.formatters import HtmlFormatter
-
-
-db = PickleDB("pastes.db")
-
-def get_paste(pid, line_numbers=None):
- code = db.get(pid)
- return highlight(code, guess_lexer(code), HtmlFormatter())
-
-class Root(Server):
-
- def index(self):
- return self.render_template("index.html")
-
- def paste(self, paste_id):
- return self.render_template("paste.html", paste_id=paste_id,
- paste_content=get_paste(paste_id))
-
- def add(self, paste_content):
- pid = str(uuid4())
- db.set(pid, paste_content)
- db.save()
- return self.redirect("/paste/{0}".format(pid))
-
-Root().run()
-```
-
-### **Explanation:**
-
-1. **Database Handling (`PickleDB`)**
- - Stores pastes using a simple key-value format.
- - `db.set(pid, paste_content)` saves new code snippets.
- - `db.get(pid)` retrieves stored snippets.
-
-2. **Syntax Highlighting (`Pygments`)**
- - `highlight()` applies syntax highlighting to the pasted code.
- - `guess_lexer()` detects the programming language automatically.
- - `HtmlFormatter()` generates HTML-formatted output.
-
-3. **Web Application (`MicroPie`)**
- - **Routes:**
- - `/` โ Displays the home page.
- - `/paste/<paste_id>` โ Shows highlighted paste content.
- - `/add` โ Accepts new pastes and stores them.
-
-
-## **4. Running the Application**
-
-Start the pastebin server with:
-
-```bash
-python pastebin.py
-```
-
-Once running, access the application at:
-
-```
-http://127.0.0.1:8080
-```
-
-
-## **5. Testing the Application**
-
-1. Open the home page and submit a new code snippet.
-2. Copy the URL of the resulting paste and view the formatted output.
-
-
-## **6. Deployment with Gunicorn**
-
-For better performance in production environments, run the application using Gunicorn:
-
-```bash
-gunicorn -w 4 -b 0.0.0.0:8080 pastebin:Root
-```
-
-
-## **7. Deploying with Docker**
-
-Create a `Dockerfile` to containerize the application:
-
-```dockerfile
-FROM python:3.9-slim
-WORKDIR /app
-COPY pastebin.py requirements.txt .
-RUN pip install -r requirements.txt
-EXPOSE 8080
-CMD ["python", "pastebin.py"]
-```
-
-Build and run the container:
-
-```bash
-docker build -t micropie-pastebin .
-docker run -p 8080:8080 micropie-pastebin
-```
-
-
-## **8. Improving the Application**
-
-To enhance the functionality, consider:
-
-- Adding **expiration policies** for pastes.
-- Implementing **user authentication**.
-- Using a more robust database such as SQLite or PostgreSQL.
-- Adding a REST API for programmatic access.
-
-
-## **9. Conclusion**
-
-This guide covered the setup and deployment of a simple pastebin web application using MicroPie, PickleDB, and Pygments. This setup is ideal for quick, lightweight code sharing with syntax highlighting.
-
-For further questions or improvements, feel free to contribute to the project or explore additional features.
-
-
diff --git a/examples/pastebin-app/pastebin-wsgi.py b/examples/pastebin-app/pastebin-wsgi.py
new file mode 100644
index 0000000..026d9d5
--- /dev/null
+++ b/examples/pastebin-app/pastebin-wsgi.py
@@ -0,0 +1,39 @@
+"""
+Example pastebin with added WSGI support. You can run it using gunicorn:
+
+$ gunicorn pastebin-wsgi:wsgi_app
+"""
+from MicroPie import Server
+from pickledb import PickleDB
+from pygments import highlight
+from pygments.lexers import guess_lexer
+from pygments.formatters import HtmlFormatter
+from uuid import uuid4
+
+# Initialize the database
+db = PickleDB("pastes.db")
+
+def get_paste(pid, line_numbers=None):
+ code = db.get(pid)
+ return highlight(code, guess_lexer(code), HtmlFormatter())
+
+class Root(Server):
+
+ def index(self):
+ return self.render_template("index.html")
+
+ def paste(self, paste_id):
+ return self.render_template("paste.html", paste_id=paste_id,
+ paste_content=get_paste(paste_id))
+
+ def add(self, paste_content):
+ pid = str(uuid4())
+ db.set(pid, paste_content)
+ db.save()
+ return self.redirect(f"/paste/{pid}")
+
+# Create the application instance
+app = Root()
+
+# Use the WSGI wrapper provided by MicroPie
+wsgi_app = app.wsgi_app
diff --git a/examples/todo-app/README.md b/examples/todo-app/README.md
deleted file mode 100644
index 39a92dc..0000000
--- a/examples/todo-app/README.md
+++ /dev/null
@@ -1,197 +0,0 @@
-# Guide: ToDo Application with MicroPie and PickleDB
-
-This guide provides instructions on how to set up and run a simple ToDo web application using the **MicroPie** framework and **PickleDB** for data storage.
-
-## **1. Overview**
-
-The ToDo application allows users to:
-
-- Log in and manage a session.
-- Add, delete, and view ToDo items.
-- Filter items by tags.
-
-### **Technologies Used:**
-- **MicroPie** โ A lightweight Python web framework.
-- **PickleDB** โ A simple key-value database for storing tasks.
-- **UUID** โ For generating unique item identifiers.
-
-
-## **2. Prerequisites**
-
-Ensure Python and the required dependencies are installed:
-
-```bash
-pip install micropie pickledb
-```
-
-
-## **3. Application Code Explanation**
-
-### **`todo.py` (Main Application)**
-
-```python
-import os
-from uuid import uuid4
-from MicroPie import Server
-from pickledb import PickleDB
-
-db = PickleDB("todo.db")
-
-def add_item(content, tags):
- item_id = str(uuid4())
- db.set(item_id, {"content": content, "tags": tags.split(), "id": item_id})
- db.save()
-
-def matching_tags(tag):
- return [
- db.get(key) for key in db.all() if tag in db.get(key).get("tags", [])
- ][::-1]
-
-def get_all_items():
- return [db.get(key) for key in db.all()][::-1]
-
-def get_all_tags():
- tags = set()
- for key in db.all():
- tags.update(db.get(key).get("tags", []))
- return list(tags)
-
-def delete_item(item_id):
- db.remove(item_id)
- db.save()
-
-class ToDoApp(Server):
- users = {"username": "password"}
-
- def login(self):
- if self.request == "GET":
- return self.render_template("login.html")
- if self.request == "POST":
- username = self.body_params.get("username", [""])[0]
- password = self.body_params.get("password", [""])[0]
- if self.users.get(username) == password:
- self.session.update({"logged_in": True, "username": username})
- return self.redirect("/")
- return self.render_template("login.html", error="Invalid credentials")
-
- def logout(self):
- self.session.clear()
- return self.redirect("/login")
-
- def index(self):
- if not self.session.get("logged_in"):
- return self.redirect("/login")
- return self.render_template(
- "index.html",
- seq=get_all_items(),
- tags=get_all_tags(),
- username=self.session.get("username"),
- )
-
- def add(self):
- if not self.session.get("logged_in"):
- return self.redirect("/login")
- if self.request == "POST":
- add_item(
- self.body_params.get("content", [""])[0],
- self.body_params.get("tags", [""])[0],
- )
- return self.redirect("/")
-
- def delete(self, item_id):
- if not self.session.get("logged_in"):
- return self.redirect("/login")
- if item_id:
- delete_item(item_id)
- return self.redirect("/")
-
- def tag(self, tag_value):
- if not self.session.get("logged_in"):
- return self.redirect("/login")
- return self.render_template(
- "tag.html",
- tag=tag_value,
- tag_items=matching_tags(tag_value),
- )
-
-if __name__ == "__main__":
- port = int(os.environ.get("PORT", 5000))
- app = ToDoApp()
- app.run(host="0.0.0.0", port=port)
-```
-
-### **Explanation:**
-
-1. **Database Operations (`PickleDB`)**
- - `add_item()` โ Adds a new item to the database.
- - `get_all_items()` โ Retrieves all stored items.
- - `delete_item()` โ Removes an item by its ID.
- - `matching_tags()` โ Finds items based on a given tag.
- - `get_all_tags()` โ Retrieves unique tags from all items.
-
-2. **Authentication System:**
- - Supports a simple username/password login.
- - Sessions are used to keep users logged in.
-
-3. **Web Application (`MicroPie`)**
- - Routes:
- - `/` โ Displays all ToDo items.
- - `/login` โ User login page.
- - `/logout` โ Ends the session.
- - `/add` โ Adds a new ToDo item.
- - `/delete/<item_id>` โ Deletes a specific item.
- - `/tag/<tag>` โ Filters items by a tag.
-
-
-## **4. Running the Application**
-
-Start the application with:
-
-```bash
-python todo.py
-```
-
-Access the app at:
-
-```
-http://127.0.0.1:5000
-```
-
-
-## **5. Deployment with Gunicorn**
-
-Run the application with Gunicorn for production:
-
-```bash
-gunicorn -w 4 -b 0.0.0.0:5000 todo:ToDoApp
-```
-
-
-## **6. Deploying with Docker**
-
-Create a `Dockerfile`:
-
-```dockerfile
-FROM python:3.9-slim
-WORKDIR /app
-COPY todo.py requirements.txt .
-RUN pip install -r requirements.txt
-EXPOSE 5000
-CMD ["python", "todo.py"]
-```
-
-Build and run the container:
-
-```bash
-docker build -t micropie-todo .
-docker run -p 5000:5000 micropie-todo
-```
-
-
-## **7. Conclusion**
-
-This guide covers the setup and deployment of a ToDo application using MicroPie and PickleDB. It provides basic CRUD operations and authentication to manage tasks effectively.
-
-For further improvements, consider integrating a more robust database and authentication system.
-
-
diff --git a/examples/websockets/README.md b/examples/websockets/README.md
deleted file mode 100644
index db186d7..0000000
--- a/examples/websockets/README.md
+++ /dev/null
@@ -1,158 +0,0 @@
-# Guide: Running MicroPie with WebSockets
-
-This guide explains how to run the **MicroPie** framework alongside a WebSocket server using Python's `asyncio` and `websockets` libraries.
-
-
-## **1. Overview**
-
-The provided script runs a MicroPie web application while simultaneously hosting a WebSocket server on a different port. The WebSocket server runs in a separate thread to enable concurrent handling of HTTP and WebSocket traffic.
-
-### **Key Components:**
-- MicroPie web server handling HTTP requests on port `8080`.
-- WebSocket server handling WebSocket connections on port `8765`.
-
-
-## **2. Prerequisites**
-
-Ensure you have Python installed along with the required dependencies:
-
-```bash
-pip install micropie websockets
-```
-
-
-## **3. Code Explanation**
-
-### **`server.py` (Main Script)**
-
-```python
-import threading
-import asyncio
-import websockets
-from MicroPie import Server
-
-class MyApp(Server):
- def index(self):
- return "WebSocket available at ws://localhost:8765"
-
-def start_websocket_server():
- async def echo(websocket, path):
- async for message in websocket:
- await websocket.send(f"Echo: {message}")
-
- asyncio.run(websockets.serve(echo, "localhost", 8765))
- asyncio.get_event_loop().run_forever()
-
-# Run MicroPie in the main thread
-if __name__ == "__main__":
- threading.Thread(target=start_websocket_server, daemon=True).start()
- MyApp().run()
-```
-
-### **Explanation:**
-1. **MicroPie Web Server (`MyApp`)**
- - Handles HTTP requests and serves content on `http://localhost:8080`.
- - Displays a message indicating WebSocket availability.
-
-2. **WebSocket Server (`start_websocket_server`)**
- - Listens on `ws://localhost:8765`.
- - Handles incoming WebSocket messages and echoes them back to the client.
-
-3. **Threading:**
- - The WebSocket server runs in a separate daemon thread, allowing the HTTP server to run concurrently.
-
-
-## **4. Running the Application**
-
-Run the script with:
-
-```bash
-python server.py
-```
-
-- The HTTP server will be available at `http://localhost:8080`.
-- The WebSocket server will be accessible at `ws://localhost:8765`.
-
-
-## **5. Testing the WebSocket Server**
-
-You can test the WebSocket server using a simple Python script or browser console.
-
-### **Python WebSocket Client Test:**
-
-```python
-import asyncio
-import websockets
-
-async def test_websocket():
- uri = "ws://localhost:8765"
- async with websockets.connect(uri) as websocket:
- await websocket.send("Hello, Server!")
- response = await websocket.recv()
- print(f"Received: {response}")
-
-asyncio.run(test_websocket())
-```
-
-### **JavaScript WebSocket Test (Browser Console):**
-
-```javascript
-let socket = new WebSocket("ws://localhost:8765");
-
-socket.onopen = function() {
- console.log("Connected to WebSocket server");
- socket.send("Hello from client!");
-};
-
-socket.onmessage = function(event) {
- console.log("Received from server:", event.data);
-};
-```
-
-
-## **6. Stopping the Application**
-
-To stop the running application, use:
-
-```bash
-CTRL + C
-```
-
-## **7. Deploying the Application**
-
-For production, consider running the application with **Gunicorn** or Docker:
-
-### **Using Gunicorn:**
-
-```bash
-gunicorn -w 4 -b 0.0.0.0:8080 server:MyApp
-```
-
-### **Using Docker:**
-
-Create a `Dockerfile`:
-
-```dockerfile
-FROM python:3.9
-WORKDIR /app
-COPY server.py .
-RUN pip install micropie websockets
-CMD ["python", "server.py"]
-```
-
-Build and run:
-
-```bash
-docker build -t micropie-websocket .
-docker run -p 8080:8080 -p 8765:8765 micropie-websocket
-```
-
-## **8. Conclusion**
-
-This guide covered how to run MicroPie with a WebSocket server simultaneously, allowing HTTP and WebSocket communication within the same application. This setup is useful for applications requiring real-time capabilities such as chat applications, notifications, or live updates.
-
----
-
-For further questions, feel free to reach out or explore additional integrations with databases and authentication services.
-
-