Flask-GWS
A high-performance WebSocket extension for Flask applications powered by uWSGI and gevent. Compatible with Python 3.7 and newer versions. Production-ready with focus on reliability and performance.
Example Usage
from flask import Flask
from flask_gws import WebSocket
app = Flask(__name__)
ws = WebSocket(app)
@ws.route('/echo')
def echo(ws):
while True:
msg = ws.receive()
if msg is None:
break
ws.send(msg)
if __name__ == '__main__':
app.run(debug=True, gevent=100)
Installation
Flask-GWS requires both gevent and uWSGI with WebSocket support. While gevent is automatically installed as a dependency, uWSGI requires special handling:
⚠️ IMPORTANT NOTE: Installing uWSGI with WebSocket support requires special flags for OpenSSL. The traditional method via requirements.txt (pip install uwsgi) will not work as it lacks SSL support needed for WebSockets. You must use the commands below with the specific compilation flags.
For Ubuntu/Debian:
CFLAGS="-I/usr/include/openssl" LDFLAGS="-L/usr/lib/x86_64-linux-gnu" UWSGI_PROFILE_OVERRIDE=ssl=true pip install --no-cache-dir uwsgi --no-binary :all:
For macOS (Apple Silicon):
CFLAGS="-I/opt/homebrew/opt/openssl@3/include" \
LDFLAGS="-L/opt/homebrew/opt/openssl@3/lib" \
UWSGI_PROFILE_OVERRIDE=ssl=true pip install --no-cache-dir uwsgi --no-binary :all:
After installing uWSGI with the proper SSL support, you can install Flask-GWS:
pip install flask-gws
Advanced Usage: Client Tracking and Broadcasting
Flask-GWS can be used to track connected clients and implement broadcasting functionality:
from flask import Flask
from flask_gws import WebSocket
import time
app = Flask(__name__)
ws = WebSocket(app)
# Store connected clients
clients = {}
@ws.route('/echo')
def echo(ws):
# Store client using unique ID
client_id = ws.id
clients[client_id] = {
'ws': ws,
'connected_at': time.time()
}
print(f"New client connected: {client_id}, Total clients: {len(clients)}")
try:
while ws.connected:
msg = ws.receive()
if msg:
ws.send(msg)
time.sleep(0.1)
except Exception as e:
print(f"Error in websocket: {e}")
finally:
# Clean up when client disconnects
if client_id in clients:
print(f"Client disconnected: {client_id}")
clients.pop(client_id, None)
print(f"Total remaining clients: {len(clients)}")
# Broadcasting utility function
def broadcast(msg):
disconnected = []
for client_id, client_info in clients.items():
try:
client_info['ws'].send(msg)
except Exception as e:
print(f"Error broadcasting to client {client_id}: {e}")
disconnected.append(client_id)
# Clean up any disconnected clients
for client_id in disconnected:
clients.pop(client_id, None)
# Example route that triggers a broadcast
@app.route('/notify')
def notify():
broadcast("New notification for all clients")
return "Notification sent to all connected clients"
Client-Side Implementation
Here's a simple but robust client implementation using ReconnectingWebSocket:
<!-- Include the ReconnectingWebSocket library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js"></script>
<div>
<div id="status">Connecting...</div>
<div id="messages"></div>
</div>
<script>
// WebSocket client with automatic reconnection
const messagesEl = document.getElementById('messages');
const statusEl = document.getElementById('status');
function addMessage(text) {
const messageEl = document.createElement('div');
messageEl.textContent = text;
messagesEl.appendChild(messageEl);
messagesEl.scrollTop = messagesEl.scrollHeight;
}
function connect() {
// Convert HTTP URL to WebSocket URL
const url_root = window.location.origin;
const server = url_root.replace('http', 'ws') + '/echo';
// Create a reconnecting WebSocket
window.socket = new ReconnectingWebSocket(server, [], {
connectionTimeout: 2000,
maxRetries: 15
});
socket.onopen = function() {
statusEl.textContent = 'Connected';
statusEl.style.color = 'green';
addMessage('Connection established');
};
socket.onmessage = function(message) {
addMessage('Received: ' + message.data);
// Special command handling
if (message.data === 'reload') {
window.location.reload();
}
};
socket.onclose = function() {
statusEl.textContent = 'Disconnected (reconnecting...)';
statusEl.style.color = 'orange';
};
socket.onerror = function() {
statusEl.textContent = 'Connection error';
statusEl.style.color = 'red';
};
}
// Initialize the connection
connect();
// Example function to send a message
function sendMessage(text) {
if (socket && socket.readyState === WebSocket.OPEN) {
socket.send(text);
addMessage('Sent: ' + text);
} else {
addMessage('Cannot send: connection not open');
}
}
</script>
Deployment
You can use uWSGI's built-in HTTP router to get up and running quickly:
$ uwsgi --master --http :8080 --http-websockets --gevent 100 --wsgi-file app.py
...or call app.run, passing uwsgi any arguments you like:
app.run(debug=True, host='localhost', port=8080, master=True, gevent=100)
Development
To use Flask's interactive debugger, install werkzeug's DebuggedApplication middleware:
from werkzeug.debug import DebuggedApplication
app.wsgi_app = DebuggedApplication(app.wsgi_app, True)
Then run uWSGI with a single worker:
$ uwsgi --master --http :8080 --http-websockets --gevent 100 --workers 1 app.py
If you use app.run(debug=True), Flask-GWS will do this automatically.
WebSocket API
Flask-GWS handles the WebSocket handshake and provides a websocket client with the following methods:
websocket.recv()- Receive a message (blocking)websocket.receive()- Alias for recv()websocket.send(msg)- Send a messagewebsocket.send_binary(msg)- Send a binary messagewebsocket.recv_nb()- Non-blocking receivewebsocket.id- Unique identifier for the connectionwebsocket.connected- Boolean indicating if the connection is still active
Credits
This project is based on code from the Flask-uWSGI-WebSocket repository, with enhancements for improved performance and additional features. Flask-GWS provides a simplified and modernized implementation focused on gevent support and contemporary Python versions.
Metadata
Release files for flask-gws 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| flask_gws-0.1.0.tar.gz | 9.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| flask_gws-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 18.5 kB
Release files / flask_gws-0.1.0.tar.gz
| Download URL | flask_gws-0.1.0.tar.gz |
|---|---|
| Size | 9.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
85b9f9b46f0d9fa57a070060d50fa9bd290f02c0b12d40f3eb02ae11c128739a
|
|
BLAKE2b-256 checksum How to use checksums |
4fda072831e7cf0976d2f8bc6c9b1f28f1e4a783b8b9c5d2d6f037be74b2b9f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-requests/2.32.0
|
Release files / flask_gws-0.1.0-py3-none-any.whl
| Download URL | flask_gws-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6c605dfaba8b964d4f9447dbdc77a425273832069f6f9ebee22b014a6979d8f8
|
|
BLAKE2b-256 checksum How to use checksums |
1175d99baa34d73054c831ebb5888477f0a7a7fed18d318aa84a3ed7ca898254
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
python-requests/2.32.0
|