Skip to content

Commit

Permalink
replace main with development branch. MICEOPIE IS NOW ASGI BASED, RUN…
Browse files Browse the repository at this point in the history
… METHOD GONE
  • Loading branch information
patx committed Jan 28, 2025
1 parent ccaa19b commit 2519a30
Show file tree
Hide file tree
Showing 20 changed files with 826 additions and 757 deletions.
531 changes: 267 additions & 264 deletions MicroPie.py

Large diffs are not rendered by default.

336 changes: 99 additions & 237 deletions README.md

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="shortcut icon" href="https://cherrypy.dev/images/favicon.gif" type="image/x-icon">
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600&display=swap" rel="stylesheet">
<title>MicroPie - An ultra-micro Python web framework</title>
<title>MicroPie - An ultra-micro Python ASGI web framework</title>
<style>
body {
font-family: 'Poppins', sans-serif;
Expand Down Expand Up @@ -107,7 +107,7 @@
<div class="logo">
<img src="logo.png" alt="MicroPie logo">
</div>
<p><strong>MicroPie is an ultra-lightweight Python web framework</strong> that gets out of your way, letting you build fast and dynamic web apps with ease.
<p><strong>MicroPie is an ultra-small ASGI Python web framework</strong> that gets out of your way, letting you build fast and dynamic web apps with ease.
Inspired by <a href="https://cherrypy.dev/">CherryPy</a> and licensed under the BSD three-clause license.</p>

<h2>MicroPie is Fun</h2>
Expand All @@ -116,10 +116,10 @@ <h2>MicroPie is Fun</h2>

<span class="c2">class</span> MyApp(<span class="c9">Server</span>):

<span class="c2">def</span> index(<span class="c9">self</span>):
<span class="c2">async def</span> index(<span class="c9">self</span>):
return <span class="c9">'Hello World!'</span>

MyApp().run()
app = MyApp() <small><em># Run with `uvicorn app:app`</em></small>
</code></pre>

<h2> And Easy to Install</h2>
Expand Down
5 changes: 4 additions & 1 deletion examples/file_uploads/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from MicroPie import Server
import os, uuid


class Root(Server):

def upload_file(self, file):
Expand Down Expand Up @@ -55,4 +56,6 @@ def index(self):
"</html>"
)

Root().run()


app = Root()
7 changes: 3 additions & 4 deletions examples/headers/app.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from MicroPie import Server


class Root(Server):
def index(self):
headers = [
Expand All @@ -12,8 +13,6 @@ def index(self):
]
return 200, "hello world", headers

app = Root()
wsgi_app = app.wsgi_app

if __name__ == "__main__":
app.run()

app = Root()
11 changes: 11 additions & 0 deletions examples/hello_world/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from MicroPie import Server


class Root(Server):

def index(self, name=None):
if name:
return f'Hello {name}'
return 'Hello ASGI World!'

app = Root() # Run with `uvicorn app:app`
26 changes: 10 additions & 16 deletions examples/pastebin/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""
A simple no frills pastebin using MicroPie, pickleDB, and highlight.js.
A simple no frills pastebin using MicroPie, pickleDB, and highlight.js.
"""

from uuid import uuid4
Expand All @@ -9,36 +9,30 @@
from pickledb import PickleDB
from markupsafe import escape


db = PickleDB('pastes.db')


class Root(Server):

def index(self):
if self.request == 'POST':
async def index(self):
# Check the HTTP method from the ASGI scope
if self.scope["method"] == "POST":
paste_content = self.body_params.get('paste_content', [''])[0]
pid = str(uuid4())
db.set(pid, escape(paste_content))
db.save()
return self.redirect(f'/paste/{pid}')
return self.render_template('index.html')

def paste(self, paste_id, delete=None):
async def paste(self, paste_id, delete=None):
if delete == 'delete':
db.remove(paste_id)
db.save()
return self.redirect('/')
return self.render_template('paste.html', paste_id=paste_id,
paste_content=db.get(paste_id))
return self.render_template(
'paste.html',
paste_id=paste_id,
paste_content=db.get(paste_id)
)


# Create a instance of our MicroPie App
app = Root()

# Run with `gunicorn app:wsgi_app`
wsgi_app = app.wsgi_app

# Run with `python3 app.py`
if __name__ == '__main__':
app.run()
12 changes: 5 additions & 7 deletions examples/requests/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def options_handler():
]

# Define the custom server application
class MyApp(Server):
class Root(Server):

# Handle root URL requests and delegate based on HTTP method
def index(self):
Expand All @@ -47,8 +47,8 @@ def handle_request(self):
}

# Check if the request method is supported and call the handler
if self.request in method_map:
response = method_map[self.request]()
if self.scope['method'] in method_map:
response = method_map[self.scope['method']]()

# Ensure response is formatted correctly for WSGI
if isinstance(response, tuple):
Expand All @@ -61,8 +61,6 @@ def handle_request(self):
# Return 405 if the request method is not supported
return 405, b"405 Method Not Allowed", [("Content-Type", "text/html")]

# Run the web server
if __name__ == '__main__':
app = MyApp()
app.run()


app = Root()
60 changes: 60 additions & 0 deletions examples/socketio/chatroom.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import socketio
from MicroPie import Server

# Create a Socket.IO server with CORS support
sio = socketio.AsyncServer(async_mode="asgi", cors_allowed_origins="*") # Allow all origins

# Create the MicroPie server
class MyApp(Server):
def index(self):
return """
<html>
<head>
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<script>
var socket = io("http://localhost:8000");
socket.on("connect", function() {
console.log("Connected to Socket.IO server");
});
socket.on("message", function(data) {
document.getElementById("output").innerHTML += data + "<br>";
});
function sendMessage() {
var message = document.getElementById("message").value;
socket.send(message);
document.getElementById("message").value = ""; // Clear input after sending
}
window.onbeforeunload = function() {
socket.disconnect();
};
</script>
</head>
<body>
<h1>Socket.IO Chat</h1>
<input type="text" id="message" placeholder="Type a message">
<button onclick="sendMessage()">Send</button>
<div id="output"></div>
</body>
</html>
"""

# Socket.IO event handlers
@sio.event
async def connect(sid, environ):
print(f"Client connected: {sid}")

@sio.event
async def disconnect(sid):
print(f"Client disconnected: {sid}")

@sio.event
async def message(sid, data):
print(f"Received message from {sid}: {data}")
# Broadcast the message to all connected clients
await sio.emit("message", f"User: {data}", room=None)



# Attach Socket.IO to the ASGI app
app = MyApp()
asgi_app = socketio.ASGIApp(sio, app)
17 changes: 17 additions & 0 deletions examples/socketio/templates/index_stream.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webcam Streaming</title>
</head>
<body>
<h1>Webcam Streaming App</h1>
<form method="post" action="/submit">
<input type="text" name="username" placeholder="Enter username" required>
<button type="submit" name="action" value="Start Streaming">Start Streaming</button>
<button type="submit" name="action" value="Watch Stream">Watch Stream</button>
</form>
</body>
</html>

57 changes: 57 additions & 0 deletions examples/socketio/templates/stream.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<title>Streaming: {{ username }}</title>
</head>
<body>
<h1>Streaming as {{ username }}</h1>
<video id="webcam" autoplay playsinline></video>

<script>
const username = "{{ username }}";
const socket = io();

// Join the room as a streamer
socket.emit("join_room", { username });

socket.on("connect", () => {
console.log("Connected as streamer for", username);
startWebcam();
});

socket.on("disconnect", () => {
console.log("Disconnected");
});

async function startWebcam() {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
const videoElement = document.getElementById("webcam");
videoElement.srcObject = stream;

const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const track = stream.getVideoTracks()[0];
const settings = track.getSettings();
canvas.width = settings.width || 640;
canvas.height = settings.height || 480;

setInterval(() => {
context.drawImage(videoElement, 0, 0, canvas.width, canvas.height);
const frameDataUrl = canvas.toDataURL("image/webp");

// Send frame to server
socket.emit("stream_frame", { username, frame: frameDataUrl });
}, 100);
} catch (err) {
console.error("Error accessing webcam:", err);
}
}
</script>

</body>
</html>

37 changes: 37 additions & 0 deletions examples/socketio/templates/watch.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
<title>Watching: {{ username }}</title>
</head>
<body>
<h1>Watching Stream of {{ username }}</h1>
<img id="videoFeed" style="width: 100%; max-width: 800px;" />


<script>
const username = "{{ username }}";
const socket = io();

// Join the room as a watcher
socket.emit("join_room", { username });

socket.on("connect", () => {
console.log("Connected as watcher for", username);
});

socket.on("video_frame", (data) => {
if (data.username === username) {
document.getElementById("videoFeed").src = data.frame;
}
});

socket.on("disconnect", () => {
console.log("Disconnected");
});
</script>

</body>
</html>
Loading

0 comments on commit 2519a30

Please sign in to comment.