Development Guide
This guide is for developers who want to contribute to PadRelay or understand its internals.
Development Setup
Prerequisites
Python 3.6+
Git
Virtual environment tool (venv or virtualenv)
ViGEmBus driver (for server development on Windows)
Clone Repository
git clone https://github.com/ssh-den/PadRelay.git
cd PadRelay
Create Virtual Environment
python -m venv venv
# Linux/macOS
source venv/bin/activate
# Windows
venv\Scripts\activate
Install Dependencies
# Install in editable mode with all dependencies
pip install -e .
# Install development dependencies
pip install -r requirements.txt
pip install pytest pytest-asyncio
Project Structure
Directory Layout
PadRelay/
├── src/padrelay/ # Main source code
│ ├── client/ # Client components
│ │ ├── client_app.py # Client application
│ │ ├── input.py # Gamepad input capture
│ │ └── constants.py # Client constants
│ ├── server/ # Server components
│ │ ├── server_app.py # Server application
│ │ ├── virtual_gamepad.py # Virtual gamepad interface
│ │ ├── input_processor.py # Input processing
│ │ └── constants.py # Server constants
│ ├── protocol/ # Protocol implementation
│ │ ├── tcp.py # TCP protocol
│ │ ├── udp.py # UDP protocol
│ │ ├── messages.py # Message types
│ │ └── constants.py # Protocol constants
│ ├── security/ # Security components
│ │ ├── auth.py # Authentication
│ │ ├── rate_limiting.py # Rate limiting
│ │ ├── tls_utils.py # TLS utilities
│ │ └── password_strength.py # Password validation
│ ├── core/ # Core utilities
│ │ ├── config.py # Configuration handling
│ │ ├── exceptions.py # Custom exceptions
│ │ └── logging_utils.py # Logging setup
│ └── scripts/ # Entry points
│ ├── server.py # Server entry point
│ ├── client.py # Client entry point
│ └── key_mapper.py # Key mapper utility
├── tests/ # Test suite
├── config/ # Example configurations
├── docs/ # Documentation
├── pyproject.toml # Project metadata
└── README.md # Project README
Code Organization
Client: Gamepad input capture and network transmission
Server: Network reception and virtual gamepad output
Protocol: Message serialization and transport
Security: Authentication, encryption, rate limiting
Core: Configuration, logging, exceptions
Scripts: CLI entry points
Running Tests
Run All Tests
pytest
Run Specific Test File
pytest tests/test_auth.py
Run with Coverage
pytest --cov=padrelay --cov-report=html
View coverage report at htmlcov/index.html.
Run Specific Test
pytest tests/test_auth.py::test_hash_password
Test Organization
Tests are organized by component:
test_auth.py- Authentication teststest_tcp_protocol.py- TCP protocol teststest_udp_protocol.py- UDP protocol teststest_rate_limiting.py- Rate limiting teststest_tls_utils.py- TLS utility teststest_messages.py- Message serialization teststest_integration.py- End-to-end integration tests
Coding Standards
Style Guide
PadRelay follows PEP 8 with some exceptions:
Line length: 100 characters (not 79)
Use double quotes for strings
Use f-strings for formatting
Type Hints
Use type hints for function signatures:
def authenticate(self, password: str, challenge: bytes) -> bool:
"""Verify authentication challenge response."""
# Implementation
Docstrings
Use Google-style docstrings:
def compute_response(self, challenge: str) -> str:
"""Compute HMAC response for authentication challenge.
Args:
challenge: Hex-encoded random bytes from server
Returns:
Hex-encoded HMAC-SHA256 response
Raises:
ValueError: If challenge is invalid
"""
# Implementation
Code Formatting
Consider using black for automatic formatting:
pip install black
black src/
Linting
Use flake8 for linting:
pip install flake8
flake8 src/
Common Development Tasks
Adding a New Message Type
Define message class in
protocol/messages.py:
class NewMessage(BaseMessage):
def __init__(self, field1, field2):
super().__init__("new_message")
self.data["field1"] = field1
self.data["field2"] = field2
@classmethod
def from_dict(cls, data):
msg = cls(data.get("field1"), data.get("field2"))
return msg
Add to
BaseMessage.from_dict()dispatch:
elif msg_type == "new_message":
return NewMessage.from_dict(data)
Add tests in
tests/test_messages.pyUpdate protocol documentation
Adding a New Configuration Option
Add to appropriate section in config parsing (
core/config.py):
if config_obj.has_section('server'):
if 'new_option' in config_obj['server']:
args.new_option = config_obj['server']['new_option']
Add command-line argument:
parser.add_argument('--new-option', type=str, help='Description')
Add default value if not specified
Update configuration documentation
Add tests for new option
Adding Authentication Method
Create new method in
security/auth.pyUpdate protocol to support new auth type
Add configuration options
Write comprehensive tests
Update security documentation
Debugging
Using Debug Mode
export PADRELAY_DEBUG=1
python -m padrelay.scripts.server --config server_config.ini
Using Python Debugger
import pdb; pdb.set_trace()
Or use VS Code debugger with launch configuration:
{
"version": "0.2.0",
"configurations": [
{
"name": "PadRelay Server",
"type": "python",
"request": "launch",
"module": "padrelay.scripts.server",
"args": ["--config", "config/server_config.ini"],
"console": "integratedTerminal"
}
]
}
Logging
Add debug logging:
from padrelay.core.logging_utils import get_logger
logger = get_logger(__name__)
logger.debug("Debug message")
logger.info("Info message")
logger.warning("Warning message")
logger.error("Error message")
Performance Profiling
Using cProfile
python -m cProfile -o profile.stats -m padrelay.scripts.server --config server_config.ini
Analyze results:
import pstats
p = pstats.Stats('profile.stats')
p.sort_stats('cumulative')
p.print_stats(20)
Memory Profiling
pip install memory_profiler
python -m memory_profiler padrelay/scripts/server.py
Building Documentation
Install Sphinx
pip install sphinx sphinx_rtd_theme
Build HTML Documentation
cd docs
make html
View at docs/_build/html/index.html.
Build PDF Documentation
cd docs
make latexpdf
Requires LaTeX installation.
Release Process
Version Numbering
PadRelay follows Semantic Versioning:
MAJOR.MINOR.PATCH (e.g., 1.1.0)
MAJOR: Breaking changes
MINOR: New features, backward compatible
PATCH: Bug fixes, backward compatible
Creating a Release
Update version in
pyproject.tomlUpdate CHANGELOG.md with release notes
Run all tests:
pytest
Commit changes:
git add pyproject.toml CHANGELOG.md git commit -m "Bump version to 1.x.x"
Create git tag:
git tag -a v1.x.x -m "Release version 1.x.x"
Push to GitHub:
git push origin main git push origin v1.x.x
GitHub Actions automatically builds and publishes to PyPI
Manual PyPI Upload
If needed, manually upload to PyPI:
pip install build twine
python -m build
twine upload dist/*
Contributing
See Contributing Guide for contribution guidelines.
Architecture Documentation
See Architecture for system architecture details.
Security Considerations
When developing security-related features:
Never log passwords or tokens
Use constant-time comparisons for secrets
Follow OWASP guidelines
Get security review for major changes
Write security-focused tests
Useful Resources
See Also
Contributing Guide - Contribution guidelines
Architecture - Architecture documentation
API Reference - API reference