Python client for Faye pub/sub protocol
Project description
PyFaye
An asynchronous Python client for the Faye publish-subscribe messaging protocol.
Features
- Asynchronous implementation using
asyncio
andaiohttp
/websockets
- Support for both WebSocket and HTTP Long-Polling transports
- Automatic transport selection and fallback
- Extensible architecture with support for custom extensions
- Channel subscription management
- Message validation and channel validation
- Automatic reconnection with exponential backoff
- Comprehensive error handling and type hints
Installation
Install using pip:
pip install pyfaye
Or with Poetry:
poetry add pyfaye
Quick Start
import asyncio
from faye import FayeClient
async def main():
# Create a client (defaults to WebSocket transport)
client = FayeClient("http://your-faye-server/faye")
# Connect to server
await client.connect()
# Subscribe to a channel
async def message_handler(message):
print(f"Received message: {message.data}")
await client.subscribe("/some/channel", message_handler)
# Publish a message
await client.publish("/some/channel", {"message": "Hello, World!"})
# Disconnect when done
await client.disconnect()
if __name__ == "__main__":
asyncio.run(main())
Advanced Usage
Custom Extensions
from faye import Extension, Message
class SigningExtension(Extension):
def __init__(self, token: str):
self.token = token
async def process_outgoing(self, message: Message) -> Message | None:
"""Sign outgoing messages."""
if not message.ext:
message.ext = {}
message.ext["token"] = self.token
return message
# Create client with extension
client = FayeClient("http://your-faye-server/faye")
client.add_extension(SigningExtension("your-auth-token"))
await client.connect()
Message Batching
from faye import Message
# Create multiple messages
messages = [
Message("/channel/1", data={"seq": 1}),
Message("/channel/2", data={"seq": 2})
]
# Send messages in batch
responses = await client.batch(messages)
Transport Selection
# Use HTTP Long-Polling transport
client = FayeClient("http://your-faye-server/faye", transport_type="long-polling")
# Use WebSocket transport (default)
client = FayeClient("http://your-faye-server/faye", transport_type="websocket")
API Reference
FayeClient
The main client class for interacting with a Faye server.
Constructor
FayeClient(
url: str,
transport_type: str = "websocket",
extensions: list[Extension] | None = None
)
url
: Faye server URLtransport_type
: Transport type to use ("websocket" or "long-polling")extensions
: Optional list of extensions to use
Properties
client_id
: The client ID assigned by the server (read-only)connected
: Whether the client is currently connected (read-only)state
: Current connection state as string (read-only)
Methods
async connect() -> None
: Connect to the Faye serverasync disconnect() -> None
: Disconnect from the serverasync subscribe(channel: str, callback: Callable[[Message], Awaitable[None]]) -> None
: Subscribe to a channelasync unsubscribe(channel: str) -> None
: Unsubscribe from a channelasync publish(channel: str, data: dict[str, Any] | str) -> None
: Publish data to a channelasync batch(messages: list[Message]) -> list[Message | None]
: Send multiple messages in batchadd_extension(extension: Extension) -> None
: Add an extension to the clientremove_extension(extension: Extension) -> None
: Remove an extension from the client
Message
The message class representing Faye protocol messages.
Message(
channel: str,
client_id: str | None = None,
data: dict[str, Any] | str | None = None,
error: str | None = None,
ext: dict[str, Any] | None = None,
message_id: str | None = None,
version: str | None = None,
minimum_version: str | None = None,
supported_connection_types: list[str] | None = None,
connection_type: str | None = None,
subscription: str | None = None,
successful: bool | None = None,
advice: dict[str, Any] | None = None
)
Factory Methods
handshake(ext: dict[str, Any] | None = None) -> Message
connect(client_id: str, connection_type: str = "websocket") -> Message
disconnect(client_id: str) -> Message
subscribe(client_id: str, subscription: str) -> Message
unsubscribe(client_id: str, subscription: str) -> Message
publish(channel: str, data: dict[str, Any], client_id: str) -> Message
Development
Setup
# Clone the repository
git clone https://github.com/mwhobrey/pyfaye.git
cd pyfaye
# Install dependencies
poetry install
# Run tests
poetry run pytest
Running Tests
# Run all tests
poetry run pytest
# Run with coverage
poetry run pytest --cov=faye
# Run specific test file
poetry run pytest tests/transport/test_websocket.py
Code Quality
# Run all checks
poetry run prerelease
# Format code
poetry run black src/
# Run linter
poetry run ruff check src/
# Run type checker
poetry run pytype src/
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request. When contributing:
- Fork the repository
- Create a feature branch
- Add tests for any new functionality
- Ensure all tests pass and code quality checks succeed
- Submit a pull request
For bug reports or feature requests, please open an issue on GitHub.